OpenGL readback: Move any format convert to when the data is read.

Eliminates a copy, and will fit better with delayed readbacks.
This commit is contained in:
Henrik Rydgård 2023-02-06 11:25:41 +01:00
parent d502198aa3
commit b4aa120298
2 changed files with 23 additions and 25 deletions

View file

@ -88,9 +88,6 @@ void GLQueueRunner::DestroyDeviceObjects() {
delete[] readbackBuffer_;
readbackBuffer_ = nullptr;
readbackBufferSize_ = 0;
delete[] tempBuffer_;
tempBuffer_ = nullptr;
tempBufferSize_ = 0;
CHECK_GL_ERROR_IF_DEBUG();
}
@ -1481,26 +1478,24 @@ void GLQueueRunner::PerformReadback(const GLRStep &pass) {
CHECK_GL_ERROR_IF_DEBUG();
// Always read back in 8888 format for the color aspect.
GLuint internalFormat = GL_RGBA;
GLuint format = GL_RGBA;
GLuint type = GL_UNSIGNED_BYTE;
int srcAlignment = 4;
int dstAlignment = (int)DataFormatSizeInBytes(pass.readback.dstFormat);
#ifndef USING_GLES2
if (pass.readback.aspectMask & GL_DEPTH_BUFFER_BIT) {
internalFormat = GL_DEPTH_COMPONENT;
format = GL_DEPTH_COMPONENT;
type = GL_FLOAT;
srcAlignment = 4;
} else if (pass.readback.aspectMask & GL_STENCIL_BUFFER_BIT) {
internalFormat = GL_STENCIL_INDEX;
format = GL_STENCIL_INDEX;
type = GL_UNSIGNED_BYTE;
srcAlignment = 1;
}
#endif
readbackAspectMask_ = pass.readback.aspectMask;
int pixelStride = pass.readback.srcRect.w;
// Apply the correct alignment.
glPixelStorei(GL_PACK_ALIGNMENT, srcAlignment);
@ -1511,31 +1506,20 @@ void GLQueueRunner::PerformReadback(const GLRStep &pass) {
GLRect2D rect = pass.readback.srcRect;
bool convert = internalFormat == GL_RGBA && pass.readback.dstFormat != DataFormat::R8G8B8A8_UNORM;
int tempSize = srcAlignment * rect.w * rect.h;
int readbackSize = dstAlignment * rect.w * rect.h;
if (convert && tempSize > tempBufferSize_) {
delete[] tempBuffer_;
tempBuffer_ = new uint8_t[tempSize];
tempBufferSize_ = tempSize;
}
int readbackSize = srcAlignment * rect.w * rect.h;
if (readbackSize > readbackBufferSize_) {
delete[] readbackBuffer_;
readbackBuffer_ = new uint8_t[readbackSize];
readbackBufferSize_ = readbackSize;
}
glReadPixels(rect.x, rect.y, rect.w, rect.h, format, type, convert ? tempBuffer_ : readbackBuffer_);
glReadPixels(rect.x, rect.y, rect.w, rect.h, format, type, readbackBuffer_);
#ifdef DEBUG_READ_PIXELS
LogReadPixelsError(glGetError());
#endif
if (!gl_extensions.IsGLES || gl_extensions.GLES3) {
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
}
if (convert && tempBuffer_ && readbackBuffer_) {
ConvertFromRGBA8888(readbackBuffer_, tempBuffer_, pixelStride, pixelStride, rect.w, rect.h, pass.readback.dstFormat);
}
CHECK_GL_ERROR_IF_DEBUG();
}
@ -1624,8 +1608,24 @@ void GLQueueRunner::CopyFromReadbackBuffer(GLRFramebuffer *framebuffer, int widt
// Something went wrong during the read and no readback buffer was allocated, probably.
return;
}
for (int y = 0; y < height; y++) {
memcpy(pixels + y * pixelStride * bpp, readbackBuffer_ + y * width * bpp, width * bpp);
// Always read back in 8888 format for the color aspect.
GLuint internalFormat = GL_RGBA;
#ifndef USING_GLES2
if (readbackAspectMask_ & GL_DEPTH_BUFFER_BIT) {
internalFormat = GL_DEPTH_COMPONENT;
} else if (readbackAspectMask_ & GL_STENCIL_BUFFER_BIT) {
internalFormat = GL_STENCIL_INDEX;
}
#endif
bool convert = internalFormat == GL_RGBA && destFormat != Draw::DataFormat::R8G8B8A8_UNORM;
if (convert) {
ConvertFromRGBA8888(pixels, readbackBuffer_, pixelStride, pixelStride, width, height, destFormat);
} else {
for (int y = 0; y < height; y++) {
memcpy(pixels + y * pixelStride * bpp, readbackBuffer_ + y * width * bpp, width * bpp);
}
}
}

View file

@ -420,9 +420,7 @@ private:
// We size it generously.
uint8_t *readbackBuffer_ = nullptr;
int readbackBufferSize_ = 0;
// Temp buffer for color conversion
uint8_t *tempBuffer_ = nullptr;
int tempBufferSize_ = 0;
uint32_t readbackAspectMask_ = 0;
float maxAnisotropyLevel_ = 0.0f;