Properly save and restore FB attachments in pixel history

* When we need to substitute a depth attachment, ensure we handle all attachment
  possibilities
This commit is contained in:
baldurk
2026-08-24 17:46:20 +01:00
parent 4db49e2c6b
commit f8e2d0f36c
+123 -35
View File
@@ -2138,36 +2138,57 @@ void QueryPrePostModPerFragment(WrappedOpenGL *driver, GLReplay *replay,
int postModLastJ = 0;
// save D/S attachment since we'll substitute our own depth
// for simplicity we assume sanity and that different objects won't be bound to each point.
GLuint curDepth;
GLint curDepthType;
GLuint curStencil;
GLint curStencilType;
GLint curStencilLevel = 0, curDepthLevel = 0;
GLint curType = eGL_NONE;
GLint curLevel = 0, curLayered = 0, curLayer = 0, curVirtualSamples = 0, curStartView = 0,
curNumViews = 0;
driver->glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
(GLint *)&curDepth);
driver->glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
&curDepthType);
if(curDepth)
{
driver->glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
&curDepthLevel);
}
driver->glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
(GLint *)&curStencil);
driver->glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
&curStencilType);
if(curStencil)
GLenum queryAtt = eGL_NONE;
if(curDepth)
queryAtt = eGL_DEPTH_ATTACHMENT;
else if(curStencil)
queryAtt = eGL_STENCIL_ATTACHMENT;
if(queryAtt)
{
driver->glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT,
eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
&curStencilLevel);
driver->glGetFramebufferAttachmentParameteriv(
eGL_DRAW_FRAMEBUFFER, queryAtt, eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &curType);
driver->glGetFramebufferAttachmentParameteriv(
eGL_DRAW_FRAMEBUFFER, queryAtt, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, &curLevel);
if(HasExt[ARB_geometry_shader4])
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, queryAtt,
eGL_FRAMEBUFFER_ATTACHMENT_LAYERED, &curLayered);
else
curLayered = 0;
if(curLayered == 0)
GL.glGetFramebufferAttachmentParameteriv(
eGL_DRAW_FRAMEBUFFER, queryAtt, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER, &curLayer);
if(HasExt[EXT_multisampled_render_to_texture])
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, queryAtt,
eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT,
&curVirtualSamples);
if(HasExt[OVR_multiview])
{
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, queryAtt,
eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_NUM_VIEWS_OVR,
&curNumViews);
GL.glGetFramebufferAttachmentParameteriv(
eGL_DRAW_FRAMEBUFFER, queryAtt, eGL_FRAMEBUFFER_ATTACHMENT_TEXTURE_BASE_VIEW_INDEX_OVR,
&curStartView);
}
}
// if we didn't have a depth buffer, turn off depth testing so we don't have to worry about
@@ -2464,25 +2485,92 @@ void QueryPrePostModPerFragment(WrappedOpenGL *driver, GLReplay *replay,
}
// restore original D/S attachments
if(curDepthType != eGL_RENDERBUFFER)
GLenum attachment = eGL_DEPTH_STENCIL_ATTACHMENT;
GLuint obj = 0;
if(curDepth)
{
driver->glFramebufferTexture(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, curDepth,
curDepthLevel);
attachment = eGL_DEPTH_ATTACHMENT;
obj = curDepth;
if(curStencil)
attachment = eGL_DEPTH_STENCIL_ATTACHMENT;
}
else if(curStencil)
{
attachment = eGL_STENCIL_ATTACHMENT;
obj = curStencil;
}
if(curType == eGL_RENDERBUFFER && obj)
{
GL.glFramebufferRenderbuffer(eGL_DRAW_FRAMEBUFFER, attachment, eGL_RENDERBUFFER, obj);
}
else
{
driver->glFramebufferRenderbuffer(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT,
eGL_RENDERBUFFER, curDepth);
}
if(curStencilType != eGL_RENDERBUFFER)
{
driver->glFramebufferTexture(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT, curStencil,
curStencilLevel);
}
else
{
driver->glFramebufferRenderbuffer(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT,
eGL_RENDERBUFFER, curStencil);
if(!curLayered && obj)
{
// if obj is a cubemap use face-specific targets
WrappedOpenGL::TextureData &details =
driver->m_Textures[driver->GetResourceManager()->GetResID(TextureRes(driver->GetCtx(), obj))];
if(details.curType == eGL_TEXTURE_CUBE_MAP)
{
GLenum faces[] = {
eGL_TEXTURE_CUBE_MAP_POSITIVE_X, eGL_TEXTURE_CUBE_MAP_NEGATIVE_X,
eGL_TEXTURE_CUBE_MAP_POSITIVE_Y, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
};
if(curLayer < 6)
{
GL.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, attachment, faces[curLayer], obj,
curLevel);
}
else
{
RDCWARN("Invalid layer %u used to bind cubemap to framebuffer. Binding POSITIVE_X");
GL.glFramebufferTexture2D(eGL_DRAW_FRAMEBUFFER, attachment, faces[0], obj, curLevel);
}
}
else if(details.curType == eGL_TEXTURE_CUBE_MAP_ARRAY ||
details.curType == eGL_TEXTURE_1D_ARRAY || details.curType == eGL_TEXTURE_2D_ARRAY ||
details.curType == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY ||
details.curType == eGL_TEXTURE_3D)
{
if(curNumViews > 1)
{
if(curVirtualSamples > 1)
{
GL.glFramebufferTextureMultisampleMultiviewOVR(eGL_DRAW_FRAMEBUFFER, attachment, obj,
curLevel, curVirtualSamples,
curStartView, curNumViews);
}
else
{
GL.glFramebufferTextureMultiviewOVR(eGL_DRAW_FRAMEBUFFER, attachment, obj, curLevel,
curStartView, curNumViews);
}
}
else
{
GL.glFramebufferTextureLayer(eGL_DRAW_FRAMEBUFFER, attachment, obj, curLevel, curLayer);
}
}
else if(curVirtualSamples > 1)
{
GL.glFramebufferTexture2DMultisampleEXT(eGL_DRAW_FRAMEBUFFER, attachment, details.curType,
obj, curLevel, curVirtualSamples);
}
else
{
RDCASSERT(curLayer == 0);
GL.glFramebufferTexture(eGL_DRAW_FRAMEBUFFER, attachment, obj, curLevel);
}
}
else
{
GL.glFramebufferTexture(eGL_DRAW_FRAMEBUFFER, attachment, obj, curLevel);
}
}
driver->glDeleteTextures(1, &forcedDepth);