INVALID_OPERATION trying to glMapBufferRange for the second time

Hello,

What I need is basically to modify my vertex coordinates in the GPU, and copy back those modified coordinates to CPU’s VBO.

The point is that I prepare the shape of my mesh once on startup of my app in the GPU, copy back the coords to CPU, and from that point on I keep sending those coords back to GPU, where they might again be modified, but this time on an ad-hoc, user-input-dependant, basis.

I use the following function to copy back - transform feedback:

public void copyTransformToVertex()
 {
 ByteBuffer buffer = (ByteBuffer)GLES30.glMapBufferRange( GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0,
                                                          TRAN_SIZE*mNumVertices, GLES30.GL_MAP_READ_BIT);
 if( buffer!=null )
   {
   FloatBuffer feedback = buffer.order(ByteOrder.nativeOrder()).asFloatBuffer();
   feedback.get(mVertAttribs1,0,VERT1_ATTRIBS*mNumVertices);
   mVBO1.updateFloat(mVertAttribs1);
   }
 else
   {
   int error = GLES30.glGetError();
   Log.e("mesh", "failed to map tf buffer, error="+error);  // INVALID_OPERATION here
   }

 GLES30.glUnmapBuffer(GLES30.GL_TRANSFORM_FEEDBACK);
 }

Now, the above works. Works if I do it the first time. But recently I discovered that under some rare circumstances, I need to modify my shape one more time on the GPU and send the results back to the CPU again. So I call the very same function again and this time I get GL_ERROR 1282 - INVALID_OPERATION.

So glMapBufferRange throws INVALID_OPERATION. Reading the spec,

GL_INVALID_OPERATION is generated for any of the following conditions:

The buffer is already in a mapped state.
Neither GL_MAP_READ_BIT or GL_MAP_WRITE_BIT is set.
GL_MAP_READ_BIT is set and any of GL_MAP_INVALIDATE_RANGE_BIT, GL_MAP_INVALIDATE_BUFFER_BIT, or GL_MAP_UNSYNCHRONIZED_BIT is set.
GL_MAP_FLUSH_EXPLICIT_BIT is set and GL_MAP_WRITE_BIT is not set. 

it would seem like the only reason might be that the buffer is already in a mapped state - but I do Unmap the buffer the first time around, don’t I?

Do you? You didn’t show us. I would check that.

I would also check that there is no GL error signalled before your glMapBufferRange() call by calling glGetError() here and verifying that you get GL_NO_ERROR.

Also, GL_INVALID_OPERATION can be thrown for reasons not repeatedly documented in the man page. See the GL-ES spec for details.

One final point: This is all geared toward clearing the error and achieving correct behavior with the method you’re attempting. If you’re targeting a mobile GPU (or even some desktops), what you’re doing is unlikely to yield the best performance.

Do you? You didn’t show us. I would check that.

Well I do call GLES30.glUnmapBuffer(GLES30.GL_TRANSFORM_FEEDBACK); as the last thing in my function - is that not enough?

I would also check that there is no GL error signalled …

Fair point

what you’re doing is unlikely to yield the best performance.

Ok but I do it only once, on startup, and now I want to do it a second time - but only in exceptional circumstances?

What Dark_Photon said is that persistent mapping would result in better performances. See this for example. But I would for sure first resolve your current issue.

It wasn’t clear to me that copyTransformToVertex() was the function you were calling on startup. If so, then yes. Do you only map it here for read but never for write? If not, you might check that that other map call has a corresponding unmap.

No, that’s not what I’m saying. I’m saying what he’s doing is unlikely to yield great performance.

Persistent maps may or may not yield better perf on his mobile platform, but I personally haven’t used that on any mobile GPU drivers.