I have an FBO with only 16-bit depth attachment:
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, w, h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, nullptr);
I render something to it, so now I have a depth texture with 16-bit precision. What is the best way to update this texture on the GPU (while maintaining precision), before passing it to the shader that will actually use it?
For example, let’s say I want to update depth texture so that for every texel at b[/b], if u < 0.5 then the resulting texel would be equal to min between texel at b[/b] and (u+0.5, v). Value is unchanged otherwise.
The only way to do this that I can see is to create second FBO with similar depth attachment, and render to it while reading from 1st FBO’s depth texture. During this render pass I can write updated values to 2nd FBO’s texture through gl_FragDepth.
Is there a better way to do this? Can I avoid having 2 FBOs and update depth texture in-place, or is it considered a feedback loop and thus undefined behavior?
You can modify a texture in-place using imageLoad() and imageStore() (requires OpenGL 4.2 or the ARB_shader_image_load_store extension), either in a fragment shader or a compute shader (OpenGL 4.3).
But I’d suggest comparing the performance of image load/store against using two textures. In general, image load/store has to consider synchronisation (the implementation may be able to determine that there’s a 1:1 mapping between texels and shader invocations and optimise accordingly, but it’s not guaranteed), whereas this is a non-issue for render-to-texture.
You can’t read the texture while it’s bound to the current framebuffer. More precisely, you can’t allow the shader to read from the level which is bound to the current framebuffer (whether the shader actually reads it is irrelevant; if the level is capable of being read, it’s considered a feedback loop and the results are undefined).
Thank you for the response. I forgot to mention that I’m targeting OpenGL ES 3.0 and below, so compute shader and read/store pixels are unfortunately not a viable options.
I guess I’ll stick to two FBO’s.
See if you’ve got access to ARM_shader_framebuffer_fetch_depth_stencil or EXT_shader_framebuffer_fetch (or the ARM variant).
If you’ve got the first, sounds like you can just access the last value in the fragment shader as gl_LastFragDepthARM. If you’ve only got the latter, you’ll need to bind your texture to a color buffer and use gl_LastFragData[n].
The nice thing about these is you don’t need to ping-pong your rendering between render targets, which can save a lot of DRAM bandwidth on mobile (even more if you properly clear/invalidate your render targets before/after rendering).
Thanks for the suggestion. I probably could use these extensions as an optimization, when they are available, and fallback to 2 FBOs otherwise.