From a82c7a10d34ec06636d4bbe5bd941fbf71a3a5d4 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 1 Aug 2018 16:08:11 +0100 Subject: [PATCH] Implement proxied MSAA texture contents on OpenGL --- renderdoc/data/glsl/array2ms.comp | 22 +- renderdoc/data/glsl/deptharr2ms.frag | 10 +- renderdoc/data/glsl/depthms2arr.frag | 10 +- renderdoc/data/glsl/ms2array.comp | 4 +- renderdoc/driver/gl/gl_debug.cpp | 14 + renderdoc/driver/gl/gl_msaa_array_conv.cpp | 342 ++++++++++++++++++++- renderdoc/driver/gl/gl_replay.cpp | 60 +++- renderdoc/driver/gl/gl_replay.h | 8 +- 8 files changed, 435 insertions(+), 35 deletions(-) diff --git a/renderdoc/data/glsl/array2ms.comp b/renderdoc/data/glsl/array2ms.comp index e2e4d8a00..b3ce9e056 100644 --- a/renderdoc/data/glsl/array2ms.comp +++ b/renderdoc/data/glsl/array2ms.comp @@ -35,23 +35,23 @@ layout(binding = 2) writeonly uniform uimage2DMSArray dstMS; layout(push_constant) uniform multisamplePush { int numMultiSamples; - int currentSample; - int currentSlice; + int sampleOffset; + int sliceOffset; uint currentStencil; } mscopy; #define numMultiSamples (mscopy.numMultiSamples) -#define currentSample (mscopy.currentSample) -#define currentSlice (mscopy.currentSlice) +#define sampleOffset (mscopy.sampleOffset) +#define sliceOffset (mscopy.sliceOffset) #define currentStencil (mscopy.currentStencil) #else -uniform uvec4 mscopy; +uniform ivec4 mscopy; -#define numMultiSamples (int(mscopy.x)) -#define currentSample (mscopy.y) -#define currentSlice (mscopy.z) +#define numMultiSamples (mscopy.x) +#define sampleOffset (mscopy.y) +#define sliceOffset (mscopy.z) #define currentStencil (mscopy.w) #endif @@ -60,10 +60,10 @@ void main() { uvec3 id = gl_GlobalInvocationID; - int slice = int(id.z / numMultiSamples); - int sampleIdx = int(id.z % numMultiSamples); + int slice = sliceOffset + int(id.z / numMultiSamples); + int sampleIdx = sampleOffset + int(id.z % numMultiSamples); - uvec4 data = texelFetch(srcArray, ivec3(int(id.x), int(id.y), int(id.z)), 0); + uvec4 data = texelFetch(srcArray, ivec3(int(id.x), int(id.y), slice * numMultiSamples + sampleIdx), 0); imageStore(dstMS, ivec3(int(id.x), int(id.y), slice), sampleIdx, data); } diff --git a/renderdoc/data/glsl/deptharr2ms.frag b/renderdoc/data/glsl/deptharr2ms.frag index a9c3f7aa2..32c769b6e 100644 --- a/renderdoc/data/glsl/deptharr2ms.frag +++ b/renderdoc/data/glsl/deptharr2ms.frag @@ -22,6 +22,8 @@ * THE SOFTWARE. ******************************************************************************/ +//#extension_nongles GL_ARB_sample_shading : require + layout(binding = 0) uniform sampler2DArray srcDepthArray; layout(binding = 1) uniform usampler2DArray srcStencilArray; // binding = 2 used as an image in the colour copy compute shaders @@ -43,12 +45,12 @@ layout(push_constant) uniform multisamplePush #else -uniform uvec4 mscopy; +uniform ivec4 mscopy; -#define numMultiSamples (int(mscopy.x)) +#define numMultiSamples (mscopy.x) #define currentSample (mscopy.y) #define currentSlice (mscopy.z) -#define currentStencil (mscopy.w) +#define currentStencil (uint(mscopy.w)) #endif @@ -56,7 +58,7 @@ void main() { ivec3 srcCoord = ivec3(int(gl_FragCoord.x), int(gl_FragCoord.y), currentSlice*numMultiSamples + gl_SampleID); - if(currentStencil < 256) + if(currentStencil < 256u) { uint stencil = texelFetch(srcStencilArray, srcCoord, 0).x; diff --git a/renderdoc/data/glsl/depthms2arr.frag b/renderdoc/data/glsl/depthms2arr.frag index 03828077d..6907338af 100644 --- a/renderdoc/data/glsl/depthms2arr.frag +++ b/renderdoc/data/glsl/depthms2arr.frag @@ -21,6 +21,8 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. ******************************************************************************/ + +//#extension_nongles GL_ARB_sample_shading : require layout(binding = 0) uniform sampler2DMSArray srcDepthMS; layout(binding = 1) uniform usampler2DMSArray srcStencilMS; @@ -43,12 +45,12 @@ layout(push_constant) uniform multisamplePush #else -uniform uvec4 mscopy; +uniform ivec4 mscopy; -#define numMultiSamples (int(mscopy.x)) +#define numMultiSamples (mscopy.x) #define currentSample (mscopy.y) #define currentSlice (mscopy.z) -#define currentStencil (mscopy.w) +#define currentStencil (uint(mscopy.w)) #endif @@ -56,7 +58,7 @@ void main() { ivec3 srcCoord = ivec3(int(gl_FragCoord.x), int(gl_FragCoord.y), currentSlice); - if(currentStencil < 256) + if(currentStencil < 256u) { uint stencil = texelFetch(srcStencilMS, srcCoord, currentSample).x; diff --git a/renderdoc/data/glsl/ms2array.comp b/renderdoc/data/glsl/ms2array.comp index f8cf95178..b67418d80 100644 --- a/renderdoc/data/glsl/ms2array.comp +++ b/renderdoc/data/glsl/ms2array.comp @@ -48,9 +48,9 @@ layout(push_constant) uniform multisamplePush #else -uniform uvec4 mscopy; +uniform ivec4 mscopy; -#define numMultiSamples (int(mscopy.x)) +#define numMultiSamples (mscopy.x) #define currentSample (mscopy.y) #define currentSlice (mscopy.z) #define currentStencil (mscopy.w) diff --git a/renderdoc/driver/gl/gl_debug.cpp b/renderdoc/driver/gl/gl_debug.cpp index 09387c76e..2ee7165b1 100644 --- a/renderdoc/driver/gl/gl_debug.cpp +++ b/renderdoc/driver/gl/gl_debug.cpp @@ -522,6 +522,17 @@ void GLReplay::InitDebugData() "GL_ARB_compute_shader not supported, disabling 2DMS save/load."); } + if(glesShadersAreComplete && HasExt[ARB_texture_multisample]) + { + GenerateGLSLShader(vs, shaderType, "", GetEmbeddedResource(glsl_blit_vert), glslBaseVer); + + GenerateGLSLShader(fs, shaderType, "", GetEmbeddedResource(glsl_depthms2arr_frag), glslBaseVer); + DebugData.DepthMS2Array = CreateShaderProgram(vs, fs); + + GenerateGLSLShader(fs, shaderType, "", GetEmbeddedResource(glsl_deptharr2ms_frag), glslBaseVer); + DebugData.DepthArray2MS = CreateShaderProgram(vs, fs); + } + if(glesShadersAreComplete && HasExt[ARB_compute_shader]) { string defines = @@ -806,6 +817,9 @@ void GLReplay::DeleteDebugData() drv.glDeleteProgram(DebugData.Array2MS); drv.glDeleteProgram(DebugData.MS2Array); + drv.glDeleteProgram(DebugData.DepthArray2MS); + drv.glDeleteProgram(DebugData.DepthMS2Array); + drv.glDeleteBuffers(1, &DebugData.minmaxTileResult); drv.glDeleteBuffers(1, &DebugData.minmaxResult); drv.glDeleteBuffers(1, &DebugData.histogramBuf); diff --git a/renderdoc/driver/gl/gl_msaa_array_conv.cpp b/renderdoc/driver/gl/gl_msaa_array_conv.cpp index 1131cfff2..fc8b97139 100644 --- a/renderdoc/driver/gl/gl_msaa_array_conv.cpp +++ b/renderdoc/driver/gl/gl_msaa_array_conv.cpp @@ -76,6 +76,14 @@ void GLReplay::CopyTex2DMSToArray(GLuint &destArray, GLuint srcMS, GLint width, drv.glTextureStorage3DEXT(destArray, eGL_TEXTURE_2D_ARRAY, 1, intFormat, width, height, arraySize * samples); + if(IsDepthStencilFormat(intFormat)) + { + CopyDepthTex2DMSToArray(destArray, srcMS, width, height, arraySize, samples, intFormat); + return; + } + + GLMarkerRegion renderoverlay("CopyTex2DMSToArray"); + GLRenderState rs; rs.FetchState(m_pDriver); @@ -118,7 +126,7 @@ void GLReplay::CopyTex2DMSToArray(GLuint &destArray, GLuint srcMS, GLint width, GLint loc = drv.glGetUniformLocation(DebugData.MS2Array, "mscopy"); if(loc >= 0) { - drv.glProgramUniform4ui(DebugData.MS2Array, loc, samples, 0, 0, 0); + drv.glProgramUniform4i(DebugData.MS2Array, loc, samples, 0, 0, 0); drv.glDispatchCompute((GLuint)width, (GLuint)height, GLuint(arraySize * samples)); } @@ -128,3 +136,335 @@ void GLReplay::CopyTex2DMSToArray(GLuint &destArray, GLuint srcMS, GLint width, rs.ApplyState(m_pDriver); } + +void GLReplay::CopyDepthTex2DMSToArray(GLuint &destArray, GLuint srcMS, GLint width, GLint height, + GLint arraySize, GLint samples, GLenum intFormat) +{ + GLMarkerRegion renderoverlay("CopyDepthTex2DMSToArray"); + + WrappedOpenGL &drv = *m_pDriver; + + GLRenderState rs; + rs.FetchState(m_pDriver); + + GLuint texs[3]; + drv.glGenTextures(3, texs); + drv.glTextureView(texs[0], eGL_TEXTURE_2D_ARRAY, destArray, intFormat, 0, 1, 0, + arraySize * samples); + drv.glTextureView(texs[1], eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, srcMS, intFormat, 0, 1, 0, arraySize); + drv.glTextureView(texs[2], eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, srcMS, intFormat, 0, 1, 0, arraySize); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_BASE_LEVEL, 0); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MAX_LEVEL, 0); + + GLuint fbo = 0; + drv.glGenFramebuffers(1, &fbo); + drv.glBindFramebuffer(eGL_FRAMEBUFFER, fbo); + drv.glDrawBuffers(0, NULL); + + drv.glUseProgram(DebugData.DepthMS2Array); + drv.glViewport(0, 0, width, height); + + drv.glDisable(eGL_CULL_FACE); + drv.glDisable(eGL_BLEND); + drv.glDisable(eGL_SCISSOR_TEST); + if(!IsGLES) + drv.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); + drv.glEnable(eGL_DEPTH_TEST); + drv.glEnable(eGL_STENCIL_TEST); + drv.glDepthFunc(eGL_ALWAYS); + drv.glDepthMask(GL_TRUE); + drv.glStencilOp(eGL_REPLACE, eGL_REPLACE, eGL_REPLACE); + drv.glStencilMask(0xff); + + uint32_t numStencil = 1; + GLenum attach = eGL_DEPTH_ATTACHMENT; + + switch(GetBaseFormat(intFormat)) + { + case eGL_DEPTH_STENCIL: + numStencil = 256; + attach = eGL_DEPTH_STENCIL_ATTACHMENT; + break; + case eGL_DEPTH: + numStencil = 1; + attach = eGL_DEPTH_ATTACHMENT; + break; + case eGL_STENCIL: + numStencil = 256; + attach = eGL_STENCIL_ATTACHMENT; + break; + default: RDCERR("Unexpected base format! %s", ToStr(intFormat).c_str()); break; + } + + if(attach == eGL_DEPTH_STENCIL_ATTACHMENT || attach == eGL_DEPTH_ATTACHMENT) + { + // 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_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, + eGL_DEPTH_COMPONENT); + } + + if(numStencil > 1) + { + // 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_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, + eGL_STENCIL_INDEX); + } + + GLint loc = drv.glGetUniformLocation(DebugData.DepthMS2Array, "mscopy"); + if(loc >= 0) + { + for(GLint i = 0; i < arraySize * samples; i++) + { + drv.glFramebufferTextureLayer(eGL_DRAW_FRAMEBUFFER, attach, texs[0], 0, i); + + for(uint32_t s = 0; s < numStencil; s++) + { + uint32_t currentStencil = numStencil == 1 ? 1000 : s; + + drv.glStencilFunc(eGL_ALWAYS, int(s), 0xff); + + drv.glProgramUniform4i(DebugData.DepthMS2Array, loc, samples, i % samples, i / samples, + currentStencil); + + drv.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); + } + } + } + + drv.glDeleteFramebuffers(1, &fbo); + drv.glDeleteTextures(3, texs); + + rs.ApplyState(m_pDriver); +} + +void GLReplay::CopyArrayToTex2DMS(GLuint destMS, GLuint srcArray, GLint width, GLint height, + GLint arraySize, GLint samples, GLenum intFormat, + uint32_t selectedSlice) +{ + WrappedOpenGL &drv = *m_pDriver; + + if(!HasExt[ARB_compute_shader]) + { + RDCWARN( + "Can't copy array to multisampled texture for serialisation without ARB_compute_shader."); + return; + } + + if(!HasExt[ARB_texture_view]) + { + RDCWARN("Can't copy array to multisampled texture for serialisation without ARB_texture_view."); + return; + } + + if(!HasExt[ARB_texture_storage]) + { + RDCWARN( + "Can't copy array to multisampled texture for serialisation without ARB_texture_view, and " + "ARB_texture_view requires ARB_texture_storage."); + return; + } + + if(IsDepthStencilFormat(intFormat)) + { + CopyDepthArrayToTex2DMS(destMS, srcArray, width, height, arraySize, samples, intFormat, + selectedSlice); + return; + } + + GLMarkerRegion renderoverlay("CopyArrayToTex2DMS"); + + bool singleSliceMode = (selectedSlice != ~0U); + + GLRenderState rs; + rs.FetchState(m_pDriver); + + GLenum viewClass; + drv.glGetInternalformativ(eGL_TEXTURE_2D_ARRAY, intFormat, eGL_VIEW_COMPATIBILITY_CLASS, + sizeof(GLenum), (GLint *)&viewClass); + + GLenum fmt = eGL_R32UI; + if(viewClass == eGL_VIEW_CLASS_8_BITS) + fmt = eGL_R8UI; + else if(viewClass == eGL_VIEW_CLASS_16_BITS) + fmt = eGL_R16UI; + else if(viewClass == eGL_VIEW_CLASS_24_BITS) + fmt = eGL_RGB8UI; + else if(viewClass == eGL_VIEW_CLASS_32_BITS) + fmt = eGL_RGBA8UI; + else if(viewClass == eGL_VIEW_CLASS_48_BITS) + fmt = eGL_RGB16UI; + else if(viewClass == eGL_VIEW_CLASS_64_BITS) + fmt = eGL_RG32UI; + else if(viewClass == eGL_VIEW_CLASS_96_BITS) + fmt = eGL_RGB32UI; + else if(viewClass == eGL_VIEW_CLASS_128_BITS) + fmt = eGL_RGBA32UI; + + GLuint texs[2]; + drv.glGenTextures(2, texs); + drv.glTextureView(texs[0], eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, destMS, fmt, 0, 1, 0, arraySize); + drv.glTextureView(texs[1], eGL_TEXTURE_2D_ARRAY, srcArray, fmt, 0, 1, 0, arraySize * samples); + + 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_BASE_LEVEL, 0); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MAX_LEVEL, 0); + + drv.glUseProgram(DebugData.Array2MS); + + GLint loc = drv.glGetUniformLocation(DebugData.Array2MS, "mscopy"); + if(loc >= 0) + { + if(singleSliceMode) + { + GLint sampleOffset = (selectedSlice % samples); + GLint sliceOffset = (selectedSlice / samples); + drv.glProgramUniform4i(DebugData.Array2MS, loc, samples, sampleOffset, sliceOffset, 0); + + drv.glDispatchCompute((GLuint)width, (GLuint)height, 1); + } + else + { + drv.glProgramUniform4i(DebugData.Array2MS, loc, samples, 0, 0, 0); + + drv.glDispatchCompute((GLuint)width, (GLuint)height, GLuint(arraySize * samples)); + } + } + drv.glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + + drv.glDeleteTextures(2, texs); + + rs.ApplyState(m_pDriver); +} + +void GLReplay::CopyDepthArrayToTex2DMS(GLuint destMS, GLuint srcArray, GLint width, GLint height, + GLint arraySize, GLint samples, GLenum intFormat, + uint32_t selectedSlice) +{ + GLMarkerRegion renderoverlay("CopyDepthArrayToTex2DMS"); + + bool singleSliceMode = (selectedSlice != ~0U); + + WrappedOpenGL &drv = *m_pDriver; + + GLRenderState rs; + rs.FetchState(m_pDriver); + + GLuint texs[3]; + drv.glGenTextures(3, texs); + drv.glTextureView(texs[0], eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, destMS, intFormat, 0, 1, 0, arraySize); + drv.glTextureView(texs[1], eGL_TEXTURE_2D_ARRAY, srcArray, intFormat, 0, 1, 0, arraySize * samples); + drv.glTextureView(texs[2], eGL_TEXTURE_2D_ARRAY, srcArray, intFormat, 0, 1, 0, arraySize * samples); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_BASE_LEVEL, 0); + drv.glTexParameteri(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, eGL_TEXTURE_MAX_LEVEL, 0); + + GLuint fbo = 0; + drv.glGenFramebuffers(1, &fbo); + drv.glBindFramebuffer(eGL_FRAMEBUFFER, fbo); + drv.glDrawBuffers(0, NULL); + + drv.glUseProgram(DebugData.DepthArray2MS); + drv.glViewport(0, 0, width, height); + + drv.glDisable(eGL_CULL_FACE); + drv.glDisable(eGL_BLEND); + drv.glDisable(eGL_SCISSOR_TEST); + if(!IsGLES) + drv.glPolygonMode(eGL_FRONT_AND_BACK, eGL_FILL); + drv.glEnable(eGL_DEPTH_TEST); + drv.glEnable(eGL_STENCIL_TEST); + drv.glDepthFunc(eGL_ALWAYS); + drv.glDepthMask(GL_TRUE); + drv.glEnable(eGL_SAMPLE_SHADING); + drv.glEnable(eGL_SAMPLE_MASK); + drv.glStencilOp(eGL_REPLACE, eGL_REPLACE, eGL_REPLACE); + drv.glStencilMask(0xff); + + uint32_t numStencil = 1; + GLenum attach = eGL_DEPTH_ATTACHMENT; + + switch(GetBaseFormat(intFormat)) + { + case eGL_DEPTH_STENCIL: + numStencil = 256; + attach = eGL_DEPTH_STENCIL_ATTACHMENT; + break; + case eGL_DEPTH: + numStencil = 1; + attach = eGL_DEPTH_ATTACHMENT; + break; + case eGL_STENCIL: + numStencil = 256; + attach = eGL_STENCIL_ATTACHMENT; + break; + default: RDCERR("Unexpected base format! %s", ToStr(intFormat).c_str()); break; + } + + if(attach == eGL_DEPTH_STENCIL_ATTACHMENT || attach == eGL_DEPTH_ATTACHMENT) + { + // 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_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); + } + + if(numStencil > 1) + { + // 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_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); + } + + GLint loc = drv.glGetUniformLocation(DebugData.DepthArray2MS, "mscopy"); + if(loc >= 0) + { + for(GLint i = 0; i < arraySize; i++) + { + if(singleSliceMode) + { + i = selectedSlice / samples; + drv.glSampleMaski(0, 1U << (selectedSlice % samples)); + } + + drv.glFramebufferTextureLayer(eGL_DRAW_FRAMEBUFFER, attach, texs[0], 0, i); + + for(uint32_t s = 0; s < numStencil; s++) + { + uint32_t currentStencil = numStencil == 1 ? 1000 : s; + + drv.glStencilFunc(eGL_ALWAYS, int(s), 0xff); + + drv.glProgramUniform4i(DebugData.DepthArray2MS, loc, samples, 0, i, currentStencil); + + drv.glDrawArrays(eGL_TRIANGLE_STRIP, 0, 4); + } + + if(singleSliceMode) + break; + } + } + + drv.glDeleteFramebuffers(1, &fbo); + drv.glDeleteTextures(3, texs); + + rs.ApplyState(m_pDriver); +} diff --git a/renderdoc/driver/gl/gl_replay.cpp b/renderdoc/driver/gl/gl_replay.cpp index 8293a23c2..08cb20536 100644 --- a/renderdoc/driver/gl/gl_replay.cpp +++ b/renderdoc/driver/gl/gl_replay.cpp @@ -3031,13 +3031,9 @@ void GLReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t drv.glCompressedTextureSubImage2DEXT(tex, target, (GLint)mip, 0, 0, width, height, fmt, (GLsizei)dataSize, data); } - else if(target == eGL_TEXTURE_2D_MULTISAMPLE) + else if(target == eGL_TEXTURE_2D_MULTISAMPLE || target == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) { - RDCUNIMPLEMENTED("multisampled proxy textures"); - } - else if(target == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) - { - RDCUNIMPLEMENTED("multisampled proxy textures"); + RDCERR("Unexpected compressed MSAA texture!"); } } else @@ -3089,13 +3085,53 @@ void GLReplay::SetProxyTextureData(ResourceId texid, uint32_t arrayIdx, uint32_t drv.glTextureSubImage2DEXT(tex, target, (GLint)mip, 0, 0, width, height, baseformat, datatype, data); } - else if(target == eGL_TEXTURE_2D_MULTISAMPLE) + else if(target == eGL_TEXTURE_2D_MULTISAMPLE || target == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) { - RDCUNIMPLEMENTED("multisampled proxy textures"); - } - else if(target == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) - { - RDCUNIMPLEMENTED("multisampled proxy textures"); + // create a temporary 2D array texture to upload the data to. Must use TexStorage to allow + // texture views inside CopyArrayToTex2DMS + GLuint uploadTex = 0; + drv.glGenTextures(1, &uploadTex); + drv.glBindTexture(eGL_TEXTURE_2D_ARRAY, uploadTex); + drv.glTextureStorage3DEXT(uploadTex, eGL_TEXTURE_2D_ARRAY, 1, texdetails.internalFormat, + width, height, texdetails.samples * RDCMAX(1, texdetails.depth)); + drv.glTexParameteri(eGL_TEXTURE_2D_ARRAY, eGL_TEXTURE_MAX_LEVEL, 0); + + // packed D24S8 is expected the wrong way around from comes in, so we re-swizzle it here + if(texdetails.internalFormat == eGL_DEPTH24_STENCIL8) + { + const uint32_t *srcptr = (const uint32_t *)data; + bytebuf swizzled; + swizzled.resize(dataSize); + uint32_t *dstptr = (uint32_t *)swizzled.data(); + + for(GLsizei y = 0; y < height; y++) + { + for(GLsizei x = 0; x < width; x++) + { + const uint32_t val = *srcptr; + *dstptr = (val << 8) | ((val & 0xff000000) >> 24); + srcptr++; + dstptr++; + } + } + + // upload the data to the given slice + drv.glTextureSubImage3DEXT(uploadTex, eGL_TEXTURE_2D_ARRAY, 0, 0, 0, (GLint)arrayIdx, width, + height, 1, baseformat, datatype, swizzled.data()); + } + else + { + // upload the data to the given slice + drv.glTextureSubImage3DEXT(uploadTex, eGL_TEXTURE_2D_ARRAY, 0, 0, 0, (GLint)arrayIdx, width, + height, 1, baseformat, datatype, data); + } + + // copy this slice into the 2D MSAA texture + CopyArrayToTex2DMS(tex, uploadTex, width, height, 1, texdetails.samples, + texdetails.internalFormat, arrayIdx); + + // delete the temporary texture + drv.glDeleteTextures(1, &uploadTex); } } } diff --git a/renderdoc/driver/gl/gl_replay.h b/renderdoc/driver/gl/gl_replay.h index 9ce8b6fe3..62645a4f7 100644 --- a/renderdoc/driver/gl/gl_replay.h +++ b/renderdoc/driver/gl/gl_replay.h @@ -245,9 +245,14 @@ private: void CreateOverlayProgram(GLuint Program, GLuint Pipeline, GLuint fragShader); void CopyArrayToTex2DMS(GLuint destMS, GLuint srcArray, GLint width, GLint height, - GLint arraySize, GLint samples, GLenum intFormat); + GLint arraySize, GLint samples, GLenum intFormat, uint32_t selectedSlice); void CopyTex2DMSToArray(GLuint &destArray, GLuint srcMS, GLint width, GLint height, GLint arraySize, GLint samples, GLenum intFormat); + void CopyDepthArrayToTex2DMS(GLuint destMS, GLuint srcArray, GLint width, GLint height, + GLint arraySize, GLint samples, GLenum intFormat, + uint32_t selectedSlice); + void CopyDepthTex2DMSToArray(GLuint &destArray, GLuint srcMS, GLint width, GLint height, + GLint arraySize, GLint samples, GLenum intFormat); struct OutputWindow : public GLWindowingData { @@ -317,6 +322,7 @@ private: GLuint pickResultBuf; GLuint MS2Array, Array2MS; + GLuint DepthMS2Array, DepthArray2MS; GLuint pointSampler; GLuint pointNoMipSampler;