diff --git a/docs/behind_scenes/opengl_support.rst b/docs/behind_scenes/opengl_support.rst index 8ad634ead..71629cec1 100644 --- a/docs/behind_scenes/opengl_support.rst +++ b/docs/behind_scenes/opengl_support.rst @@ -23,7 +23,6 @@ RenderDoc assumes a certain minimum feature set on replay. On desktop this means * GL_ARB_program_interface_query * GL_ARB_separate_shader_objects -* GL_ARB_sampler_objects These extensions should not require newer hardware than the base 3.2 context, but they might need an updated driver to be listed as available. Also note that this is the *minimum* required extension set to replay, some analysis features will be disabled unless you have more capable hardware features such as GL_ARB_shader_image_load_store, GL_ARB_compute_shader and GL_ARB_gpu_shader5. diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index d2f418a56..57a598980 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -122,11 +122,6 @@ bool CheckReplayContext() // Possible to remove this with self-compiled SPIR-V for reflection - see above. Likewise // convenience for our own pipelines when replacing single shaders or such. REQUIRE_EXTENSION(ARB_separate_shader_objects); - // adds sampler objects so we can swap sampling behaviour when sampling from the capture's - // textures - // Possible to remove by manually pushing and popping all of the sampler state that we're - // interested in on each texture instead of binding sampler objects. - REQUIRE_EXTENSION(ARB_sampler_objects); if(!missingExts.empty()) { diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 31a018ff9..5bd67eda7 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -615,24 +615,6 @@ void GLReplay::InitDebugData() RenderDoc::Inst().SetProgress(LoadProgress::DebugManagerInit, 0.4f); - drv.glGenSamplers(1, &DebugData.linearSampler); - drv.glSamplerParameteri(DebugData.linearSampler, eGL_TEXTURE_MIN_FILTER, eGL_LINEAR); - drv.glSamplerParameteri(DebugData.linearSampler, eGL_TEXTURE_MAG_FILTER, eGL_LINEAR); - drv.glSamplerParameteri(DebugData.linearSampler, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); - drv.glSamplerParameteri(DebugData.linearSampler, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); - - drv.glGenSamplers(1, &DebugData.pointSampler); - drv.glSamplerParameteri(DebugData.pointSampler, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST_MIPMAP_NEAREST); - drv.glSamplerParameteri(DebugData.pointSampler, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); - drv.glSamplerParameteri(DebugData.pointSampler, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); - drv.glSamplerParameteri(DebugData.pointSampler, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); - - drv.glGenSamplers(1, &DebugData.pointNoMipSampler); - drv.glSamplerParameteri(DebugData.pointNoMipSampler, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); - drv.glSamplerParameteri(DebugData.pointNoMipSampler, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); - drv.glSamplerParameteri(DebugData.pointNoMipSampler, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); - drv.glSamplerParameteri(DebugData.pointNoMipSampler, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); - drv.glGenBuffers(ARRAY_COUNT(DebugData.UBOs), DebugData.UBOs); for(size_t i = 0; i < ARRAY_COUNT(DebugData.UBOs); i++) { @@ -1095,9 +1077,6 @@ void GLReplay::DeleteDebugData() } drv.glDeleteProgram(DebugData.trisizeProg); - drv.glDeleteSamplers(1, &DebugData.linearSampler); - drv.glDeleteSamplers(1, &DebugData.pointSampler); - drv.glDeleteSamplers(1, &DebugData.pointNoMipSampler); drv.glDeleteBuffers(ARRAY_COUNT(DebugData.UBOs), DebugData.UBOs); drv.glDeleteFramebuffers(1, &DebugData.pickPixelFBO); drv.glDeleteTextures(1, &DebugData.pickPixelTex); @@ -1152,6 +1131,64 @@ void GLReplay::DeleteDebugData() drv.glDeleteBuffers(1, &DebugData.triHighlightBuffer); } +GLReplay::TextureSamplerState GLReplay::SetSamplerParams(GLenum target, GLuint texname, + TextureSamplerMode mode) +{ + TextureSamplerState ret; + + if(target == eGL_TEXTURE_BUFFER || target == eGL_TEXTURE_2D_MULTISAMPLE || + target == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) + return ret; + + // fetch previous texture sampler settings + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_MIN_FILTER, (GLint *)&ret.minFilter); + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_MAG_FILTER, (GLint *)&ret.magFilter); + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_S, (GLint *)&ret.wrapS); + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_T, (GLint *)&ret.wrapT); + + // always want to clamp + GLenum param = eGL_CLAMP_TO_EDGE; + GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_S, (GLint *)¶m); + GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_T, (GLint *)¶m); + + // depending on the mode, set min/mag filter + GLenum minFilter = eGL_NEAREST; + GLenum magFilter = eGL_NEAREST; + + switch(mode) + { + case TextureSamplerMode::Point: + minFilter = eGL_NEAREST_MIPMAP_NEAREST; + magFilter = eGL_NEAREST; + break; + case TextureSamplerMode::PointNoMip: + minFilter = eGL_NEAREST; + magFilter = eGL_NEAREST; + break; + case TextureSamplerMode::Linear: + minFilter = eGL_LINEAR; + magFilter = eGL_LINEAR; + break; + } + + GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_MIN_FILTER, (GLint *)&minFilter); + GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_MAG_FILTER, (GLint *)&magFilter); + + return ret; +} + +void GLReplay::RestoreSamplerParams(GLenum target, GLuint texname, TextureSamplerState state) +{ + if(target == eGL_TEXTURE_BUFFER || target == eGL_TEXTURE_2D_MULTISAMPLE || + target == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) + return; + + GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_S, (GLint *)&state.wrapS); + GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_T, (GLint *)&state.wrapT); + GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_MIN_FILTER, (GLint *)&state.minFilter); + GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_MAG_FILTER, (GLint *)&state.magFilter); +} + bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uint32_t sample, CompType typeHint, float *minval, float *maxval) { @@ -1337,10 +1374,13 @@ bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uin GL.glActiveTexture((RDCGLenum)(eGL_TEXTURE0 + texSlot)); GL.glBindTexture(target, texname); + + TextureSamplerMode mode = TextureSamplerMode::Point; + if(texSlot == RESTYPE_TEXRECT || texSlot == RESTYPE_TEXBUFFER) - GL.glBindSampler(texSlot, DebugData.pointNoMipSampler); - else - GL.glBindSampler(texSlot, DebugData.pointSampler); + mode = TextureSamplerMode::PointNoMip; + + TextureSamplerState prevSampState = SetSamplerParams(target, texname, mode); GLint origDSTexMode = eGL_DEPTH_COMPONENT; if(dsTexMode != eGL_NONE && HasExt[ARB_stencil_texturing]) @@ -1405,6 +1445,8 @@ bool GLReplay::GetMinMax(ResourceId texid, uint32_t sliceFace, uint32_t mip, uin if(maxlevel[0] >= 0) GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_MAX_LEVEL, maxlevel); + RestoreSamplerParams(target, texname, prevSampState); + minval[0] = minmax[0].x; minval[1] = minmax[0].y; minval[2] = minmax[0].z; @@ -1613,10 +1655,13 @@ bool GLReplay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, GL.glActiveTexture((RDCGLenum)(eGL_TEXTURE0 + texSlot)); GL.glBindTexture(target, texname); + + TextureSamplerMode mode = TextureSamplerMode::Point; + if(texSlot == RESTYPE_TEXRECT || texSlot == RESTYPE_TEXBUFFER) - GL.glBindSampler(texSlot, DebugData.pointNoMipSampler); - else - GL.glBindSampler(texSlot, DebugData.pointSampler); + mode = TextureSamplerMode::PointNoMip; + + TextureSamplerState prevSampState = SetSamplerParams(target, texname, mode); GLint origDSTexMode = eGL_DEPTH_COMPONENT; if(dsTexMode != eGL_NONE && HasExt[ARB_stencil_texturing]) @@ -1679,6 +1724,8 @@ bool GLReplay::GetHistogram(ResourceId texid, uint32_t sliceFace, uint32_t mip, if(maxlevel[0] >= 0) GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_MAX_LEVEL, maxlevel); + RestoreSamplerParams(target, texname, prevSampState); + if(dsTexMode != eGL_NONE && HasExt[ARB_stencil_texturing]) GL.glTexParameteri(target, eGL_DEPTH_STENCIL_TEXTURE_MODE, origDSTexMode); diff --git a/renderdoc/driver/gl/gl_msaa_array_conv.cpp b/renderdoc/driver/gl/gl_msaa_array_conv.cpp index b2e971740..9eeb3ff19 100644 --- a/renderdoc/driver/gl/gl_msaa_array_conv.cpp +++ b/renderdoc/driver/gl/gl_msaa_array_conv.cpp @@ -117,7 +117,10 @@ void GLReplay::CopyTex2DMSToArray(GLuint &destArray, GLuint srcMS, GLint width, drv.glBindImageTexture(2, texs[0], 0, GL_TRUE, 0, eGL_WRITE_ONLY, fmt); drv.glActiveTexture(eGL_TEXTURE0); drv.glBindTexture(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, texs[1]); - drv.glBindSampler(0, DebugData.pointNoMipSampler); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_BASE_LEVEL, 0); drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MAX_LEVEL, 0); @@ -201,7 +204,10 @@ void GLReplay::CopyDepthTex2DMSToArray(GLuint &destArray, GLuint srcMS, GLint wi // depth aspect drv.glActiveTexture(eGL_TEXTURE0); drv.glBindTexture(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, texs[1]); - drv.glBindSampler(0, DebugData.pointNoMipSampler); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_BASE_LEVEL, 0); drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MAX_LEVEL, 0); drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_DEPTH_STENCIL_TEXTURE_MODE, @@ -213,7 +219,10 @@ void GLReplay::CopyDepthTex2DMSToArray(GLuint &destArray, GLuint srcMS, GLint wi // stencil aspect drv.glActiveTexture(eGL_TEXTURE1); drv.glBindTexture(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, texs[2]); - drv.glBindSampler(1, DebugData.pointNoMipSampler); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_BASE_LEVEL, 0); drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MAX_LEVEL, 0); drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_DEPTH_STENCIL_TEXTURE_MODE, @@ -318,7 +327,10 @@ void GLReplay::CopyArrayToTex2DMS(GLuint destMS, GLuint srcArray, GLint width, G drv.glBindImageTexture(2, texs[0], 0, GL_TRUE, 0, eGL_WRITE_ONLY, fmt); drv.glActiveTexture(eGL_TEXTURE0); drv.glBindTexture(eGL_TEXTURE_2D_ARRAY, texs[1]); - drv.glBindSampler(0, DebugData.pointNoMipSampler); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_BASE_LEVEL, 0); drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MAX_LEVEL, 0); @@ -417,7 +429,10 @@ void GLReplay::CopyDepthArrayToTex2DMS(GLuint destMS, GLuint srcArray, GLint wid // depth aspect drv.glActiveTexture(eGL_TEXTURE0); drv.glBindTexture(eGL_TEXTURE_2D_ARRAY, texs[1]); - drv.glBindSampler(0, DebugData.pointNoMipSampler); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_BASE_LEVEL, 0); drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MAX_LEVEL, 0); drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_DEPTH_STENCIL_TEXTURE_MODE, eGL_DEPTH_COMPONENT); @@ -428,7 +443,10 @@ void GLReplay::CopyDepthArrayToTex2DMS(GLuint destMS, GLuint srcArray, GLint wid // stencil aspect drv.glActiveTexture(eGL_TEXTURE1); drv.glBindTexture(eGL_TEXTURE_2D_ARRAY, texs[2]); - drv.glBindSampler(1, DebugData.pointNoMipSampler); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_BASE_LEVEL, 0); drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MAX_LEVEL, 0); drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_DEPTH_STENCIL_TEXTURE_MODE, eGL_STENCIL_INDEX); diff --git a/renderdoc/driver/gl/gl_rendertexture.cpp b/renderdoc/driver/gl/gl_rendertexture.cpp index e7ef2b591..368fce79e 100644 --- a/renderdoc/driver/gl/gl_rendertexture.cpp +++ b/renderdoc/driver/gl/gl_rendertexture.cpp @@ -279,19 +279,23 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) maxlevel[0] = -1; } + TextureSamplerMode mode = TextureSamplerMode::Point; + if(cfg.mip == 0 && cfg.scale < 1.0f && dsTexMode == eGL_NONE && resType != RESTYPE_TEXBUFFER && resType != RESTYPE_TEXRECT) { - drv.glBindSampler(resType, DebugData.linearSampler); + mode = TextureSamplerMode::Linear; } else { if(resType == RESTYPE_TEXRECT || resType == RESTYPE_TEX2DMS || resType == RESTYPE_TEXBUFFER) - drv.glBindSampler(resType, DebugData.pointNoMipSampler); + mode = TextureSamplerMode::PointNoMip; else - drv.glBindSampler(resType, DebugData.pointSampler); + mode = TextureSamplerMode::Point; } + TextureSamplerState prevSampState = SetSamplerParams(target, texname, mode); + GLint tex_x = texDetails.width, tex_y = texDetails.height, tex_z = texDetails.depth; drv.glBindBufferBase(eGL_UNIFORM_BUFFER, 0, DebugData.UBOs[0]); @@ -452,7 +456,7 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) if(maxlevel[0] >= 0) drv.glTextureParameterivEXT(texname, target, eGL_TEXTURE_MAX_LEVEL, maxlevel); - drv.glBindSampler(0, 0); + RestoreSamplerParams(target, texname, prevSampState); if(customProgram) { diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 0a1c3dd07..466fac482 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -292,6 +292,25 @@ private: int width = 1, height = 1; }; + enum class TextureSamplerMode + { + Point, + PointNoMip, + Linear, + }; + + struct TextureSamplerState + { + GLenum minFilter = eGL_NEAREST; + GLenum magFilter = eGL_NEAREST; + GLenum wrapS = eGL_CLAMP_TO_EDGE; + GLenum wrapT = eGL_CLAMP_TO_EDGE; + }; + + // sets the desired parameters, and returns the previous ones ready to restore + TextureSamplerState SetSamplerParams(GLenum target, GLuint texname, TextureSamplerMode mode); + void RestoreSamplerParams(GLenum target, GLuint texname, TextureSamplerState state); + // any objects that are shared between contexts, we just initialise // once struct DebugRenderData @@ -327,10 +346,6 @@ private: GLuint MS2Array, Array2MS; GLuint DepthMS2Array, DepthArray2MS; - GLuint pointSampler; - GLuint pointNoMipSampler; - GLuint linearSampler; - GLuint genericUBO; GLuint checkerProg;