I've recently stumbled on a problem that took a few hours to pin down. On a desctop PC my code worked fine, but on a Vivante embedded device it crashed with segmentation fault on a seemingly good code.
Here's the code:
// get our VBO
vboID = vboIDList.get(1);
glBindBuffer(GL_COPY_READ_BUFFER, vboID);
// create new buffer and copy data
int newVboID = glGenBuffers();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, newVboID);
indexBuffer = MemoryUtil.memAllocInt(indexBufferLength);
indexBuffer.put(new int[indexBufferLength]).flip();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer, GL_STATIC_DRAW);
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_ELEMENT_ARRAY_BUFFER, 0, 0, indexCount * INT_SIZE);
//INT_SIZE is a static final = 4
//replace VBO
vboIDList.set(1, newVboID);
glDeleteBuffers(vboID);
// unbind buffers
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_COPY_READ_BUFFER, 0);
it crashed on glBufferSubData with no clear reason.
Turned out that in a rare case indexCount was equal 0, so I was trying to copy 0 bytes. Some drivers handle this well, but others do not.
Just in case someone stumbles on this too, that's my answer. Check for a positive copy length before calling glCopyBufferSubData().
Related
I'm currently trying to use glMultiDrawElementsIndirect in with LWJGL in Java, but I have an error INVALID_OPERATION.
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, this.modelManager.indirect, NB_TYPE_MESH, 0);
I see in the documentation this error is about the GL_DRAW_INDIRECT_BUFFER or GL_ELEMENT_ARRAY_BUFFER, but I don't know where the problem is in my code.
Indirect buffer
int[] indirect = new int[NB_TYPE_MESH*5];
for(int i=0; i<2; i++) {
indirect[i] = getElementCount().get(i);
indirect[1+i] = Game.NB_MAX_OBJECTS/2;
indirect[2+i] = 0;
indirect[3+i] = i==0?0:getElementCount().get(i-1);
indirect[4+i] = i; // maybe 0
}
vboIdIndirect = glGenBuffers();
IntBuffer gIndirectBuffer = MemoryUtil.memAllocInt(indirect.length);
gIndirectBuffer.put(indirect).flip();
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, vboIdIndirect);
glBufferData(GL_DRAW_INDIRECT_BUFFER, gIndirectBuffer, GL_DYNAMIC_DRAW);
and my elements buffer
vboId = glGenBuffers();
vboIdList.add(vboId);
indicesBuffer = MemoryUtil.memAllocInt(indices.length);
indicesBuffer.put(indices).flip();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboId);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer, GL_DYNAMIC_DRAW);
indices contains indices for NB_TYPE_MESH types of mesh
If a buffer is bound to the target GL_DRAW_INDIRECT_BUFFER when glMultiDrawElementsIndirect is called, the indirect argument is interpreted as an offset in basic machine units into this buffer.
Hence you need to bind the GL_DRAW_INDIRECT_BUFFER before drawing the elements, but the indirect argument must be null:
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, this.modelManager.indirect, NB_TYPE_MESH, 0);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, vboIdIndirect);
glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_INT, null, NB_TYPE_MESH, 0);
See also Java Code Examples glMultiDrawElementsIndirect()
I recently decided to start Learning OpenGL and got myself a book about OpenGL Core 3.3. The book is generally about C++.
So, after looking for a bit, I found a library in a language I was better in which provided almost the same functionality: lwjgl.
I followed the book's steps and translated the C++ syntax into java syntax, which worked until it got to actually drawing something.
There, the JVM just kept crashing, no matter what I changed about the code. After doing some debugging, I found out that the JVM crashed when I called either glVertexAttribPointer or glDrawArrays.
I am very new to OpenGL, and I am assuming this question must sound very stupid to someone more experienced, but: What do I need to change about this code?
float[] vertices = {
-0.5f, -0.5f, -0.0f,
0.5f, 0.5f, 0.0f,
0.0f,0.5f,0.0f
};
FloatBuffer b = BufferUtils.createFloatBuffer(9);
b.put(vertices);
int VBO = glGenBuffers();
int VAO = glGenVertexArrays();
log.info("VBO:" + VBO + "VAO: " + VAO);
// bind the Vertex Array Object first, then bind and set vertex buffer(s), and then configure vertex attributes(s).
glBindVertexArray(VAO);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 12, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices, GL_STATIC_DRAW);
glBindVertexArray(0);
// Run the rendering loop until the user has attempted to close
// the window or has pressed the ESCAPE key.
while (!glfwWindowShouldClose(window))
{
// input
// -----
// render
// ------
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// draw our first triangle
glUseProgram(shaderProgram);
glBindVertexArray(VAO); // seeing as we only have a single VAO there's no need to bind it every time, but we'll do so to keep things a bit more organized
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0); // no need to unbind it every time
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
I would be very thankful for any help i can get, if you need more info/ need to see more of my code please let me know. Thanks in advance
You have to bind the vertex buffer object to the target GL_ARRAY_BUFFER, before specifying the vertex attribute:
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 12, 0);
When glVertexAttribPointer is called, the buffer object currently bound to the ARRAY_BUFFER target is associated to the attribute (index) and a reference to the buffer object is stored in the state vector of the Vertex Array Object.
As in the title, I'm using OpenGL ES (2) on Android (7.0).
Apparently, though, I have some problems when trying to load a texture from the asset folder.
This is the code I'm using
public static int loadTexture(final AssetManager assetManager, final String img)
{
final int[] textureHandle = new int[1];
glGenTextures(1, textureHandle, 0);
if(textureHandle[0] == 0)
throw new RuntimeException("Error loading texture");
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
try
{
final Bitmap bitmap = BitmapFactory.decodeStream(assetManager.open(img));
glBindTexture(GL_TEXTURE_2D, textureHandle[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
catch (IOException e)
{
e.printStackTrace();
}
textures.put(img, textureHandle[0]);
return textureHandle[0];
}
This is called from onSurfaceCreated as I know I need a running OpenGL context
Most of the time this works and gives me this result
but a considerable number of other times I get this
No Exception is thrown.
I know the problem is not depending on the 3D model nor the texture because I've tried other ones. The only thing I can do when this happens is to restart my App a couple of times.
I've tried googling around but with no results. I know I could try to implement another loading function, but first I'd like to understand why this is not ok and where it's not working.
If you think this could depends on the code I'm using to render the scene here it is (no VAOs because I need to support older devices and OpenGL ES 2):
glBindBuffer(GL_ARRAY_BUFFER, model.getCoordsVBO());
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, model.getTextureVBO());
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, model.getNormalsVBO());
glVertexAttribPointer(2, 3, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(2);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, entity.getTexture());
loadFloat(loc_textureSampler, 0);
if(model.getIndicesBuffer() != null)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, model.getIndicesVBO());
glDrawElements(GL_TRIANGLES, model.getVertexCount(), GL_UNSIGNED_INT, 0);
}
else
glDrawArrays(GL_TRIANGLES, 0, model.getVertexCount());
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
What I didn't say (because I thought it was irrelevant) is that I had a little more code ad the top of the function...
if(textures.containsKey(img))
return textures.get(img);
and at the bottom
textures.put(img, textureHandle[0]);
I thought it was intelligent to keep track of the textures, so I could have called this load function anytime I needed a texture and if I had already loaded it, it would have returned it without loading again.
This could work on a desktop application, but I haven't considered that on Android the garbage collector could delete the texture from OpenGL when I exit the app so that when the activity restarts it wouldn't be there anymore.
Removing that HashMap solved the problem, demonstrating that the actual reading and loading code had nothing to do with that black thing.
According to lwjgl javadooc, there is a function :
public static void glGenBuffers(int n, ByteBuffer buffer)
But i dont exactly understand how this works.
Do i create an ByteBuffer :
ByteBuffer buffer = ByteBuffer.allocate("how much???")
glGenBuffers(4, buffer);
And especially do i have to fill the Buffer with glBufferSubData OR
is it better to create 4 buffers and bind and fill them?
My thought was, that it is more efficient when i only create 1 Buffer ,which stores vertices,texturecoords,normals and indices.
glGenBuffers(int n, ByteBuffer buffer) generates n vertex buffer objects (VBOs), which you can use to store your data, and puts them in the specified buffer. This buffer is not actually the one that holds your data, but the ids of the VBOs just generated. You have to manually define the VBO data with glBufferData.
The function is useful if you want to create multiple VBOs with a single call. Each VBO id is an integer, and the buffer has to be large enough to hold n (in this case 4) buffers.
ByteBuffer buffer = BufferUtils.createByteBuffer(4 * Integer.BYTES);
glGenBuffers(4, buffer);
However, to make things easier, you can also use an IntBuffer.
IntBuffer buffer = BufferUtils.createIntBuffer(4);
glGenBuffers(4, buffer);
You can then attach the data to each of the VBOs.
glBindBuffer(GL_ARRAY_BUFFER, buffer.get(2); /*value from 0 to 3*/
glBufferData(GL_ARRAY_BUFFER, data, GL_STATIC_DRAW);
(If you are using a ByteBuffer, you have to call buffer.getInt(2) instead.)
It is generally more efficient to have all data in a single buffer, but note that in this case you have to use at least two because indices have to be in a GL_ELEMENT_ARRAY_BUFFER. However, the performance difference is very small, so it may be easier to use several different VBOs.
It is preferred to tightly pack all the data in a buffer and upload that with glBufferData instead of calling glBufferSubData for each type of data. Your data layout will then look something like this (P = position, T = texture coordinate, N = normal vector):
PPPTTNNNPPPTTNNNPPPTTN...
Now you can setup the vertex attribute pointers to correctly read the values from this buffer.
int vbo = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, tightlyPackedData, GL_STATIC_DRAW);
int stride = (3 + 2 + 3) * Float.BYTES;
glVertexAttribPointer(positionIndex, 3, GL_FLOAT, false, stride, 0);
glVertexAttribPointer(texCoordIndex, 2, GL_FLOAT, false, stride, 3 * Float.BYTES);
glVertexAttribPointer(normalIndex, 3, GL_FLOAT, false, stride, (3 + 2) * Float.BYTES);
positionIndex, texCoordIndex and normalIndex are the attribute locations of your vertex shader attributes. You can get them with glGetAttribLocation.
stride is the number of bytes between the value of one vertex and the value of the next one. We have 3 positions, 2 texture coordinates and 3 normals, which are all floats, so we multiply them with Float.BYTES.
The last parameter to glVertexAttribPointer is the offset in bytes, i.e. the number of bytes from the start of the buffer to where the first value is located.
I am trying to render large VBO array objects, containing ~700000 values and I have ~1500000 values in my element_array buffer. But what I am getting is a blank screen. On the other hand if I just use only the VAO, my code works correctly. My code is as follows:
//Data buffers
FloatBuffer vertexBuffer = GLBuffers.newDirectFloatBuffer(this.coordCount);
vertexBuffer.put(Vertices);
vertexBuffer.rewind();
IntBuffer indexBuffer = GLBuffers.newDirectIntBuffer(this.indexCount);
indexBuffer.put(index);
indexBuffer.rewind();
//setting up the VBO
int nVBO = 2;
int[] VBO = new int[nVBO];
gl.glGenBuffers(nVBO, VBO,0);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, VBO[0]);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER,VBO[1]);
gl.glBufferData(GL.GL_ARRAY_BUFFER, this.coordCount*Float.SIZE, vertexBuffer, GL.GL_STATIC_DRAW);
gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, this.indexCount*Integer.SIZE, indexBuffer, GL.GL_STATIC_DRAW);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, VBO[0]);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, VBO[1]);
gl.glEnableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, 0);
//gl.glVertexPointer(3, GL.GL_FLOAT, 0, vertexBuffer);
//gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, 4);
gl.glDrawElements(GL.GL_TRIANGLES, this.indexCount, GL.GL_UNSIGNED_INT, 0);
//gl.glDrawElements(GL.GL_TRIANGLES, this.indexCount, GL.GL_UNSIGNED_INT, indexBuffer);
gl.glDisableClientState(GLPointerFunc.GL_VERTEX_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0);
Any clues/suggestions on how I can fix this?
Is this code block called each time when the loop runs? If it is, you should divide your vbo phases into different blocks.This sample code may help you how to divide. (In the link that I post, you should just focus initVBO and renderVbo functions) I guess your initializing your vbo's sequentially, which it may make your program unresponsive.