Search code examples
javamultithreadingopengllwjglvao

How to load VBO and render it on separate Java threads?


To create a virtual world I am using Lightweight Java Game Library (LWJGL) (Java + OpenGL). I want to load my terrains into graphics card memory on worker thread, while on main thread I want to take these, already loaded terrains, and render them. In order to do that I have to create Vertex Array Object (VAO), create Vertex Buffer Object (VBO), add VBO into VAO attribute list and finally render everything. This works perfectly on single-threaded system, however I am having problems implementing it on multi-threaded system. I know that VBO can be shared between OpenGL contexts, while VAO cannot be shared (reference1; reference2). Therefore to accomplish my goal I:

  1. create VAO on main thread,
  2. create VBO on worker tread by using these methods:

    GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, ID); int ID = GL15.glGenBuffers(); GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW); GL20.glVertexAttribPointer(attributeNr, coordSize, GL11.GL_FLOAT, false, 0, 0); GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);

  3. render it on main thread, however I get this exception:

Exception in thread "main" org.lwjgl.opengl.OpenGLException: Cannot use offsets when Element Array Buffer Object is disabled

I am sure that I do not render not loaded terrains, because I load terrains when they are outside render scope. I have read many articles, questions and blogs about OpenGL shared contexts and concurrency, but did not managed to find a solution. I would be very grateful for any help.


Solution

  • As you already stated, VAOs are NOT shared between contexts, so it is also impossible to modify them from multiple threads.

    GL20.glVertexAttribPointer(attributeNr, coordSize, GL11.GL_FLOAT, false, 0, 0); 
    

    is modifying the VAO state, thus it has to be called from the main thread.

    It is perfectly fine to have the data upload (glBufferData) in a separate thread, but constructing the VAO can only be done from the main thread.