Texture Buffer Error

Hi,

I am experiencing an error.

My code is very simple and straight forward…

ByteBuffer bb=image.getData(0);
bb.position(pointer);
bb.put(bytes,pointer,thisW);
bb.position(0);
image.setData(bb);

This code is process by the LWJGL thread and is synchronized.
This code modifies the image of the texture on the fly and for the most part works extremely well.

Every now and again I get the following error but as you have already seen I do not modify the size of the buffer at all. I do not alter any texture buckets. Its just a straight forward buffer read then write back.

Does anyone have any ideas why this error is occuring? Thanks

Here is the stack trace…

SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.IllegalArgumentException: Number of remaining buffer elements is 355568, must be at least 528000. Because at most 528000 elements can be returned, a buffer with at least 528000 elements is required, regardless of actual returned element count
at org.lwjgl.BufferChecks.throwBufferSizeException(BufferChecks.java:162)
at org.lwjgl.BufferChecks.checkBufferSize(BufferChecks.java:189)
at org.lwjgl.BufferChecks.checkBuffer(BufferChecks.java:230)
at org.lwjgl.opengl.GL11.glTexImage2D(GL11.java:2845)
at com.jme3.renderer.lwjgl.TextureUtil.uploadTexture(TextureUtil.java:352)
at com.jme3.renderer.lwjgl.LwjglRenderer.updateTexImageData(LwjglRenderer.java:1913)
at com.jme3.renderer.lwjgl.LwjglRenderer.setTexture(LwjglRenderer.java:1936)
at com.jme3.material.MatParamTexture.apply(MatParamTexture.java:86)
at com.jme3.material.Material.render(Material.java:1088)
at com.jme3.renderer.RenderManager.renderGeometry(RenderManager.java:523)
at com.jme3.renderer.queue.RenderQueue.renderGeometryList(RenderQueue.java:322)
at com.jme3.renderer.queue.RenderQueue.renderQueue(RenderQueue.java:371)
at com.jme3.renderer.RenderManager.renderViewPortQueues(RenderManager.java:788)
at com.jme3.renderer.RenderManager.flushQueue(RenderManager.java:719)
at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:983)
at com.jme3.renderer.RenderManager.render(RenderManager.java:1035)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:252)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
at com.jme3.system.lwjgl.LwjglCanvas.runLoop(LwjglCanvas.java:229)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
at java.lang.Thread.run(Thread.java:745)

Every now and again? Maybe you’re modifying the buffer on another thread?

It shouldnt do as I have specifically designed that all updates are buffered to be performed by the LWJGL thread only. However, I will run a test to ensure this is the case.

The code is only called by the LWJGL thread.

Looking into my code I perform a buffer get upon instantiation of the object. The buffer is updated using a different thread but the image of the texture is updated using only the LWJGL thread and as you can see the two processes are synchronized.

It is my understanding that as no changes are exeprienced until image.put is called that the buffer instance from image.get is a clone. If this is incorrect what is best practise? thanks.

private ByteBuffer bb;
public MyUpdater()
{
bb=image.getData(0);
bb.position(0);
}
public void updateBuffer()
{
synchronized(LOCK)
{
bb.position(pointer);
bb.put(bytes,pointer,thisW);
}
}
public void updateTexture()
{
synchronized(LOCK)
{
bb.position(0);
image.setData(bb);
}
}

You do the position reset in two separate methods so they can be called at any time and anyway your locks are not keeping the lwjgl thread from doing stuff.

Ok that would make sense.

So to overcome this error I need the LWJGL thread to perform the buffer writes?

My ethos so far has been to queue updates using alternative threads so the LWJGL thread doesnt get bogged down with non critical processes to promote a smoother front end. However, I am sure queuing the buffer writes and having the LWJGL thread perform these wont have a significant impact.

I will give this a try.
Thank you very much.

One question I do have is that if synchronize doesnt “synchronize” the LWJGL thread how am I to ensure threads communicate correctly through objects?

Will ConcurrentLinkedQueue work correctly? That is the object I use to queue updates.
Thanks

It seems to be working fine by queuing all the buffer writes into a ConcurrentLinkedQueue and then having the LWJGL thread perform the actual writes.

ConcurrentLinkedQueue is apparently thread safe so hopefully all of the issues with the LWJGL thread not being synchronized should be negated.

Many Thanks for your help.

application.enqueue() is already ready to use and does the same.

Does enqueue mean the object is executed using the LWJGL thread?

My purpose here is that I am using a different thread to execute time consuming non critical processes which negates causing significant overhead on the LWJGL thread.

I initially used synchronize so the threads communicated correctly but it appears this was insufficient hence causing the error.

Using ConcurrentLinkedQueue seems to pass instance data from that thread to the LWJGL thread without the synchronization problem and appears to work just fine.

Unless there is a specific advantage to using enqueue I am quite happy with how it currently works. I am however concerned that if ConcurrentLinkedQueue, designed to be thread safe, might actually drop some objects but it does not seem to be the case so far.

Regards

The specific advantage to using enqueue() is that it’s doing exactly what you wrote a bunch of code to do already. That’s all. Both of these approaches are thread safe but that one was already including specifically so that you could do what you are trying to do.

…which is kind of precisely what the javadoc says it does:
http://javadoc.jmonkeyengine.org/com/jme3/app/Application.html#enqueue(java.util.concurrent.Callable)

Keep the javadoc open at all times. It’s very useful.

I see where you are going with this.

However, using the ConcurrentLinkedQueue in the way I have allows a number of thread processes to create a batch list of buffer updates to which can all be updated in the same (synchronized) frame update. It works very well for my purposes.

In future if I require single instance update of a buffer I will consider implementing an enqueued callable.

Many Thanks.

I’m not sure I see the real difference. What is it that you are enqueing in your queue?

The update objects are stored in the ConcurrentLinkedQueue waiting and when the update system is ready to release the updates they are all done in one batch. This ensures that all the updates are synchronized.

If each update was enqueued they would not be synchronized and produce a lackadaisical update experience.

At the beginning of every frame, JME runs all enqueues Callables.

Yes, but in my case not every update will be ready on each frame as some of them are complicated. Using the method I have adopted they are visually synchronised. I am content that several frames may pass inbetween each update but most importantly all the updates are synchronised together.

My initial design only called the transfer of the buffer to the image at the end of all the updates. The difficulty I was experiencing was that using synchronized was not ensuring single thread manipulation of the objects and hence the errors. Now I have changed my design so that the details of the buffer updates are held in a ConcurrentLinkedQueue when all of the updates have completed the LWJGL thread is used to transfer the updates to the buffer before the image is updated and this appears to work fine.

Hopefully I have clearly explained that I need batch processing so using enqueue for each update will not provide the desired effect.

Many Thanks for your help. My design is continuing to work really well :smile:

So if I read it right… you also could have just passed all of your objects to a single callable when they were done. Somehow you are detecting that all of them are done from the lwjgl thread anyway… which seems redundant to me.

The irony is that concurrent linked queue is a good way to go when you DO want to avoid updating everything at once. Frame drops are really jarring and uploading a ton of data to the GPU in one frame will inevitably lead to frame drops. So many of us opt to do smaller updates per frame rather than one giant chunk. The user will hardly notice that 10 textures updated over 1/6th of a second but they will certainly notice a much smaller frame drop in anything but the stillest of scenes.

Updating the buffer of an image once in 10 frames seems a lot more efficient compared to every frame with partial updates. Bearing in mind the whole buffer has to be transfered on each update.

The LWJGL thread has nothing to do or plays any part with the updates until they are all ready to be batched.

I think you read my explanation wrong.