From f395f244eb08bd5aa24b4af7172e842d05a277a9 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 16 Jan 2019 13:47:56 +0000 Subject: [PATCH] Add initial contents and dirtying for high-frequency samplers * For samplers that are updated a lot we fall back to fetching & applying their state as initial contents. --- renderdoc/driver/gl/gl_common.cpp | 4 + renderdoc/driver/gl/gl_driver.h | 2 +- renderdoc/driver/gl/gl_initstate.cpp | 129 ++++++++++++++++++ renderdoc/driver/gl/gl_initstate.h | 15 ++ .../driver/gl/wrappers/gl_sampler_funcs.cpp | 90 +++++++++++- 5 files changed, 233 insertions(+), 7 deletions(-) diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index d86f104d2..72caed652 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -1141,6 +1141,10 @@ bool GLInitParams::IsSupportedVersion(uint64_t ver) if(ver == 0x1D) return true; + // 0x1E -> 0x1F - added initial states for samplers that are modified a lot + if(ver == 0x1E) + return true; + return false; } diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index 410f842d4..2344240f4 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -54,7 +54,7 @@ struct GLInitParams bool isYFlipped; // check if a frame capture section version is supported - static const uint64_t CurrentVersion = 0x1E; + static const uint64_t CurrentVersion = 0x1F; static bool IsSupportedVersion(uint64_t ver); }; diff --git a/renderdoc/driver/gl/gl_initstate.cpp b/renderdoc/driver/gl/gl_initstate.cpp index 8102053d8..f7d32fec8 100644 --- a/renderdoc/driver/gl/gl_initstate.cpp +++ b/renderdoc/driver/gl/gl_initstate.cpp @@ -108,6 +108,22 @@ void DoSerialise(SerialiserType &ser, PipelineInitialData &el) SERIALISE_MEMBER(programs); } +template +void DoSerialise(SerialiserType &ser, SamplerInitialData &el) +{ + SERIALISE_MEMBER(valid); + SERIALISE_MEMBER(border); + SERIALISE_MEMBER(compareFunc); + SERIALISE_MEMBER(compareMode); + SERIALISE_MEMBER(lodBias); + SERIALISE_MEMBER(minLod); + SERIALISE_MEMBER(maxLod); + SERIALISE_MEMBER(minFilter); + SERIALISE_MEMBER(magFilter); + SERIALISE_MEMBER(maxAniso); + SERIALISE_MEMBER(wrap); +} + template void DoSerialise(SerialiserType &ser, TextureStateInitialData &el) { @@ -287,6 +303,47 @@ void GLResourceManager::ContextPrepare_InitialState(GLResource res) GL.glGetProgramPipelineiv(res.name, eGL_TESS_EVALUATION_SHADER, (GLint *)&data.programs[2].name); GL.glGetProgramPipelineiv(res.name, eGL_COMPUTE_SHADER, (GLint *)&data.programs[5].name); } + else if(res.Namespace == eResSampler) + { + SamplerInitialData &data = initContents.samp; + + RDCASSERT(!data.valid); + data.valid = true; + + GLenum activeTexture = eGL_TEXTURE0; + GL.glGetIntegerv(eGL_ACTIVE_TEXTURE, (GLint *)&activeTexture); + + GL.glActiveTexture(eGL_TEXTURE0); + + GLuint prevsampler = 0; + GL.glGetIntegerv(eGL_SAMPLER_BINDING, (GLint *)&prevsampler); + + { + GL.glGetSamplerParameteriv(res.name, eGL_TEXTURE_COMPARE_FUNC, (GLint *)&data.compareFunc); + GL.glGetSamplerParameteriv(res.name, eGL_TEXTURE_COMPARE_MODE, (GLint *)&data.compareMode); + GL.glGetSamplerParameteriv(res.name, eGL_TEXTURE_MIN_FILTER, (GLint *)&data.minFilter); + GL.glGetSamplerParameteriv(res.name, eGL_TEXTURE_MAG_FILTER, (GLint *)&data.magFilter); + GL.glGetSamplerParameteriv(res.name, eGL_TEXTURE_WRAP_R, (GLint *)&data.wrap[0]); + GL.glGetSamplerParameteriv(res.name, eGL_TEXTURE_WRAP_S, (GLint *)&data.wrap[1]); + GL.glGetSamplerParameteriv(res.name, eGL_TEXTURE_WRAP_T, (GLint *)&data.wrap[2]); + GL.glGetSamplerParameterfv(res.name, eGL_TEXTURE_MIN_LOD, &data.minLod); + GL.glGetSamplerParameterfv(res.name, eGL_TEXTURE_MAX_LOD, &data.maxLod); + if(!IsGLES) + GL.glGetSamplerParameterfv(res.name, eGL_TEXTURE_LOD_BIAS, &data.lodBias); + + // technically border color has been in since GL 1.0, but since this extension was really + // early and dovetails nicely with OES_texture_border_color which added both border colors and + // clamping, we check it. + if(HasExt[ARB_texture_border_clamp]) + GL.glGetSamplerParameterfv(res.name, eGL_TEXTURE_BORDER_COLOR, &data.border[0]); + else + data.border[0] = data.border[1] = data.border[2] = data.border[3] = 1.0f; + } + + GL.glBindSampler(0, prevsampler); + + GL.glActiveTexture(activeTexture); + } else if(res.Namespace == eResFeedback) { FeedbackInitialData &data = initContents.xfb; @@ -500,6 +557,20 @@ bool GLResourceManager::Prepare_InitialState(GLResource res) ContextPrepare_InitialState(res); } } + else if(res.Namespace == eResSampler) + { + // queue initial state fetching if we're not on the right context, see above in FBOs for more + // explanation of this. + ContextPair &ctx = m_Driver->GetCtx(); + if(res.ContextShareGroup != ctx.ctx && res.ContextShareGroup != ctx.shareGroup) + { + m_Driver->QueuePrepareInitialState(res); + } + else + { + ContextPrepare_InitialState(res); + } + } else if(res.Namespace == eResFeedback) { // queue initial state fetching if we're not on the right context, see above in FBOs for more @@ -1088,6 +1159,11 @@ uint32_t GLResourceManager::GetSize_InitialState(ResourceId resid, GLResource re { return sizeof(FramebufferInitialData); } + else if(res.Namespace == eResSampler) + { + // reserve some extra size to account for array count + return sizeof(SamplerInitialData) + 32; + } else if(res.Namespace == eResFeedback) { return sizeof(FeedbackInitialData); @@ -1671,6 +1747,22 @@ bool GLResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceId r SetInitialContents(Id, initContents); } } + else if(Type == eResSampler) + { + SamplerInitialData &SamplerState = initContents.samp; + + SERIALISE_ELEMENT(SamplerState); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + byte *blob = AllocAlignedBuffer(sizeof(SamplerState)); + memcpy(blob, &SamplerState, sizeof(SamplerState)); + + SetInitialContents(Id, initContents); + } + } else if(Type == eResFeedback) { FeedbackInitialData &TransformFeedbackState = initContents.xfb; @@ -2180,6 +2272,43 @@ void GLResourceManager::Apply_InitialState(GLResource live, GLInitialContents in GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, prevread); } } + else if(live.Namespace == eResSampler) + { + const SamplerInitialData &data = initial.samp; + + if(data.valid) + { + GLenum activeTexture = eGL_TEXTURE0; + GL.glGetIntegerv(eGL_ACTIVE_TEXTURE, (GLint *)&activeTexture); + + GL.glActiveTexture(eGL_TEXTURE0); + + GLuint prevsampler = 0; + GL.glGetIntegerv(eGL_SAMPLER_BINDING, (GLint *)&prevsampler); + + { + GL.glSamplerParameteri(live.name, eGL_TEXTURE_COMPARE_FUNC, (GLint)data.compareFunc); + GL.glSamplerParameteri(live.name, eGL_TEXTURE_COMPARE_MODE, (GLint)data.compareMode); + GL.glSamplerParameteri(live.name, eGL_TEXTURE_MIN_FILTER, (GLint)data.minFilter); + GL.glSamplerParameteri(live.name, eGL_TEXTURE_MAG_FILTER, (GLint)data.magFilter); + GL.glSamplerParameteri(live.name, eGL_TEXTURE_WRAP_R, (GLint)data.wrap[0]); + GL.glSamplerParameteri(live.name, eGL_TEXTURE_WRAP_S, (GLint)data.wrap[1]); + GL.glSamplerParameteri(live.name, eGL_TEXTURE_WRAP_T, (GLint)data.wrap[2]); + GL.glSamplerParameterf(live.name, eGL_TEXTURE_MIN_LOD, data.minLod); + GL.glSamplerParameterf(live.name, eGL_TEXTURE_MAX_LOD, data.maxLod); + if(!IsGLES) + GL.glSamplerParameterf(live.name, eGL_TEXTURE_LOD_BIAS, data.lodBias); + + // see fetch in PrepareTextureInitialContents + if(HasExt[ARB_texture_border_clamp]) + GL.glSamplerParameterfv(live.name, eGL_TEXTURE_BORDER_COLOR, &data.border[0]); + } + + GL.glBindSampler(0, prevsampler); + + GL.glActiveTexture(activeTexture); + } + } else if(live.Namespace == eResFeedback) { const FeedbackInitialData &data = initial.xfb; diff --git a/renderdoc/driver/gl/gl_initstate.h b/renderdoc/driver/gl/gl_initstate.h index 83f56807d..64b0c58e4 100644 --- a/renderdoc/driver/gl/gl_initstate.h +++ b/renderdoc/driver/gl/gl_initstate.h @@ -99,6 +99,20 @@ struct FramebufferInitialData DECLARE_REFLECTION_STRUCT(FramebufferInitialData); +struct SamplerInitialData +{ + bool valid; + float border[4]; + GLenum compareFunc, compareMode; + float lodBias; + float minLod, maxLod; + GLenum minFilter, magFilter; + float maxAniso; + GLenum wrap[3]; +}; + +DECLARE_REFLECTION_STRUCT(SamplerInitialData); + struct PipelineInitialData { bool valid; @@ -164,6 +178,7 @@ struct GLInitialContents VAOInitialData vao; FeedbackInitialData xfb; FramebufferInitialData fbo; + SamplerInitialData samp; PipelineInitialData pipe; TextureStateInitialData tex; }; diff --git a/renderdoc/driver/gl/wrappers/gl_sampler_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_sampler_funcs.cpp index eb01b66e3..a72bbb911 100644 --- a/renderdoc/driver/gl/wrappers/gl_sampler_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_sampler_funcs.cpp @@ -273,13 +273,26 @@ void WrappedOpenGL::glSamplerParameteri(GLuint sampler, GLenum pname, GLint para if(IsCaptureMode(m_State)) { + GLResourceRecord *record = GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler)); + + if(m_HighTrafficResources.find(record->GetResourceID()) != m_HighTrafficResources.end() && + IsBackgroundCapturing(m_State)) + return; + USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(gl_CurChunk); Serialise_glSamplerParameteri(ser, sampler, pname, param); if(IsBackgroundCapturing(m_State)) { - GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler))->AddChunk(scope.Get()); + record->AddChunk(scope.Get()); + record->UpdateCount++; + + if(record->UpdateCount > 20) + { + m_HighTrafficResources.insert(record->GetResourceID()); + GetResourceManager()->MarkDirtyResource(record->GetResourceID()); + } } else { @@ -320,13 +333,26 @@ void WrappedOpenGL::glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat pa if(IsCaptureMode(m_State)) { + GLResourceRecord *record = GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler)); + + if(m_HighTrafficResources.find(record->GetResourceID()) != m_HighTrafficResources.end() && + IsBackgroundCapturing(m_State)) + return; + USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(gl_CurChunk); Serialise_glSamplerParameterf(ser, sampler, pname, param); if(IsBackgroundCapturing(m_State)) { - GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler))->AddChunk(scope.Get()); + record->AddChunk(scope.Get()); + record->UpdateCount++; + + if(record->UpdateCount > 20) + { + m_HighTrafficResources.insert(record->GetResourceID()); + GetResourceManager()->MarkDirtyResource(record->GetResourceID()); + } } else { @@ -368,13 +394,26 @@ void WrappedOpenGL::glSamplerParameteriv(GLuint sampler, GLenum pname, const GLi if(IsCaptureMode(m_State)) { + GLResourceRecord *record = GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler)); + + if(m_HighTrafficResources.find(record->GetResourceID()) != m_HighTrafficResources.end() && + IsBackgroundCapturing(m_State)) + return; + USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(gl_CurChunk); Serialise_glSamplerParameteriv(ser, sampler, pname, params); if(IsBackgroundCapturing(m_State)) { - GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler))->AddChunk(scope.Get()); + record->AddChunk(scope.Get()); + record->UpdateCount++; + + if(record->UpdateCount > 20) + { + m_HighTrafficResources.insert(record->GetResourceID()); + GetResourceManager()->MarkDirtyResource(record->GetResourceID()); + } } else { @@ -416,13 +455,26 @@ void WrappedOpenGL::glSamplerParameterfv(GLuint sampler, GLenum pname, const GLf if(IsCaptureMode(m_State)) { + GLResourceRecord *record = GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler)); + + if(m_HighTrafficResources.find(record->GetResourceID()) != m_HighTrafficResources.end() && + IsBackgroundCapturing(m_State)) + return; + USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(gl_CurChunk); Serialise_glSamplerParameterfv(ser, sampler, pname, params); if(IsBackgroundCapturing(m_State)) { - GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler))->AddChunk(scope.Get()); + record->AddChunk(scope.Get()); + record->UpdateCount++; + + if(record->UpdateCount > 20) + { + m_HighTrafficResources.insert(record->GetResourceID()); + GetResourceManager()->MarkDirtyResource(record->GetResourceID()); + } } else { @@ -464,13 +516,26 @@ void WrappedOpenGL::glSamplerParameterIiv(GLuint sampler, GLenum pname, const GL if(IsCaptureMode(m_State)) { + GLResourceRecord *record = GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler)); + + if(m_HighTrafficResources.find(record->GetResourceID()) != m_HighTrafficResources.end() && + IsBackgroundCapturing(m_State)) + return; + USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(gl_CurChunk); Serialise_glSamplerParameterIiv(ser, sampler, pname, params); if(IsBackgroundCapturing(m_State)) { - GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler))->AddChunk(scope.Get()); + record->AddChunk(scope.Get()); + record->UpdateCount++; + + if(record->UpdateCount > 20) + { + m_HighTrafficResources.insert(record->GetResourceID()); + GetResourceManager()->MarkDirtyResource(record->GetResourceID()); + } } else { @@ -512,13 +577,26 @@ void WrappedOpenGL::glSamplerParameterIuiv(GLuint sampler, GLenum pname, const G if(IsCaptureMode(m_State)) { + GLResourceRecord *record = GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler)); + + if(m_HighTrafficResources.find(record->GetResourceID()) != m_HighTrafficResources.end() && + IsBackgroundCapturing(m_State)) + return; + USE_SCRATCH_SERIALISER(); SCOPED_SERIALISE_CHUNK(gl_CurChunk); Serialise_glSamplerParameterIuiv(ser, sampler, pname, params); if(IsBackgroundCapturing(m_State)) { - GetResourceManager()->GetResourceRecord(SamplerRes(GetCtx(), sampler))->AddChunk(scope.Get()); + record->AddChunk(scope.Get()); + record->UpdateCount++; + + if(record->UpdateCount > 20) + { + m_HighTrafficResources.insert(record->GetResourceID()); + GetResourceManager()->MarkDirtyResource(record->GetResourceID()); + } } else {