Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

complete glCopyImageSubData #2955

Merged
merged 3 commits into from
Jun 15, 2023
Merged

Conversation

qiankanglai
Copy link
Contributor

Description

When serializing glCopyImageSubData, we could try glGetTexImage when srcData.compressedData doesn't exist.
Also I reformat here to make code more readable.

TODO: need find a elegant way to skip copying here

srcCd = srcData.compressedData[srcLevel];

Copy link
Owner

@baldurk baldurk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks good though I've left a couple of small comments.

I must admit I'm shocked that any Android driver actually successfully implements a feature like this, but it seems to be working for you since I think you are the one who implemented this compressed copy in this function in the first place!

{
dstData.compressedData[dstLevel] = srcData.compressedData[srcLevel];
// TODO: avoid copy
srcCd = srcData.compressedData[srcLevel];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can change srcCd to be a pointer like bytebuf *srcCd, and have it either point to this compressed data, or to a new temporary variable bytebuf tempReadback or similar.

}
else
else if(!srcIsCompressed &&
(srcData.curType == eGL_TEXTURE_2D || srcData.curType == eGL_TEXTURE_2D_ARRAY))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth adding an error message if the source texture is not 2D or 2D array? it could be a cubemap or 3D texture as well, copying a single slice.

Copy link
Contributor Author

@qiankanglai qiankanglai Jun 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit unsure about supporting 3D or Cubemap here (just remove line 1405 and use TextureBinding), which is not used in the game.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that's totally fine to not support it, I just mean to add an error message for that case. It looks like at the moment the call will be silently dropped.

GL.glActiveTexture(eGL_TEXTURE0);

GL.glBindTexture(srcData.curType, srcName);
GL.glGetTexImage(srcData.curType, srcLevel, srcFmt, srcType, srcCd.data());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you also need to push & pop the pixel pack state here too, to ensure tightly packed data that doesn't go to a buffer.


if(srcX == 0 && srcY == 0 && srcZ == 0 && dstX == 0 && dstY == 0 && dstZ == 0 &&
srcLevelWidth == srcWidth && srcLevelHeight == srcHeight &&
srcLevelDepth == srcDepth && srcSize == dstSize)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this check is accurate anymore, since unless I'm mistaken the dimensions of the uncompressed texture will be off by a factor of the block size from the compressed texture - each uncompressed 1x1 texel maps to a compressed 4x4 block.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could be like 1x1 RGBA32UI -> 4x4 ETC2, which is in fact the case we use (virtual texture like and runtime gpu compression). So I just leave this fast code path when perform full texture copy of the same size.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeh that's what I mean. In fact I didn't notice that the check had been changed, and it's now comparing srcLevelWidth to srcWidth which doesn't seem correct. I think the check for a full copy should be something like comparing src dimensions divided by src block size to dst dimensions divided by dst block size. Then it does the same kind of check as before (where it just compared src to dst) but with handling for compressed textures only being on one side.

Copy link
Contributor Author

@qiankanglai qiankanglai Jun 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fast path is ensured under these situations:

  • copy full srcTex (srcX == 0 && srcY == 0 && srcZ == 0 and srcLevelWidth == srcWidth && srcLevelHeight == srcHeight && srcLevelDepth == srcDepth
  • copy full dstTex (dstX == 0 && dstY == 0 && dstZ == 0 and srcSize == dstSize)

src dimensions divided by src block size to dst dimensions divided by dst block size

I didn't check way because it is implied by srcSize == dstSize (Please correct me if I misunderstand it)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is correct, but I had to think quite carefully to be sure there wasn't a scenario where this would break. Normally the size could be same for different dimensions, but together with the constraint that the whole source texture is copied there's no valid way to copy to anything but the same dimension.

As I say though, I did have to think through it carefully as it's not trivially obvious to me and my first instinct was that it could still break in some cases. For that reason I would still rather do an explicit check that the source dimension is equal to the destination dimension after normalising for blocks/texels. This is not a high performance case so there is no need to minimise the number of comparisons, and keeping the same "src == dest" logic as before is clearer to read.

@qiankanglai
Copy link
Contributor Author

qiankanglai commented Jun 9, 2023

Just a screenshot of capture&replay on my device(ETC2 on XiaoMi13). We rely on this API to copy into compressed formats, and tests show many devices nowdays are able to work in this way.

screenshot-20230609-184125

@qiankanglai qiankanglai requested a review from baldurk June 11, 2023 14:42
GLuint packbuf = 0;
GL.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint *)&packbuf);
GLint align = 1;
GL.glGetIntegerv(eGL_PACK_ALIGNMENT, &align);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a helper PixelPackState which does this push/pop for you, as well as a helper ResetPixelPackState, since alignment is not the only pack value that could interfere here.

@qiankanglai qiankanglai requested a review from baldurk June 15, 2023 15:41
@baldurk baldurk merged commit 367d55d into baldurk:v1.x Jun 15, 2023
9 of 16 checks passed
@qiankanglai qiankanglai deleted the glCopyImageSubData branch June 16, 2023 01:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants