Asynchronous Multithreading: Error compiling shader. (libgdx) - java

I'm writing an application with the libgdx api for Android, and I'm running into issues concerning changing states and multithreading.
What I initially want is two asynchronous threads running at the same time, one being the game render thread, and the other being the game logic thread. I then want to be able to change the state of the game, which changes the update/render methods on their respective objects. Obviously, the render thread is running per frame (which is taken care of by libgdx already). This is my code modeling my attempt to do so:
public final class StateManager {
private static State gameState = State.START;
private static StateObject stateObject = new StartScreen();
private static final Object syncObjectUpdate = new Object();
private static final Object syncObjectRender = new Object();
public static void update(float elapsedTime){
if (!stateObject.isCreated){
//pause this thread until render thread stops
synchronized(syncObjectUpdate) {
try {
// Calling wait() will block this thread until another thread
// calls notify() on the object.
syncObjectUpdate.wait();
} catch (InterruptedException ignored) {} // Happens if someone interrupts your thread.
}
//once the render thread stops-
stateObject.dispose();
switch (gameState){
//note: creating a new object here sets isCreated to true,
//so the if statements gets called only once per state change.
case START:
stateObject = new StartScreen();
break;
case GAME:
stateObject = new GameScreen();
break;
case LOADING:
//stateObject = new LoadingScreen();
break;
default:
System.out.print("ERROR IN STATE!");
break;
}//end switch
//-change the state and resume render thread
//what if this happens before wait? surround in while loop?
synchronized(syncObjectRender) {
syncObjectRender.notify();
}
}//end if
stateObject.update(elapsedTime);
}
public static void render(){
stateObject.render();
//if update thread is waiting
if (MyGdxGame.logicThread.getState() == Thread.State.WAITING){
//then resume that one,
synchronized(syncObjectUpdate) {
syncObjectUpdate.notify();
}
// and pause this one
synchronized(syncObjectRender) {
try {
syncObjectRender.wait();
} catch (InterruptedException ignored) {}
}
}//end if
}//end render
public static void changeState(State state){
stateObject.isCreated = false;
gameState = state;
}
public static void dispose(){
stateObject.dispose();
}
public static void resize(int width, int height){
stateObject.resize(width, height);
}
public static void pause(){
stateObject.pause();
}
public static void resume(){
stateObject.resume();
}
}//class
This runs well, until I call changeState(), and it throws the error:
E/AndroidRuntime(19094): java.lang.IllegalArgumentException: Error compiling shader
I THINK this happened because stateObject.render() got called (which changes the spritebatch and such) while there was no StateObject present.
[BTW, if it isn't clear already, a StateObject is something like a start screen, or game screen, which has a render() and update() method inside that are called by two different threads. Also, I wrote this program before without multithreading, and the state changing mechanism worked perfectly.]
Here's my thought process:
1. When I change the state, the update thread gets the notification. This pauses the update thread. (Render is still running)
2. When the render thread sees that the update thread is paused, it resumes the update thread and pauses the render thread. This is so the stateObject.render() method doesn't get called before it tries to call render() on something that is disposed.
3. At this point, the update thread is notified to start up again, so it disposes of the StateObject and creates a new one.
4. Now that a new state object is initialized, stateObject.render() should have no problem. It then resumes the render thread. Both threads should be running, and peace in the universe is restored.
Now there's obviously something wrong with my implementation or that logic, because I'm getting that error. So... why?
Any help is greatly appreciated. If something isn't clear, let me know in the comments. Thanks!

Through hours of experimenting, I was able to solve this by putting the switch-case in the render method, and deleting the line stateObject.dispose();. That's it, no waiting on threads and locking objects. This now calls the appropriate render method for the state without issues of changing the spritebatch (because its in the same OpenGL thread). Deleting the dispose method means that whenever I attempt to change the state, the update method always has something to update.
This is rather a work around because changing the sate is now handed in the render method, but the performance impact is very minimal.
Here are the working render and update methods with the changes (same class):
public static void update(float elapsedTime){
stateObject.update(elapsedTime);
}
public static void render(){
stateObject.render();
if (!stateObject.isCreated){
switch (gameState){
case START:
stateObject = new StartScreen();
break;
case GAME:
stateObject = new GameScreen();
break;
case LOADING:
//stateObject = new LoadingScreen();
break;
default:
System.out.print("ERROR IN STATE!");
break;
}//end switch
}//end if
}//end render
I hope this helps someone!

Related

Force method to finish before continuing

I'm working on some sensitive LWJGL code and need to make sure that I create my display, and therefore GL context before executing any other code.
To give a clear example of my current predicament, take the following:
public static void main(String[] args) {
GLDisplay display = new GLDisplay();
display.start();
GLShader shader = new StaticShader();
}
The beginning of my GL creation happens in display.start(), where a separate thread is created, and within the separate thread, my Display is created.
Except this is where the problem lies, I have it in a separate thread. So then my program goes on and starts prematurely executing the new StaticShader() which calls even more GL code, breaking the program. (Can't execute before display is created).
What I'm trying to do, is achieve two threads simultaneously which I already have, but make sure that start() method is called completely before anything else is.
Here is how the start method works:
public synchronized void start() {
Threader.createThread(this, "GLDisplay");
}
#Override // public class GLDisplay extends Runnable
public void run() {
// GL code goes here.
}
And here is Threader:
public static void createThread(Runnable behaviour, String name) {
new Thread(behaviour, name + behaviour.hashCode()).start();
}
Now you may notice the synchronized keyword in the start method, well thats just one attempt I've had to no avail. I've also tried the following (which I actually grabbed from another StackOverflow answer):
#Override
public void run() {
synchronized(this) {
// GL code
}
}
I've checked other StackOverflow answers but either don't understand them or don't help me in my case. With the first code block I give in the main method, that is how I want my code to look to the person using it. I'm trying to put the thread-creation inside GlDisplay to hide it.
Any ideas?
Edit:
I can't simply wait for GLDisplay to close either (with Thread.join()) because there lies a while-loop that updates the display for the entirety of the program.
This is the entire reason I multi-threaded it. To allow this forever-ending loop to run while I do other things in the program. By closing the thread, I close the loop, cleanup the display and free the GL context from memory, once again making the shader code fail for lack of an existing context.
You can use java.util.concurrent.CountDownLatch to achieve it which aids in making a thread(s) wait till the operations on other threads is complete. Please see the reference on on what and how to use it.
Example:
public static void main(String[] args) {
CountDownLatch cdl = new CountDownLatch(1);
// pass the CountDownLatch into display
GLDisplay display = new GLDisplay(cdl);
display.start();
// wait for the latch to have been counted down in the disp thread
try
{
cdl.await();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
GLShader shader = new StaticShader();
}
In your GLDisplay thread, call the countDown method of CountDownLatch
I might be misunderstanding something, but try the following:
public static void createThread(Runnable behaviour, String name) {
Thread t = new Thread(behaviour, name + behaviour.hashCode()).start();
t.join();
}
By calling join() the program should wait for the thread to complete.
Well I remember now that I can't have GL code against two separate threads anyway, but thats besides the point.
I don't actually need to use any thread-lock classes or anything, but rather can just do something as simple as this:
private Boolean threadLock = true;
public void start() {
Threader.createThread(this, "GLDisplay");
while (true) {
synchronized(threadLock) {
if (!threadLock) break;
}
}
}
#Runnable
public void run() {
// Do GL code.
synchronized(threadLock) { threadLock = false; }
// Do the rest of whatever I'm doing.
}
When the threadlock is reached in the second thread and is released, the first thread continues doing it's activity. It's that simple!

Problems with threads, making a game in Java

I'm doing a Snake game in Java. I have the basic functionability, but I want pause the game when I click on a button. But the problem I have is when I clic on this button, the game is paused, but when I click again the game doesn't recognize the controls. I have a method called Init, on this I initialize the thread "Hilo". I tried to make a second thread in which I put an actionPerformed for the button, but the problem continued, now I am more confused. Here is my code:
Thread hilo; //I declared the thread
String state=""; //It is for control de state (paused or no)
Runnable hiloFor = new Runnable()
{
public void run()
{
Thread actual = Thread.currentThread();
synchronized(actual)
{
do
{
//Game instructions (there are a lot of them)
if(state.equals("paused"))
{
actual.wait();
}
}while(!option.equals("Exit"));
}
}
};
//This is my action performed where I control if it is paused
public void actionPerformed(ActionEvent e)
{
if ( e.getSource() == btnPause )
{
if(state.equals("paused"))
{
cont(); //method for reactive the thread
state="";
}else if(state.equals(""))
{
state="paused";
}
}
}
If somebody can help me, I will be very glad, It has turned difficult to me.
To reactivate the Thread in wait() you must call notify() (or better notifyAll()) on the same object.
Your code looks like you expect to pause the Thread you call wait() on. This is not the case. wait() will always pause the thread making the call, not the object that is the target. You can use any object for the wait() / notifyAll() signaling, it just has to be the same object for both sides of the communication.
This pages has some good explanations: http://javamex.com/tutorials/synchronization_wait_notify.shtml
if(state.equals("paused"))
{
actual.wait();
}
This part actually pauses the thread, until it's told to start it's work again. I suppose what you wanted in this case is something like continue; in loop, which, although, is not a very elegant way to do this. More suitable way to do this would be using notify().

libgdx - doing something in other thread not working

My game has a stats queue, after each game the current game stats goes into the queue.
Whenever the mainmenu starts i want to upload all the game stats to a server, and this take like 1-3 seconds and I want to do this in an other thread.
My code
#Override
public void show() {
Global.key = Global.getKey();
// System.out.println(Stats.getJSONObject(Global.key));
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
Stats.TryUploadGame1();
System.out.println("DONE");
}
});
.....
}
But this also freezes my game.
What should I do?
Your current code is posting a Runnable instance that will be executed by the render thread before the next frame. The Gdx.app.postRunnable API is generally used so background threads can ask for something to happen on the render thread. You want to post a Runnable to execute anywhere but the render thread.
As long as your Stats code doesn't interact with OpenGL context at all (since Android OpenGL APIs assume only a single thread interacts with them), you can just post your Runnable on a new background thread:
new Thread(new Runnable() { ... }).start();
This should unblock your render. (Of course, if your background thread uses a lot of CPU, it can still interfere with the render thread, but if its mostly doing blocking IO or host has spare cores, it shouldn't interfere.)
This could be improved in lots of ways (using a ThreadPool, or using Android-aware background task support), but if your stats update is relatively quick and the thread creation isn't frequent this should work fine.
Okay to do something in a other thread you need to take care of the OpenGL context. Inside of a different thread you cant do anything that does render stuff. You are forced to push such thing into the renderthread in any way. And you need to synchronize everything that can be called from the regular render thread from libgdx. For example you want to call the .act(float delta) from a stage from a different thread you are forced to put the stage indo an synchronized block.
The post runable isn't a thread. It is an runable that get executed at the beginning of the next rendercall. So it will stop the game till it's done but it is inside of the OpenGl context thread. (That's why your game stops)
So here is an example of how to use threading in libgdx. I use this inside of my game. It runs on 210 frames so 210 updatecalls per second. You can change it to as fast as possible or just to 60fps whatever you need:
public class GameLogicThread extends Thread {
private GameScreen m_screen;
private boolean m_runing;
private long m_timeBegin;
private long m_timeDiff;
private long m_sleepTime;
private final static float FRAMERATE = 210f;
public GameLogicThread(GameScreen screen) { //pass the game screen to it.
m_screen = screen;
setName("GameLogic");
}
#Override
public void run() {
m_runing = true;
Logger.log("Started");
while (m_runing) {
m_timeBegin = TimeUtils.millis();
// act of the camera
synchronized (m_screen.figureStage) { //stage with figures
// now figures
if (m_screen.m_status == GameStatus.GAME) {
m_screen.figureStage.act(1f / GameLogicThread.FRAMERATE);
}
}
m_timeDiff = TimeUtils.millis() - m_timeBegin;
m_sleepTime = (long) (1f / GameLogicThread.FRAMERATE * 1000f - m_timeDiff);
if (m_sleepTime > 0) {
try {
Thread.sleep(m_sleepTime);
}
catch (InterruptedException e) {
Logger.error("Couldn't sleep " + e.getStackTrace());
}
} else {
Logger.error("we are to slow! " + m_sleepTime); //meight create it dynamic so if you are to slow decrease the framerate till you are not to slow anymore
}
}
}
/**
* Stops the thread save<br>
*/
public void stopThread() {
m_runing = false;
boolean retry = true;
while (retry) {
try {
this.join();
retry = false;
}
catch (Exception e) {
Logger.error(e.getMessage());
}
}
}
}
This does update all my figures. To not cause any troubles with the rendering thread the figurestage is synchronized. (Kind of critical section)
Dont forget that you need to create a new thread every time you stopped it. so for example inside of the show you need todo this:
#Override
public void show() {
super.show();
m_logic = new GameLogicThread(this); //create a new one inside of the GameScreen
m_logic.start(); //start the thread
}
Also dont forget to savestop it inside of the pause stop and so on.
#Override
public void dispose() {
m_logic.stopThread();
}
According to the wiki
To pass data to the rendering thread from another thread we recommend using Application.postRunnable(). This will run the code in the Runnable in the rendering thread in the next frame, before ApplicationListener.render() is called.
So calling that method is just creating a new thread on to run on the render thread.
You may want to use standard java practice on creating threads unless this is frowned upon in libgdx because of android, that I am not sure of.

Synchronized with GLThread in Android

I'm making a game in android using opengl-es, using multiple threads:
class World{
protected static final AtomicInteger entityLock = new AtomicInteger();
private GameEntity entities[];
public World(){
// populate game world with entities
// executed on main thread
addEntity(new GameEntity("tank"));
addEntity(new GameEntity("rifleman"));
addEntity(new GameEntity("rifleman"));
}
void update(){
synchronized(entityLock){
for(int i = 0;i<entities.length;i++){
// move entity to new position
// executed on PhysThread
entities[i].updatePosition();
}
}
if(entity.isDead(){
// remove entity. Enter sync block inside removeEntity() method
removeEntity(entity);
}
}
void draw(GL10 gl){
synchronized(entityLock){
for(int i = 0;i<entites.length;i++){
// draw models
// executed on GLThread
Vector3 entityPosition = entities[i].getPosition();
gl.glTranslatef(entityPosition.x, entityPosition.y, entityPosition.z);
entities[i].draw();
}
}
}
public void addEntity(GameEntity entity){
synchronized(entityLock){
// arrays stuff
}
}
public void removeEntity(GameEntity entity){
synchronized(entityLock){
// arrays stuff
}
}
}
class MyRenderer implements GLSurfaceView.Renderer{
World world;
public MyRenderer(World world){
this.world = world;
}
public void onDrawFrame(GL10 gl) {
// executed on GLThread
world.draw(gl);
}
}
class PhysThreadRunnable implements Runnable{
private long tickRate = 30;
private World world;
private PhysThreadRunnable(World world){
this.world = world;
}
protected void setTickRate(long tickRate){
this.tickRate = tickRate;
}
public void run() {
while(true){
try {
// executed on PhysThread
world.update();
Thread.sleep(1000/tickRate);
} catch (InterruptedException e) {
return;
}
}
}
}
MyActivity extends Activity{
#Override
public void onCreate(Bundle savedInstanceState) {
World world = new World();
// sets up the game world, populates it with entities
// set up GLSurfaceView (simplified)
setContentView(R.layout.main);
GLSurfaceView mGLView = findViewById(R.id.myGLSurfaceView);
mGLView.setRenderer(new MyRenderer(world));
// start phys thread
PhysThreadRunnable physThreadRunnable = new PhysThreadRunnable(world);
Thread physThread = new Thread(physThreadRunnable);
physThread.start();
}
}
I have a problem where sometimes (but not every time) when I start the game, the PhysThread gets stuck waiting for the lock to be released (i.e. when I go to debug and pause the thread, it is just sat on synchronized(entityLock) inside update()
What's really strange is that after a while (between 2 seconds and a minute), the PhysThread will be unblocked, and the game will continue without either thread getting locked out for more than a few iterations of the thread loops. (i.e. the game runs fine)
Edit: I added some extra stuff to the example, just in case that is the cause of the problem. Basically, updating and drawing an array of entities rather than a single entity
I think the issue here is probably that there is no fairness guaranteed by the 'synchronized' block.
The OpenGL thread will always be rendering continuously, so it will attempt to reenter onDraw as soon as it finishes it. Since the choice of which thread is allowed to enter the synchronized block is arbitrary, it could be possible that the OpenGL thread attempts to reacquire the lock before it is released to the physics thread, and based on some arbitrary criteria it is given the lock over and over without allowing the physics thread to enter.
This might explain why it happens sometime and not others, since it is an arbitrary decision.
You might try implementing a fair lock instead of a synchronization block, or making it such that the OpenGL does not attempt to redraw the scene more than once since the last physics update (put the render thread to sleep until an update has occured).
In the end, I went for the cheat solution. I put the synchronization blocks around access to the entities array and put the for loops inside a try/catch with ArrayIndexOutOfBounds:
void update(){
try{
for(int i = 0;i<entities.length;i++){
GameEntity entity = entities[i];
synchrnonized(entity){
entity.updatePosition();
}
}
}catch(ArrayIndexOutOfBoundsException aioob){
if(tryAgain){
update();
} else {
return;
}
}
}
The problem with this solution is that if entity.updateposition() throws an ArrayIndexOutOfBoundsException from something completely unrelated, then I'll catch it and misinterpret it. Plus the whole thing is a bit messy, and once in every while, a frame or update gets skipped
As this appears to solved the problem, I suspect the original cause probably lies somewhere deeper in my code, between entering the for loops and actually modifying the entities, and I don't really think it'd be fair to dump my entire code here.
I'll leave the question unanswered for a couple days in case anyone else has a better solution

How can I schedule a background thread to play sounds in my app?

I have a process which should react on some events. So when playFromList() is called it plays some sound from soundpool. Then in a thread I set a flag and for 3,5 seconds it should not play any sounds.
What I got is: It plays sound and if than wait 3,5 seconds. If playFromList() is called 5 times in 3,5 seconds it still gets to SoundManager.playSound(listNr), and still is done in 17,5 seconds. And its not exactly what I wanted. I wanted method SoundManager.playSound(listNr) called only once.
public class Settings{
public static boolean flag = false;
}
public class Main{
public void playFromList(int listNr,int g){
if(!Settings.flag){
SoundManager.playSound(listNr);
if(g ==0){
mpVolume((float) 0.3);
t5sec.run();
}else{pauseMus();}
}
}
private Handler vijfSeconden = new Handler(){
public void handleMessage(Message msg){
mpVolume((float)0.8);
}
};
Thread t5sec = new Thread(){
public void run(){
if(Settings.flag == false){
Settings.flag = true;
try {
Thread.sleep(3500);
} catch (InterruptedException e) {
Settings.flag = false;
e.printStackTrace();
}
vijfSeconden.sendEmptyMessage(0);
Settings.flag = false;
}
}
};
}
There are few problems with the code. Probably most important thing that is strange is
t5sec.run(), in Java you you should use start method on the Thread object to start new Thread. As written it will execute in the calling thread.
Second problem is absolute lack of synchronization, one way to fix that, I guess, would be to use AtomicBoolean instead of boolean in Settings.flag
Another issue is that it is quite expensive to start new thread every time. It is a bit hard to tell from the description precisely what you want to do, but if my understanding is correct you should just do something like this:
if ( (System.currentTimeInMillis() - lastTimePlayed) < 3500) {
playSound();
lastTimePlayed = System.currentTimeInMillis();
}
that's it and no threads required. You might want to use AtomicInteger to hold lastTimePlayed value if you want your class to be thread safe.

Categories