Daemon
Daemon copied to clipboard
Tiled artifacts with smoke
Some of the light tiles are seemingly poking holes through the smoke. The bug does not happen if setting r_drawDynamicLights 0. Happens with both 0.55.0 engine and a recent engine.
The tiled realtime light renderer has a known limitation with non-depth-writing textures since it filters out lights if they are out of range according to the depth buffer. We could try to blame it on that (if the grate textures are non-depth-writing), but I don't think that could explain why the smoke is not visible at all in some spots.
It's possible that the lights are added in those spots but the blending modes make the result look weird.
I tried setting attenuation = 0.0; in the computeDynamicLight GLSL function. Having lights with 0 intensity ought to be the same as having no lights, but the same artifact is produced. So there must be a real bug.
In fact it DOES happen with r_drawDynamicLights 0. Must have messed up the previous test somehow. After fixing r_showLightTiles, I see that the light tiles are bigger than the squares I'm getting here here. And there aren't even any dynamic lights being rendered in the messed up area. So nothing to do with dynamic lights. Tile-patterned artifacts can happen with various driver/GPU bugs such as in #949
Doesn't happen for me with Intel or Nvidia proprietary drivers.
Easy repro steps:
devmap uvcssetviewpos -2242 -1267 184 177 -27testshader gfx/weapons/rifle/smokeortestshader gfx/buildables/acid_tube/spore
The triggering condition for the foreground shader is use of depth fade. I haven't investigated yet what needs to be in the background.
This seems to be happening in front of surfaces with alpha-test? Might be worth trying to visualise the depth buffer.
Btw does switching relief mapping affect it in any way?
It happens in both ultra and low presets so does not depend on relief mapping setting.
The depth value as read in the generic shader with depth fade enabled, with the color formula 1 / (1.0001 - depth) / 600.
I don't think those low values are really written to the depth buffer as I can put a model in front of there and it displays fine. But wrong values are read out by the shader. Maybe there is some bug with not maintaining a consistent view of memory.
I don't think those low values are really written to the depth buffer as I can put a model in front of there and it displays fine. But wrong values are read out by the shader. Maybe there is some bug with not maintaining a consistent view of memory.
Does it happen to use bindless textures? That's the only issue I could think of right now.
It does also look like a tiling pattern you might get with rasterisation, so it might just be that it hasn't finished writing to the depth buffer yet for some reason. Could be worth trying to add glFinish() or glMemoryBarrier( GL_ALL_BARRIER_BITS ) after the relevant drawcalls and seeing if it changes anything.
Happens regardless of bindless texture (or material system) settings.
I tried putting glMemoryBarrier( GL_ALL_BARRIER_BITS ) in Tess_End and that didn't fix it.
Since I didn't note the GPU model yet it's AMD Radeon RX 7700 XT. Mesa 22.3.6
I guess it's just a driver bug then.
I tried putting a call to glTextureBarrier() in Tess_End and that fixes it. This function requires the ARB_texture_barrier extension. Maybe we could call that only before shaders that use the depth sampler.
Maybe we could call that only before shaders that use the depth sampler.
Sounds good.
Although TextureBarrier worked in practice, I don't think it stops the undefined results according to the standard. From OpenGL 3.2 section 3.8.9 "Texture Minification:
Rendering Feedback Loops If all of the following conditions are satisfied, then the value of the selected τijk, τij , or τi in the above equations is undefined instead of referring to the value of the texel at location (i, j, k), (i, j), or (i) respectively. This situation is discussed in more detail in the description of feedback loops in section 4.4.3. • The current DRAW_FRAMEBUFFER_BINDING names a framebuffer object F. • The texture is attached to one of the attachment points, A, of framebuffer object F. • <long-winded condition about using the same level if it is a multi-level texture>
This seems to apply that all reads from the depth texture have undefined value while we are rendering to the main 3D rendering FBO. That section still has the same content in OpenGL 4.5 which incorporates ARB_texture_barrier. So I think the standardly correct way would be to detach the depth texture from the FBO while we need to read from it. I guess we could do that after rendering all opaque shaders.
Hmm I don't see any way of getting past the "feedback loop" rules without creating a copy of the depth buffer, so I guess I'll go with the texture barrier hack.
Also I just noticed the bug does not occur with all alpha-tested textures. The offending texture from map uvcs was textures/shared_vega/grate01. It has alphafunc GE128, blendfunc blend, and depthwrite. Meanwhile textures/yocto_ex/rndfloor_01st_d, which has alphafunc GE128 but no blending, does not exhibit the bug.
Oh I bet it's the polygonOffset that triggers the bug. That could involve a different GPU code path for writing the depth. Unless it's just the different shader sort that makes it be drawn later. Here's a shader which exhibits the bug:
textures/shared_vega/grate02
{
qer_editorImage textures/shared_vega_src/grate02_b
qer_alphaFunc greater .5
surfaceparm nomarks
surfaceparm metalsteps
// polygonOffset fixes Z-fighting with objects on top of the grate
polygonOffset
cull none
imageMinDimension 128
{
diffuseMap textures/shared_vega_src/grate02_b
alphafunc GE128
blend blend
depthwrite
}
}
That shader has sort order DECAL (6). textures/shared_vega/grate02_nonsolid is identical, except it does not have polygonOffset. It has sort order SEE_THROUGH (7). So sort order is probably not the culprit. The Yocto grates have sort order OPAQUE (4).
Although
TextureBarrierworked in practice, I don't think it stops the undefined results according to the standard. From OpenGL 3.2 section 3.8.9 "Texture Minification:Rendering Feedback Loops If all of the following conditions are satisfied, then the value of the selected τijk, τij , or τi in the above equations is undefined instead of referring to the value of the texel at location (i, j, k), (i, j), or (i) respectively. This situation is discussed in more detail in the description of feedback loops in section 4.4.3. • The current DRAW_FRAMEBUFFER_BINDING names a framebuffer object F. • The texture is attached to one of the attachment points, A, of framebuffer object F. •
This seems to apply that all reads from the depth texture have undefined value while we are rendering to the main 3D rendering FBO. That section still has the same content in OpenGL 4.5 which incorporates
ARB_texture_barrier. So I think the standardly correct way would be to detach the depth texture from the FBO while we need to read from it. I guess we could do that after rendering all opaque shaders.
No, using glTextureBarrier() is correct:
9.3.1 Rendering Feedback Loops:
Specifically, the values of rendered fragments are undefined if any shader stage fetches texels and the same texels are written via fragment shader outputs, even if the reads and writes are not in the same draw call, unless any of the following exceptions apply: .. • If a texel has been written, then in order to safely read the result a texel fetch must be in a subsequent draw call separated by the command void TextureBarrier( void ); TextureBarrier will guarantee that writes have completed and caches have been invalidated before subsequent draw calls are executed.
No, using
glTextureBarrier()is correct: 9.3.1 Rendering Feedback Loops:
Yeah, there's that section about exceptions where a texture write is not undefined. But it doesn't say anything to negate the other section I quoted where a texture read is undefined. So taken altogether, the spec seems to say you are allowed to read a texture, throw away the value without using it, and then write something to the same texture :-) But it seems to be understood by the community that you are supposed to be able to read and write the texture while using the value. So I will go ahead with adding a barrier at the point before SS_BLEND0 shaders are rendered.
I opened https://github.com/UnvanquishedAssets/tex-vega_src.dpkdir/pull/4 to fix the bogus usage of polygonOffset in the grate shader. But valid uses of polygonOffset for decals are also affected:
Fix is now in. But I will note that with material system enabled, the depth values can be bad with any old surface -- it doesn't have to be polygonOffset.