However, my efforts were in vain because that was only the place where the problem was manifesting itself, not where the actual problem is.
The actual problem has to do with the inner workings of ::glFlush(), which is called by presentRenderbuffer:. I can replace presentRenderbuffer: with ::glFlush() and get the same results.
So what is the actual problem?
In my extremely exhaustive search for the problem, I stripped down the code to the point where it is issuing no draw calls. It does everything else, such as activate shaders, set/unset textures, change render targets, etc.
The result is an expected 60 FPS.
I then enabled a single draw call. A triangle strip with just 4 vertices. The shader for it simply reads a texture and returns the result. The purpose is simply to copy from the 480×320 back-buffer texture to the 960×640 render buffer.
Suddenly it drops to 30 FPS. A single draw call adds 16.6 milliseconds to my frame time.
That is ridiculous.
The renderer is running on a separate thread from the main iOS thread, but all the OpenGL ES 2 calls are on that thread.
This should not be a problem because my past engine was rendering from a second thread and could always reach 60 FPS in OpenGL ES 1.0.
Also, executing the draw command inside the OpenGL ES 2 driver does not take 16.6 milliseconds.
My current engine works the same way (rendering 3D to a back buffer and then copying it to the render buffer before calling presentRenderbuffer:) yet I can run physically based shaders and post-processing at 55-60 FPS, so I certainly won’t accept that, “switching render targets is just that slow,” or, “the fill-rate is just that bad.”
The render call is leaving behind side-effects that cause ::glFinish to stall unreasonably.
I can add back the rest of the render calls and it stays at 30 FPS. So it isn’t that any draw command itself is actually taking a long time, it is just causing an unnecessary stall.
I would normally assume it is waiting for V-blank, but that doesn’t fit, since it stalls for up to 32 milliseconds.
Here are the actual render commands I issue in one frame (resulting in 30 FPS):
#0 GL_NO_ERROR <- glGetError()
#1 GL_NO_ERROR <- glGetError()
#2 GL_NO_ERROR <- glGetError()
#3 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 8, 0)
#4 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 4)
#5 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0)
#6 glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, {GL_DEPTH_ATTACHMENT})
#7 glClearDepthf(0.0000000)
#8 glClearStencil(0)
#9 glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, {GL_COLOR_ATTACHMENT0})
#10 glClear(GL_COLOR_BUFFER_BIT)
#11 glDepthMask(1)
#12 glClear(GL_DEPTH_BUFFER_BIT)
#13 glDepthMask(0)
#14 glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, {GL_STENCIL_ATTACHMENT})
#15 glClear(GL_STENCIL_BUFFER_BIT)
#16 glDepthMask(1)
#17 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 1)
#18 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 2)
#19 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 2)
#20 glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, {GL_DEPTH_ATTACHMENT})
#21 glBindTexture(GL_TEXTURE_2D, 8)
#22 glVertexAttribPointer(2, 3, GL_FLOAT, 0, 36, 0x07709cac)
#23 glVertexAttribPointer(1, 4, GL_FLOAT, 0, 36, 0x07709cb8)
#24 glVertexAttribPointer(0, 2, GL_FLOAT, 0, 36, 0x07709cc8)
#25 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
#26 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
#27 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
#28 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
#29 glUseProgram(79)
#30 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4)
#31 glUseProgram(82)
#32 glUniformMatrix4fv(asTexStage[2], 1, 0, {-2.4142134, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 3.2390072, 0.0000904, -0.4472136, 0.0000000, -1.6195037, 0.0001807, -0.8944272, 0.0000000, 0.0000000, 9.8761530, 1118.0339355})
#33 glUniform4fv(csvConst_1, 3, {1.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 1.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 1.0000000, 0.0000000})
#34 glUniform4fv(7, 1, {1.0000000, 1.0000000, 1.0000000, 1.0000000})
#35 glVertexAttribPointer(1, 3, GL_FLOAT, 0, 52, 0x0885b990)
#36 glVertexAttribPointer(0, 4, GL_UNSIGNED_BYTE, 1, 52, 0x0885b9a8)
#37 glDepthMask(0)
#38 glUseProgram(110)
#39 glUniform4fv(csvConst_1, 2, {0.0020833, -0.0031250, 1.0000000, 1.0000000, -1.0000000, 1.0000000, 0.0000000, 0.0000000})
#40 glVertexAttribPointer(1, 4, GL_FLOAT, 0, 28, 0x0cbe3240)
#41 glVertexAttribPointer(0, 4, GL_UNSIGNED_BYTE, 1, 28, 0x0cbe3250)
#42 glBindTexture(GL_TEXTURE_2D, 2)
#43 glUseProgram(111)
#44 glUniform4fv(csvConst_1, 2, {0.0020833, -0.0031250, 1.0000000, 1.0000000, -1.0000000, 1.0000000, 0.0000000, 0.0000000})
#45 glVertexAttribPointer(1, 4, GL_FLOAT, 0, 28, 0x0cc3a040)
#46 glVertexAttribPointer(0, 4, GL_UNSIGNED_BYTE, 1, 28, 0x0cc3a050)
#47 glVertexAttribPointer(2, 2, GL_FLOAT, 0, 28, 0x0cc3a054)
#48 glDepthMask(1)
#49 glDepthMask(0)
#50 glUseProgram(82)
#51 glUniformMatrix4fv(asTexStage[2], 1, 0, {-0.6600000, 0.0000000, 0.0000000, 0.0000000, 0.2657602, 1.1154090, 0.0000596, -0.2951610, 0.5315203, 0.0171107, 0.0001193, -0.5903219, -432.1875000, -373.9130249, 10.0050621, 480.0000000})
#52 glUniform4fv(csvConst_1, 3, {-0.6600000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.5903220, -0.2951610, 0.0000000, 0.0000000, -0.2951610, -0.5903219, 0.0000000})
#53 glUniform4fv(7, 1, {1.0000000, 1.0000000, 1.0000000, 1.0000000})
#54 glVertexAttribPointer(1, 3, GL_FLOAT, 0, 52, 0x0ccd8860)
#55 glVertexAttribPointer(0, 4, GL_UNSIGNED_BYTE, 1, 52, 0x0ccd8878)
#56 [0x0000000002480500 presentRenderbuffer:GL_RENDERBUFFER]This is with only the 1 draw call being allowed (line #30)
What could be causing such unreasonable stalls here?
Buffer resolves? Buffer restores?
Anyone ever see this before?
L. Spiro






