diff --git a/renderdoc/driver/gl/gl_common.cpp b/renderdoc/driver/gl/gl_common.cpp index 3fdd95974..78f8c3f19 100644 --- a/renderdoc/driver/gl/gl_common.cpp +++ b/renderdoc/driver/gl/gl_common.cpp @@ -2245,7 +2245,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) ret = eGL_RGBA32F; else if(fmt.compType == CompType::SInt) ret = eGL_RGBA32I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_RGBA32UI; else RDCERR("Unrecognised component type"); @@ -2256,7 +2256,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) ret = eGL_RGBA16F; else if(fmt.compType == CompType::SInt) ret = eGL_RGBA16I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_RGBA16UI; else if(fmt.compType == CompType::SNorm) ret = eGL_RGBA16_SNORM; @@ -2269,7 +2269,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) { if(fmt.compType == CompType::SInt) ret = eGL_RGBA8I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_RGBA8UI; else if(fmt.compType == CompType::SNorm) ret = eGL_RGBA8_SNORM; @@ -2295,7 +2295,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) ret = eGL_RGB32F; else if(fmt.compType == CompType::SInt) ret = eGL_RGB32I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_RGB32UI; else RDCERR("Unrecognised component type"); @@ -2306,7 +2306,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) ret = eGL_RGB16F; else if(fmt.compType == CompType::SInt) ret = eGL_RGB16I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_RGB16UI; else if(fmt.compType == CompType::SNorm) ret = eGL_RGB16_SNORM; @@ -2319,7 +2319,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) { if(fmt.compType == CompType::SInt) ret = eGL_RGB8I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_RGB8UI; else if(fmt.compType == CompType::SNorm) ret = eGL_RGB8_SNORM; @@ -2345,7 +2345,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) ret = eGL_RG32F; else if(fmt.compType == CompType::SInt) ret = eGL_RG32I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_RG32UI; else RDCERR("Unrecognised component type"); @@ -2356,7 +2356,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) ret = eGL_RG16F; else if(fmt.compType == CompType::SInt) ret = eGL_RG16I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_RG16UI; else if(fmt.compType == CompType::SNorm) ret = eGL_RG16_SNORM; @@ -2369,7 +2369,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) { if(fmt.compType == CompType::SInt) ret = eGL_RG8I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_RG8UI; else if(fmt.compType == CompType::SNorm) ret = eGL_RG8_SNORM; @@ -2395,7 +2395,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) ret = eGL_R32F; else if(fmt.compType == CompType::SInt) ret = eGL_R32I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_R32UI; else if(fmt.compType == CompType::Depth) ret = eGL_DEPTH_COMPONENT32F; @@ -2412,7 +2412,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) ret = eGL_R16F; else if(fmt.compType == CompType::SInt) ret = eGL_R16I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_R16UI; else if(fmt.compType == CompType::SNorm) ret = eGL_R16_SNORM; @@ -2427,7 +2427,7 @@ GLenum MakeGLFormat(ResourceFormat fmt) { if(fmt.compType == CompType::SInt) ret = eGL_R8I; - else if(fmt.compType == CompType::UInt) + else if(fmt.compType == CompType::UInt || fmt.compType == CompType::Typeless) ret = eGL_R8UI; else if(fmt.compType == CompType::SNorm) ret = eGL_R8_SNORM; diff --git a/renderdoc/driver/gl/gl_driver.cpp b/renderdoc/driver/gl/gl_driver.cpp index a97ef8212..d2492f6b7 100644 --- a/renderdoc/driver/gl/gl_driver.cpp +++ b/renderdoc/driver/gl/gl_driver.cpp @@ -2715,6 +2715,140 @@ void WrappedOpenGL::QueueResourceRelease(GLResource res) } } +void WrappedOpenGL::CreateTextureImage(GLuint tex, GLenum internalFormat, GLenum internalFormatHint, + GLenum textype, GLint dim, GLint width, GLint height, + GLint depth, GLint samples, int mips) +{ + if(textype == eGL_TEXTURE_BUFFER) + { + return; + } + + GLuint ppb = 0, pub = 0; + + GL.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint *)&ppb); + GL.glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING, (GLint *)&pub); + + GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0); + GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, 0); + + if(textype == eGL_TEXTURE_2D_MULTISAMPLE) + { + GL.glTextureStorage2DMultisampleEXT(tex, textype, samples, internalFormat, width, height, + GL_TRUE); + } + else if(textype == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) + { + GL.glTextureStorage3DMultisampleEXT(tex, textype, samples, internalFormat, width, height, depth, + GL_TRUE); + } + else + { + GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MAX_LEVEL, mips - 1); + GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); + GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); + GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); + GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); + + bool isCompressed = IsCompressedFormat(internalFormat); + + GLenum baseFormat = eGL_RGBA; + GLenum dataType = internalFormatHint != eGL_NONE ? internalFormatHint : eGL_UNSIGNED_BYTE; + if(!isCompressed) + { + baseFormat = GetBaseFormat(internalFormat); + + if(internalFormatHint == eGL_NONE) + dataType = GetDataType(internalFormat); + } + + GLenum targets[] = { + 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, + }; + + int count = ARRAY_COUNT(targets); + + if(textype != eGL_TEXTURE_CUBE_MAP) + { + targets[0] = textype; + count = 1; + } + + GLsizei w = (GLsizei)width; + GLsizei h = (GLsizei)height; + GLsizei d = (GLsizei)depth; + + for(int m = 0; m < mips; m++) + { + for(int t = 0; t < count; t++) + { + if(isCompressed) + { + GLsizei compSize = (GLsizei)GetCompressedByteSize(w, h, d, internalFormat); + + std::vector dummy; + dummy.resize(compSize); + + if(dim == 1) + GL.glCompressedTextureImage1DEXT(tex, targets[t], m, internalFormat, w, 0, compSize, + &dummy[0]); + else if(dim == 2) + GL.glCompressedTextureImage2DEXT(tex, targets[t], m, internalFormat, w, h, 0, compSize, + &dummy[0]); + else if(dim == 3) + GL.glCompressedTextureImage3DEXT(tex, targets[t], m, internalFormat, w, h, d, 0, + compSize, &dummy[0]); + } + else + { + if(dim == 1) + GL.glTextureImage1DEXT(tex, targets[t], m, internalFormat, w, 0, baseFormat, dataType, + NULL); + else if(dim == 2) + GL.glTextureImage2DEXT(tex, targets[t], m, internalFormat, w, h, 0, baseFormat, + dataType, NULL); + else if(dim == 3) + GL.glTextureImage3DEXT(tex, targets[t], m, internalFormat, w, h, d, 0, baseFormat, + dataType, NULL); + } + } + + w = RDCMAX(1, w >> 1); + if(textype != eGL_TEXTURE_1D_ARRAY) + h = RDCMAX(1, h >> 1); + if(textype != eGL_TEXTURE_2D_ARRAY && textype != eGL_TEXTURE_CUBE_MAP_ARRAY) + d = RDCMAX(1, d >> 1); + } + } + + if(IsCaptureMode(m_State)) + { + // register this texture and set up its texture details, so it's available for emulation + // readback. + GLResource res = TextureRes(GetCtx(), tex); + ResourceId id = GetResourceManager()->RegisterResource(res); + + WrappedOpenGL::TextureData &details = m_Textures[id]; + + details.resource = res; + details.curType = textype; + details.dimension = dim; + details.emulated = details.view = false; + details.width = width; + details.height = height; + details.depth = depth; + details.samples = samples; + details.creationFlags = TextureCategory::NoFlags; + details.internalFormat = internalFormat; + details.mipsValid = (1 << mips) - 1; + } + + GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, ppb); + GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, pub); +} + void WrappedOpenGL::ReleaseResource(GLResource res) { switch(res.Namespace) diff --git a/renderdoc/driver/gl/gl_driver.h b/renderdoc/driver/gl/gl_driver.h index dd7242521..b774e7198 100644 --- a/renderdoc/driver/gl/gl_driver.h +++ b/renderdoc/driver/gl/gl_driver.h @@ -552,6 +552,10 @@ public: ContextPair &GetCtx(); GLResourceRecord *GetContextRecord(); + void CreateTextureImage(GLuint tex, GLenum internalFormat, GLenum internalFormatHint, + GLenum textype, GLint dim, GLint width, GLint height, GLint depth, + GLint samples, int mips); + void PushInternalShader() { m_InternalShader++; } void PopInternalShader() { m_InternalShader--; } bool IsInternalShader() { return m_InternalShader > 0; } diff --git a/renderdoc/driver/gl/gl_initstate.cpp b/renderdoc/driver/gl/gl_initstate.cpp index c3eb2ed76..5f5b82c32 100644 --- a/renderdoc/driver/gl/gl_initstate.cpp +++ b/renderdoc/driver/gl/gl_initstate.cpp @@ -567,141 +567,6 @@ bool GLResourceManager::Prepare_InitialState(GLResource res) return true; } -void GLResourceManager::CreateTextureImage(GLuint tex, GLenum internalFormat, - GLenum internalFormatHint, GLenum textype, GLint dim, - GLint width, GLint height, GLint depth, GLint samples, - int mips) -{ - if(textype == eGL_TEXTURE_BUFFER) - { - return; - } - - GLuint ppb = 0, pub = 0; - - GL.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint *)&ppb); - GL.glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING, (GLint *)&pub); - - GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0); - GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, 0); - - if(textype == eGL_TEXTURE_2D_MULTISAMPLE) - { - GL.glTextureStorage2DMultisampleEXT(tex, textype, samples, internalFormat, width, height, - GL_TRUE); - } - else if(textype == eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) - { - GL.glTextureStorage3DMultisampleEXT(tex, textype, samples, internalFormat, width, height, depth, - GL_TRUE); - } - else - { - GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MAX_LEVEL, mips - 1); - GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MIN_FILTER, eGL_NEAREST); - GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_MAG_FILTER, eGL_NEAREST); - GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_WRAP_S, eGL_CLAMP_TO_EDGE); - GL.glTextureParameteriEXT(tex, textype, eGL_TEXTURE_WRAP_T, eGL_CLAMP_TO_EDGE); - - bool isCompressed = IsCompressedFormat(internalFormat); - - GLenum baseFormat = eGL_RGBA; - GLenum dataType = internalFormatHint != eGL_NONE ? internalFormatHint : eGL_UNSIGNED_BYTE; - if(!isCompressed) - { - baseFormat = GetBaseFormat(internalFormat); - - if(internalFormatHint == eGL_NONE) - dataType = GetDataType(internalFormat); - } - - GLenum targets[] = { - 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, - }; - - int count = ARRAY_COUNT(targets); - - if(textype != eGL_TEXTURE_CUBE_MAP) - { - targets[0] = textype; - count = 1; - } - - GLsizei w = (GLsizei)width; - GLsizei h = (GLsizei)height; - GLsizei d = (GLsizei)depth; - - for(int m = 0; m < mips; m++) - { - for(int t = 0; t < count; t++) - { - if(isCompressed) - { - GLsizei compSize = (GLsizei)GetCompressedByteSize(w, h, d, internalFormat); - - std::vector dummy; - dummy.resize(compSize); - - if(dim == 1) - GL.glCompressedTextureImage1DEXT(tex, targets[t], m, internalFormat, w, 0, compSize, - &dummy[0]); - else if(dim == 2) - GL.glCompressedTextureImage2DEXT(tex, targets[t], m, internalFormat, w, h, 0, compSize, - &dummy[0]); - else if(dim == 3) - GL.glCompressedTextureImage3DEXT(tex, targets[t], m, internalFormat, w, h, d, 0, - compSize, &dummy[0]); - } - else - { - if(dim == 1) - GL.glTextureImage1DEXT(tex, targets[t], m, internalFormat, w, 0, baseFormat, dataType, - NULL); - else if(dim == 2) - GL.glTextureImage2DEXT(tex, targets[t], m, internalFormat, w, h, 0, baseFormat, - dataType, NULL); - else if(dim == 3) - GL.glTextureImage3DEXT(tex, targets[t], m, internalFormat, w, h, d, 0, baseFormat, - dataType, NULL); - } - } - - w = RDCMAX(1, w >> 1); - if(textype != eGL_TEXTURE_1D_ARRAY) - h = RDCMAX(1, h >> 1); - if(textype != eGL_TEXTURE_2D_ARRAY && textype != eGL_TEXTURE_CUBE_MAP_ARRAY) - d = RDCMAX(1, d >> 1); - } - } - - if(IsCaptureMode(m_State)) - { - // register this texture and set up its texture details, so it's available for emulation - // readback. - GLResource res = TextureRes(m_Driver->GetCtx(), tex); - ResourceId id = RegisterResource(res); - - WrappedOpenGL::TextureData &details = m_Driver->m_Textures[id]; - - details.resource = res; - details.curType = textype; - details.dimension = dim; - details.emulated = details.view = false; - details.width = width; - details.height = height; - details.depth = depth; - details.samples = samples; - details.creationFlags = TextureCategory::NoFlags; - details.internalFormat = internalFormat; - details.mipsValid = (1 << mips) - 1; - } - - GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, ppb); - GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, pub); -} - void GLResourceManager::PrepareTextureInitialContents(ResourceId liveid, ResourceId origid, GLResource res) { @@ -840,9 +705,9 @@ void GLResourceManager::PrepareTextureInitialContents(ResourceId liveid, Resourc mips = 1; // create texture of identical format/size to store initial contents - CreateTextureImage(tex, details.internalFormat, details.internalFormatHint, details.curType, - details.dimension, details.width, details.height, details.depth, - details.samples, mips); + m_Driver->CreateTextureImage(tex, details.internalFormat, details.internalFormatHint, + details.curType, details.dimension, details.width, + details.height, details.depth, details.samples, mips); // we need to set maxlevel appropriately for number of mips to force the texture to be // complete. @@ -1576,10 +1441,10 @@ bool GLResourceManager::Serialise_InitialState(SerialiserType &ser, ResourceId i GL.glGenTextures(1, &tex); GL.glBindTexture(TextureState.type, tex); - CreateTextureImage(tex, TextureState.internalformat, details.internalFormatHint, - TextureState.type, TextureState.dim, TextureState.width, - TextureState.height, TextureState.depth, TextureState.samples, - TextureState.mips); + m_Driver->CreateTextureImage(tex, TextureState.internalformat, details.internalFormatHint, + TextureState.type, TextureState.dim, TextureState.width, + TextureState.height, TextureState.depth, + TextureState.samples, TextureState.mips); } else if(ser.IsWriting()) { diff --git a/renderdoc/driver/gl/gl_manager.h b/renderdoc/driver/gl/gl_manager.h index 832bb8f24..c963cbe3a 100644 --- a/renderdoc/driver/gl/gl_manager.h +++ b/renderdoc/driver/gl/gl_manager.h @@ -285,9 +285,6 @@ private: bool Prepare_InitialState(GLResource res); uint64_t GetSize_InitialState(ResourceId resid, const GLInitialContents &initial); - void CreateTextureImage(GLuint tex, GLenum internalFormat, GLenum internalFormatHint, - GLenum textype, GLint dim, GLint width, GLint height, GLint depth, - GLint samples, int mips); void PrepareTextureInitialContents(ResourceId liveid, ResourceId origid, GLResource res); void Create_InitialState(ResourceId id, GLResource live, bool hasData); diff --git a/renderdoc/driver/gl/gl_rendertexture.cpp b/renderdoc/driver/gl/gl_rendertexture.cpp index 11679fecd..4bbee8ca1 100644 --- a/renderdoc/driver/gl/gl_rendertexture.cpp +++ b/renderdoc/driver/gl/gl_rendertexture.cpp @@ -113,11 +113,195 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) MakeCurrentReplayContext(m_DebugCtx); + uint32_t numMips = m_CachedTextures[cfg.resourceId].mips; + + GLuint castTexture = 0; + + GLenum displayFormat = texDetails.internalFormat; + + if(cfg.typeCast != CompType::Typeless && + cfg.typeCast != MakeResourceFormat(target, displayFormat).compType) + { + displayFormat = GetViewCastedFormat(displayFormat, cfg.typeCast); + + // if the format didn't change we can't re-interpret this format anyway + if(displayFormat != texDetails.internalFormat) + { + GLMarkerRegion region("Casting texture for view"); + + drv.glGenTextures(1, &castTexture); + drv.glActiveTexture(eGL_TEXTURE0); + drv.glBindTexture(target, castTexture); + + // can't use texture views because the underlying image isn't immutable because we don't + // want to rely on texture storage. We also can't rely on texture views, meaning we need a + // fallback path ANYWAY, so might as well always use it. Yayyy opengl... + drv.CreateTextureImage(castTexture, displayFormat, eGL_NONE, target, texDetails.dimension, + texDetails.width, texDetails.height, texDetails.depth, + texDetails.samples, (int)numMips); + + bool isCompressed = IsCompressedFormat(displayFormat); + + GLint values[4] = {}; + float fvalues[4] = {}; + + // ensure source texture is complete + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_MAX_LEVEL, values); + + int prevMaxLevel = values[0]; + + int maxlevel = numMips - 1; + GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_MAX_LEVEL, (GLint *)&maxlevel); + + // copy state + + if(!texDetails.emulated && (HasExt[ARB_texture_swizzle] || HasExt[EXT_texture_swizzle])) + { + GetTextureSwizzle(texname, target, (GLenum *)values); + SetTextureSwizzle(castTexture, target, (GLenum *)values); + } + + if((target == eGL_TEXTURE_CUBE_MAP || target == eGL_TEXTURE_CUBE_MAP_ARRAY) && + HasExt[ARB_seamless_cubemap_per_texture]) + { + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_CUBE_MAP_SEAMLESS, values); + GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_CUBE_MAP_SEAMLESS, values); + } + + if(target != eGL_TEXTURE_2D_MULTISAMPLE && target != eGL_TEXTURE_2D_MULTISAMPLE_ARRAY) + { + if(HasExt[EXT_texture_sRGB_decode]) + { + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_SRGB_DECODE_EXT, values); + GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_SRGB_DECODE_EXT, values); + } + + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_COMPARE_FUNC, values); + GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_COMPARE_FUNC, values); + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_COMPARE_MODE, values); + GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_COMPARE_MODE, values); + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_MIN_FILTER, values); + GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_MIN_FILTER, values); + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_MAG_FILTER, values); + GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_MAG_FILTER, values); + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_R, values); + GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_WRAP_R, values); + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_S, values); + GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_WRAP_S, values); + GL.glGetTextureParameterivEXT(texname, target, eGL_TEXTURE_WRAP_T, values); + GL.glTextureParameterivEXT(castTexture, target, eGL_TEXTURE_WRAP_T, values); + + if(HasExt[ARB_texture_border_clamp]) + { + GL.glGetTextureParameterfvEXT(texname, target, eGL_TEXTURE_BORDER_COLOR, fvalues); + GL.glTextureParameterfvEXT(castTexture, target, eGL_TEXTURE_BORDER_COLOR, fvalues); + } + + if(!IsGLES) + { + GL.glGetTextureParameterfvEXT(texname, target, eGL_TEXTURE_LOD_BIAS, fvalues); + GL.glTextureParameterfvEXT(castTexture, target, eGL_TEXTURE_LOD_BIAS, fvalues); + } + + if(target != eGL_TEXTURE_RECTANGLE) + { + GL.glGetTextureParameterfvEXT(texname, target, eGL_TEXTURE_MIN_LOD, fvalues); + GL.glTextureParameterfvEXT(castTexture, target, eGL_TEXTURE_MIN_LOD, fvalues); + GL.glGetTextureParameterfvEXT(texname, target, eGL_TEXTURE_MAX_LOD, fvalues); + GL.glTextureParameterfvEXT(castTexture, target, eGL_TEXTURE_MAX_LOD, fvalues); + } + } + + // copy mip data + for(uint32_t i = 0; i < numMips; i++) + { + int w = RDCMAX(texDetails.width >> i, 1); + int h = RDCMAX(texDetails.height >> i, 1); + int d = RDCMAX(texDetails.depth >> i, 1); + + if(target == eGL_TEXTURE_CUBE_MAP) + d *= 6; + else if(target == eGL_TEXTURE_CUBE_MAP_ARRAY || target == eGL_TEXTURE_2D_ARRAY) + d = texDetails.depth; + + // glCopyImageSubData treats 1D arrays sanely - with depth as array size - but at odds + // with the rest of the API. + if(target == eGL_TEXTURE_1D_ARRAY) + { + h = 1; + d = texDetails.height; + } + + if((isCompressed && VendorCheck[VendorCheck_AMD_copy_compressed_tinymips] && (w < 4 || h < 4)) || + (isCompressed && VendorCheck[VendorCheck_AMD_copy_compressed_cubemaps] && + texDetails.curType == eGL_TEXTURE_CUBE_MAP) || + (isCompressed && IsGLES)) + { + GLenum targets[] = { + 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, + }; + + int count = ARRAY_COUNT(targets); + + if(target != eGL_TEXTURE_CUBE_MAP) + { + targets[0] = target; + count = 1; + } + + for(int trg = 0; trg < count; trg++) + { + size_t size = GetCompressedByteSize(w, h, d, displayFormat); + + if(target == eGL_TEXTURE_CUBE_MAP) + size /= 6; + + byte *buf = new byte[size]; + + if(IsGLES) + { + texDetails.GetCompressedImageDataGLES(i, targets[trg], size, buf); + } + else + { + // read to CPU + GL.glGetCompressedTextureImageEXT(texname, targets[trg], i, buf); + } + + // write to GPU + if(texDetails.dimension == 1) + GL.glCompressedTextureSubImage1DEXT(castTexture, targets[trg], i, 0, w, displayFormat, + (GLsizei)size, buf); + else if(texDetails.dimension == 2) + GL.glCompressedTextureSubImage2DEXT(castTexture, targets[trg], i, 0, 0, w, h, + displayFormat, (GLsizei)size, buf); + else if(texDetails.dimension == 3) + GL.glCompressedTextureSubImage3DEXT(castTexture, targets[trg], i, 0, 0, 0, w, h, d, + displayFormat, (GLsizei)size, buf); + + delete[] buf; + } + } + else + { + GL.glCopyImageSubData(texname, target, i, 0, 0, 0, castTexture, target, i, 0, 0, 0, w, h, + d); + } + } + + GL.glTextureParameterivEXT(texname, target, eGL_TEXTURE_MAX_LEVEL, (GLint *)&prevMaxLevel); + + texname = castTexture; + } + } + RDCGLenum dsTexMode = eGL_NONE; - if(IsDepthStencilFormat(texDetails.internalFormat)) + if(IsDepthStencilFormat(displayFormat)) { // stencil-only, make sure we display it as such - if(texDetails.internalFormat == eGL_STENCIL_INDEX8) + if(displayFormat == eGL_STENCIL_INDEX8) { cfg.red = false; cfg.green = true; @@ -126,7 +310,7 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) } // depth-only, make sure we display it as such - if(GetBaseFormat(texDetails.internalFormat) == eGL_DEPTH_COMPONENT) + if(GetBaseFormat(displayFormat) == eGL_DEPTH_COMPONENT) { cfg.red = true; cfg.green = false; @@ -141,7 +325,7 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) // Stencil texture sampling is not normalized in OpenGL intIdx = 1; float rangeScale = 1.0f; - switch(texDetails.internalFormat) + switch(displayFormat) { case eGL_STENCIL_INDEX1: rangeScale = 1.0f; break; case eGL_STENCIL_INDEX4: rangeScale = 16.0f; break; @@ -162,17 +346,15 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) } else { - if(IsUIntFormat(texDetails.internalFormat)) + if(IsUIntFormat(displayFormat)) intIdx = 1; - if(IsSIntFormat(texDetails.internalFormat)) + if(IsSIntFormat(displayFormat)) intIdx = 2; } drv.glBindProgramPipeline(0); drv.glUseProgram(DebugData.texDisplayProg[intIdx]); - uint32_t numMips = m_CachedTextures[cfg.resourceId].mips; - GLuint customProgram = 0; if(cfg.customShaderId != ResourceId() && @@ -393,7 +575,7 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) if(cfg.overlay == DebugOverlay::Clipping) ubo->OutputDisplayFormat |= TEXDISPLAY_CLIPPING; - if(!IsSRGBFormat(texDetails.internalFormat) && cfg.linearDisplayAsGamma) + if(!IsSRGBFormat(displayFormat) && cfg.linearDisplayAsGamma) ubo->OutputDisplayFormat |= TEXDISPLAY_GAMMA_CURVE; ubo->RawOutput = cfg.rawOutput ? 1 : 0; @@ -490,5 +672,8 @@ bool GLReplay::RenderTextureInternal(TextureDisplay cfg, int flags) if(dsTexMode != eGL_NONE && HasExt[ARB_stencil_texturing]) drv.glTexParameteri(target, eGL_DEPTH_STENCIL_TEXTURE_MODE, origDSTexMode); + if(castTexture) + drv.glDeleteTextures(1, &castTexture); + return true; } diff --git a/renderdoc/driver/gl/gl_resources.cpp b/renderdoc/driver/gl/gl_resources.cpp index 667c425ea..9ed4f0764 100644 --- a/renderdoc/driver/gl/gl_resources.cpp +++ b/renderdoc/driver/gl/gl_resources.cpp @@ -1048,6 +1048,267 @@ bool IsSRGBFormat(GLenum internalFormat) return false; } +GLenum GetViewCastedFormat(GLenum internalFormat, CompType typeCast) +{ + switch(internalFormat) + { + case eGL_RGBA: + case eGL_RGBA8: + case eGL_RGBA8_SNORM: + case eGL_RGBA8UI: + case eGL_RGBA8I: + case eGL_SRGB_ALPHA: + case eGL_SRGB8_ALPHA8: + switch(typeCast) + { + case CompType::UNorm: internalFormat = eGL_RGBA8; break; + case CompType::SNorm: internalFormat = eGL_RGBA8_SNORM; break; + case CompType::UInt: internalFormat = eGL_RGBA8UI; break; + case CompType::SInt: internalFormat = eGL_RGBA8I; break; + case CompType::UNormSRGB: internalFormat = eGL_SRGB8_ALPHA8; break; + default: break; + } + break; + + case eGL_RGB: + case eGL_RGB8: + case eGL_RGB8_SNORM: + case eGL_RGB8UI: + case eGL_RGB8I: + case eGL_SRGB: + case eGL_SRGB8: + switch(typeCast) + { + case CompType::UNorm: internalFormat = eGL_RGB8; break; + case CompType::SNorm: internalFormat = eGL_RGB8_SNORM; break; + case CompType::UInt: internalFormat = eGL_RGB8UI; break; + case CompType::SInt: internalFormat = eGL_RGB8I; break; + case CompType::UNormSRGB: internalFormat = eGL_SRGB8; break; + default: break; + } + break; + + case eGL_RG: + case eGL_RG8: + case eGL_RG8_SNORM: + case eGL_RG8UI: + case eGL_RG8I: + switch(typeCast) + { + case CompType::UNorm: internalFormat = eGL_RG8; break; + case CompType::SNorm: internalFormat = eGL_RG8_SNORM; break; + case CompType::UInt: internalFormat = eGL_RG8UI; break; + case CompType::SInt: internalFormat = eGL_RG8I; break; + case CompType::UNormSRGB: internalFormat = eGL_SRG8_EXT; break; + default: break; + } + break; + + case eGL_RED: + case eGL_R8: + case eGL_R8_SNORM: + case eGL_R8UI: + case eGL_R8I: + switch(typeCast) + { + case CompType::UNorm: internalFormat = eGL_R8; break; + case CompType::SNorm: internalFormat = eGL_R8_SNORM; break; + case CompType::UInt: internalFormat = eGL_R8UI; break; + case CompType::SInt: internalFormat = eGL_R8I; break; + case CompType::UNormSRGB: internalFormat = eGL_SR8_EXT; break; + default: break; + } + break; + + case eGL_RGBA16F: + case eGL_RGBA16: + case eGL_RGBA16_SNORM: + case eGL_RGBA16UI: + case eGL_RGBA16I: + switch(typeCast) + { + case CompType::Float: internalFormat = eGL_RGBA16F; break; + case CompType::UNorm: internalFormat = eGL_RGBA16; break; + case CompType::SNorm: internalFormat = eGL_RGBA16_SNORM; break; + case CompType::UInt: internalFormat = eGL_RGBA16UI; break; + case CompType::SInt: internalFormat = eGL_RGBA16I; break; + default: break; + } + break; + + case eGL_RGB16F: + case eGL_RGB16: + case eGL_RGB16_SNORM: + case eGL_RGB16UI: + case eGL_RGB16I: + switch(typeCast) + { + case CompType::Float: internalFormat = eGL_RGB16F; break; + case CompType::UNorm: internalFormat = eGL_RGB16; break; + case CompType::SNorm: internalFormat = eGL_RGB16_SNORM; break; + case CompType::UInt: internalFormat = eGL_RGB16UI; break; + case CompType::SInt: internalFormat = eGL_RGB16I; break; + default: break; + } + break; + + case eGL_RG16F: + case eGL_RG16: + case eGL_RG16_SNORM: + case eGL_RG16UI: + case eGL_RG16I: + switch(typeCast) + { + case CompType::Float: internalFormat = eGL_RG16F; break; + case CompType::UNorm: internalFormat = eGL_RG16; break; + case CompType::SNorm: internalFormat = eGL_RG16_SNORM; break; + case CompType::UInt: internalFormat = eGL_RG16UI; break; + case CompType::SInt: internalFormat = eGL_RG16I; break; + default: break; + } + break; + + case eGL_R16F: + case eGL_R16: + case eGL_R16_SNORM: + case eGL_R16UI: + case eGL_R16I: + switch(typeCast) + { + case CompType::Float: internalFormat = eGL_R16F; break; + case CompType::UNorm: internalFormat = eGL_R16; break; + case CompType::SNorm: internalFormat = eGL_R16_SNORM; break; + case CompType::UInt: internalFormat = eGL_R16UI; break; + case CompType::SInt: internalFormat = eGL_R16I; break; + default: break; + } + break; + + case eGL_RGBA32F: + case eGL_RGBA32UI: + case eGL_RGBA32I: + switch(typeCast) + { + case CompType::Float: internalFormat = eGL_RGBA32F; break; + case CompType::UInt: internalFormat = eGL_RGBA32UI; break; + case CompType::SInt: internalFormat = eGL_RGBA32I; break; + default: break; + } + break; + + case eGL_RGB32F: + case eGL_RGB32UI: + case eGL_RGB32I: + switch(typeCast) + { + case CompType::Float: internalFormat = eGL_RGB32F; break; + case CompType::UInt: internalFormat = eGL_RGB32UI; break; + case CompType::SInt: internalFormat = eGL_RGB32I; break; + default: break; + } + break; + + case eGL_RG32F: + case eGL_RG32UI: + case eGL_RG32I: + switch(typeCast) + { + case CompType::Float: internalFormat = eGL_RG32F; break; + case CompType::UInt: internalFormat = eGL_RG32UI; break; + case CompType::SInt: internalFormat = eGL_RG32I; break; + default: break; + } + break; + + case eGL_R32F: + case eGL_R32UI: + case eGL_R32I: + switch(typeCast) + { + case CompType::Float: internalFormat = eGL_R32F; break; + case CompType::UInt: internalFormat = eGL_R32UI; break; + case CompType::SInt: internalFormat = eGL_R32I; break; + default: break; + } + break; + + case eGL_RGB10_A2UI: + case eGL_RGB10_A2: + switch(typeCast) + { + case CompType::Float: + case CompType::UNorm: internalFormat = eGL_RGB10_A2; break; + case CompType::UInt: internalFormat = eGL_RGB10_A2UI; break; + default: break; + } + break; + + case eGL_COMPRESSED_RGB_S3TC_DXT1_EXT: + case eGL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + internalFormat = (typeCast == CompType::UNormSRGB) ? eGL_COMPRESSED_SRGB_S3TC_DXT1_EXT + : eGL_COMPRESSED_RGB_S3TC_DXT1_EXT; + break; + + case eGL_COMPRESSED_RGBA_S3TC_DXT1_EXT: + case eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: + internalFormat = (typeCast == CompType::UNormSRGB) ? eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT + : eGL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + + case eGL_COMPRESSED_RGBA_S3TC_DXT3_EXT: + case eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: + internalFormat = (typeCast == CompType::UNormSRGB) ? eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT + : eGL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + + case eGL_COMPRESSED_RGBA_S3TC_DXT5_EXT: + case eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: + internalFormat = (typeCast == CompType::UNormSRGB) ? eGL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT + : eGL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + + case eGL_COMPRESSED_RED_RGTC1: + case eGL_COMPRESSED_SIGNED_RED_RGTC1: + internalFormat = (typeCast == CompType::SNorm) ? eGL_COMPRESSED_SIGNED_RED_RGTC1 + : eGL_COMPRESSED_RED_RGTC1; + break; + + case eGL_COMPRESSED_RG_RGTC2: + case eGL_COMPRESSED_SIGNED_RG_RGTC2: + internalFormat = + (typeCast == CompType::SNorm) ? eGL_COMPRESSED_SIGNED_RG_RGTC2 : eGL_COMPRESSED_RG_RGTC2; + break; + + case eGL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB: + case eGL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB: + internalFormat = (typeCast == CompType::SNorm) ? eGL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB + : eGL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB; + break; + + case eGL_COMPRESSED_RGBA_BPTC_UNORM_ARB: + case eGL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB: + internalFormat = (typeCast == CompType::UNormSRGB) ? eGL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB + : eGL_COMPRESSED_RGBA_BPTC_UNORM_ARB; + break; + + case eGL_COMPRESSED_SIGNED_R11_EAC: + case eGL_COMPRESSED_R11_EAC: + internalFormat = + (typeCast == CompType::SNorm) ? eGL_COMPRESSED_SIGNED_R11_EAC : eGL_COMPRESSED_R11_EAC; + break; + + case eGL_COMPRESSED_SIGNED_RG11_EAC: + case eGL_COMPRESSED_RG11_EAC: + internalFormat = + (typeCast == CompType::SNorm) ? eGL_COMPRESSED_SIGNED_RG11_EAC : eGL_COMPRESSED_RG11_EAC; + break; + + default: break; + } + + return internalFormat; +} + GLenum TextureBinding(GLenum target) { switch(target) diff --git a/renderdoc/driver/gl/gl_resources.h b/renderdoc/driver/gl/gl_resources.h index 51a7e9c8d..73e26913c 100644 --- a/renderdoc/driver/gl/gl_resources.h +++ b/renderdoc/driver/gl/gl_resources.h @@ -52,6 +52,8 @@ bool IsUIntFormat(GLenum internalFormat); bool IsSIntFormat(GLenum internalFormat); bool IsSRGBFormat(GLenum internalFormat); +GLenum GetViewCastedFormat(GLenum internalFormat, CompType typeCast); + bool IsCubeFace(GLenum target); GLint CubeTargetIndex(GLenum face); GLenum TextureBinding(GLenum target);