diff --git a/renderdoc/driver/gl/wrappers/gl_texture_funcs.cpp b/renderdoc/driver/gl/wrappers/gl_texture_funcs.cpp index d861565d1..1dae19b8e 100644 --- a/renderdoc/driver/gl/wrappers/gl_texture_funcs.cpp +++ b/renderdoc/driver/gl/wrappers/gl_texture_funcs.cpp @@ -1365,11 +1365,16 @@ void WrappedOpenGL::glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint s if(IsGLES) { TextureData &srcData = m_Textures[srcrecord->GetResourceID()]; + TextureData &dstData = m_Textures[dstrecord->GetResourceID()]; - // if we have source compressed data to copy (for uncompressed textures, we won't) - if(srcData.compressedData.find(srcLevel) != srcData.compressedData.end()) + bool dstIsCompressed = IsCompressedFormat(dstData.internalFormat); + + // only need dst's compressedData + if(dstIsCompressed) { - TextureData &dstData = m_Textures[dstrecord->GetResourceID()]; + bool srcIsCompressed = IsCompressedFormat(srcData.internalFormat); + GLenum srcFmt = srcIsCompressed ? eGL_NONE : GetBaseFormat(srcData.internalFormat); + GLenum srcType = srcIsCompressed ? eGL_NONE : GetDataType(srcData.internalFormat); GLsizei srcLevelWidth = RDCMAX(1, srcData.width >> srcLevel); GLsizei srcLevelHeight = (srcData.curType != eGL_TEXTURE_1D_ARRAY) @@ -1388,55 +1393,121 @@ void WrappedOpenGL::glCopyImageSubData(GLuint srcName, GLenum srcTarget, GLint s dstData.curType != eGL_TEXTURE_CUBE_MAP_ARRAY) ? RDCMAX(1, dstData.depth >> dstLevel) : dstData.depth; - if(srcX == 0 && srcY == 0 && srcZ == 0 && dstX == 0 && dstY == 0 && dstZ == 0 && - srcLevelWidth == dstLevelWidth && srcLevelHeight == dstLevelHeight && - srcLevelDepth == dstLevelDepth) + + bytebuf srcCd; + // if we have source compressed data to copy + if(srcData.compressedData.find(srcLevel) != srcData.compressedData.end()) { - dstData.compressedData[dstLevel] = srcData.compressedData[srcLevel]; + // TODO: avoid copy + srcCd = srcData.compressedData[srcLevel]; } - else + else if(!srcIsCompressed && + (srcData.curType == eGL_TEXTURE_2D || srcData.curType == eGL_TEXTURE_2D_ARRAY)) { - rdcfixedarray srcBlockSize = GetCompressedBlockSize(srcData.internalFormat); + // try reading back without existing compressedData + RDCASSERT(!srcIsCompressed); + + uint32_t size = + (uint32_t)GetByteSize(srcLevelWidth, srcLevelHeight, srcLevelDepth, srcFmt, srcType); + srcCd.resize(size); + + GLuint prevTex = 0; + GL.glGetIntegerv(srcData.curType == eGL_TEXTURE_2D ? eGL_TEXTURE_BINDING_2D + : eGL_TEXTURE_BINDING_2D_ARRAY, + (GLint *)&prevTex); + + GLenum oldActive = eGL_TEXTURE0; + GL.glGetIntegerv(eGL_ACTIVE_TEXTURE, (GLint *)&oldActive); + GL.glActiveTexture(eGL_TEXTURE0); + + GL.glBindTexture(srcData.curType, srcName); + GL.glGetTexImage(srcData.curType, srcLevel, srcFmt, srcType, srcCd.data()); + + GL.glBindTexture(srcData.curType, prevTex); + GL.glActiveTexture(oldActive); + } + if(!srcCd.isEmpty()) + { + rdcfixedarray srcBlockSize = + srcIsCompressed ? GetCompressedBlockSize(srcData.internalFormat) + : rdcfixedarray{1u, 1u, 1u}; rdcfixedarray dstBlockSize = GetCompressedBlockSize(dstData.internalFormat); - size_t srcSliceSize = GetCompressedByteSize(srcLevelWidth, srcLevelHeight, - srcBlockSize[2], srcData.internalFormat); - size_t dstSliceSize = GetCompressedByteSize(dstLevelWidth, dstLevelHeight, - dstBlockSize[2], dstData.internalFormat); - RDCASSERT(srcWidth % srcBlockSize[0] == 0); - RDCASSERT(srcWidth % dstBlockSize[0] == 0); RDCASSERT(srcHeight % srcBlockSize[1] == 0); - RDCASSERT(srcHeight % dstBlockSize[1] == 0); RDCASSERT(srcDepth % srcBlockSize[2] == 0); - RDCASSERT(srcDepth % dstBlockSize[2] == 0); - for(size_t z = 0; z < (size_t)srcDepth; z += srcBlockSize[2]) + RDCASSERT(srcX % srcBlockSize[0] == 0); + RDCASSERT(srcY % srcBlockSize[1] == 0); + RDCASSERT(srcZ % srcBlockSize[2] == 0); + RDCASSERT(dstX % dstBlockSize[0] == 0); + RDCASSERT(dstY % dstBlockSize[1] == 0); + RDCASSERT(dstZ % dstBlockSize[2] == 0); + + size_t srcSize = + srcIsCompressed + ? GetCompressedByteSize(srcLevelWidth, srcLevelHeight, srcLevelDepth, + srcData.internalFormat) + : GetByteSize(srcLevelWidth, srcLevelHeight, srcLevelDepth, srcFmt, srcType); + size_t dstSize = GetCompressedByteSize(dstLevelWidth, dstLevelHeight, dstLevelDepth, + dstData.internalFormat); + + if(srcX == 0 && srcY == 0 && srcZ == 0 && dstX == 0 && dstY == 0 && dstZ == 0 && + srcLevelWidth == srcWidth && srcLevelHeight == srcHeight && + srcLevelDepth == srcDepth && srcSize == dstSize) { - size_t srcLineSize = - GetCompressedByteSize(srcLevelWidth, (GLsizei)srcBlockSize[1], - (GLsizei)srcBlockSize[2], srcData.internalFormat); - size_t dstLineSize = + // fast path when perform full copy + dstData.compressedData[dstLevel] = srcCd; + } + else + { + bytebuf &dstCd = dstData.compressedData[dstLevel]; + + size_t srcSliceSize = + srcIsCompressed + ? GetCompressedByteSize(srcLevelWidth, srcLevelHeight, srcBlockSize[2], + srcData.internalFormat) + : GetByteSize(srcLevelWidth, srcLevelHeight, srcBlockSize[2], srcFmt, srcType); + size_t dstSliceSize = GetCompressedByteSize(dstLevelWidth, dstLevelHeight, + dstBlockSize[2], dstData.internalFormat); + + size_t srcRowSize = + srcIsCompressed + ? GetCompressedByteSize(srcLevelWidth, (GLsizei)srcBlockSize[1], + (GLsizei)srcBlockSize[2], srcData.internalFormat) + : GetByteSize(srcLevelWidth, srcBlockSize[1], srcBlockSize[2], srcFmt, srcType); + size_t dstRowSize = GetCompressedByteSize(dstLevelWidth, (GLsizei)dstBlockSize[1], (GLsizei)dstBlockSize[2], dstData.internalFormat); - size_t srcOffset = srcSliceSize * ((srcZ + z) / (GLsizei)srcBlockSize[2]) + - srcLineSize * (srcY / (GLsizei)srcBlockSize[1]); - srcOffset += GetCompressedByteSize(srcX, (GLsizei)srcBlockSize[1], - (GLsizei)srcBlockSize[2], srcData.internalFormat); - size_t dstOffset = dstSliceSize * ((dstZ + z) / (GLsizei)dstBlockSize[2]) + - dstLineSize * (dstY / (GLsizei)dstBlockSize[1]); - dstOffset += GetCompressedByteSize(dstX, (GLsizei)dstBlockSize[1], - (GLsizei)dstBlockSize[2], dstData.internalFormat); - size_t blockSize = GetCompressedByteSize( - srcWidth, (GLsizei)dstBlockSize[1], (GLsizei)dstBlockSize[2], srcData.internalFormat); - bytebuf &srcCd = srcData.compressedData[srcLevel]; - bytebuf &dstCd = dstData.compressedData[dstLevel]; - for(size_t y = 0; y < (size_t)srcHeight; y += srcBlockSize[1]) + + size_t srcStartOffset = + srcIsCompressed + ? GetCompressedByteSize(srcX, (GLsizei)srcBlockSize[1], + (GLsizei)srcBlockSize[2], srcData.internalFormat) + : GetByteSize(srcX, srcBlockSize[1], srcBlockSize[2], srcFmt, srcType); + size_t dstStartOffset = GetCompressedByteSize( + dstX, (GLsizei)dstBlockSize[1], (GLsizei)dstBlockSize[2], dstData.internalFormat); + + size_t blockSize = + srcIsCompressed + ? GetCompressedByteSize(srcWidth, (GLsizei)srcBlockSize[1], + (GLsizei)srcBlockSize[2], srcData.internalFormat) + : GetByteSize(srcWidth, srcBlockSize[1], srcBlockSize[2], srcFmt, srcType); + + for(size_t z = 0; z < (size_t)srcDepth; z += srcBlockSize[2]) { - if(dstCd.size() < dstOffset + blockSize || srcCd.size() < srcOffset + blockSize) - break; - memcpy(dstCd.data() + dstOffset, srcCd.data() + srcOffset, blockSize); - srcOffset += srcLineSize; - dstOffset += dstLineSize; + size_t srcOffset = srcSliceSize * ((srcZ + z) / (GLsizei)srcBlockSize[2]) + + srcRowSize * (srcY / (GLsizei)srcBlockSize[1]) + srcStartOffset; + size_t dstOffset = dstSliceSize * ((dstZ + z) / (GLsizei)dstBlockSize[2]) + + dstRowSize * (dstY / (GLsizei)dstBlockSize[1]) + dstStartOffset; + for(size_t y = 0; y < (size_t)srcHeight; y += srcBlockSize[1]) + { + RDCASSERT(srcCd.size() >= srcOffset + blockSize); + if(dstCd.size() < dstOffset + blockSize) + dstCd.resize(dstOffset + blockSize); + memcpy(dstCd.data() + dstOffset, srcCd.data() + srcOffset, blockSize); + srcOffset += srcRowSize; + dstOffset += dstRowSize; + } } } }