Skip to content

Commit

Permalink
complete glCopyImageSubData: when copy from uncompressed texture to…
Browse files Browse the repository at this point in the history
… compressed one, try `glGetTexImage` and copy across different formats
  • Loading branch information
qiankanglai committed Jun 8, 2023
1 parent 96ff474 commit ac4ad05
Showing 1 changed file with 111 additions and 40 deletions.
151 changes: 111 additions & 40 deletions renderdoc/driver/gl/wrappers/gl_texture_funcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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<uint32_t, 3> srcBlockSize = GetCompressedBlockSize(srcData.internalFormat);
rdcfixedarray<uint32_t, 3> dstBlockSize = GetCompressedBlockSize(dstData.internalFormat);
// try reading back without existing compressedData
RDCASSERT(!srcIsCompressed);

uint32_t size =
(uint32_t)GetByteSize(srcLevelWidth, srcLevelHeight, srcLevelDepth, srcFmt, srcType);
srcCd.resize(size);

size_t srcSliceSize = GetCompressedByteSize(srcLevelWidth, srcLevelHeight,
srcBlockSize[2], srcData.internalFormat);
size_t dstSliceSize = GetCompressedByteSize(dstLevelWidth, dstLevelHeight,
dstBlockSize[2], dstData.internalFormat);
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<uint32_t, 3> srcBlockSize =
srcIsCompressed ? GetCompressedBlockSize(srcData.internalFormat)
: rdcfixedarray<uint32_t, 3>{1u, 1u, 1u};
rdcfixedarray<uint32_t, 3> dstBlockSize = GetCompressedBlockSize(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)
{
// fast path when perform full copy
dstData.compressedData[dstLevel] = srcCd;
}
else
{
size_t srcLineSize =
GetCompressedByteSize(srcLevelWidth, (GLsizei)srcBlockSize[1],
(GLsizei)srcBlockSize[2], srcData.internalFormat);
size_t dstLineSize =
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;
}
}
}
}
Expand Down

0 comments on commit ac4ad05

Please sign in to comment.