From e67568706fc83e2136f240ef7f222a46752e251a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Brooke?= Date: Fri, 28 Feb 2025 13:59:03 +0100 Subject: [PATCH] rhi: gl: allow readbacks for all texture formats Texture readbacks other than RGBA8 (e.g., R32UI) are often not supported on OpenGL ES but are fully supported on Desktop OpenGL 3.0+. So, do the same as the float formats: always send the correct glReadPixels command, as it should work on Desktop OpenGL. Use the toGLTextureFormat and textureFormatInfo helpers to reduce code duplication and support new texture formats automagically in the future. Use QByteArray::resizeForOverwrite to avoid unnecessary zero- initialization before glReadPixels writes data. [ChangeLog][RHI] All readback texture formats supported by the OpenGL implementation can now be used with the Qt RHI. Change-Id: I537a5fceff50c2909c16702d66596dfd2fc1119e Reviewed-by: Laszlo Agocs --- src/gui/rhi/qrhigles2.cpp | 46 ++++++++++++--------------------------- 1 file changed, 14 insertions(+), 32 deletions(-) diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 53b2bf9f326..8585556d4f5 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -3654,9 +3654,9 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) // With GLES, GL_RGBA is the only mandated readback format, so stick with it. // (and that's why we return false for the ReadBackAnyTextureFormat feature) if (result->format == QRhiTexture::R8 || result->format == QRhiTexture::RED_OR_ALPHA8) { - result->data.resize(w * h); + result->data.resizeForOverwrite(w * h); QByteArray tmpBuf; - tmpBuf.resize(w * h * 4); + tmpBuf.resizeForOverwrite(w * h * 4); f->glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, tmpBuf.data()); const quint8 *srcBase = reinterpret_cast(tmpBuf.constData()); quint8 *dstBase = reinterpret_cast(result->data.data()); @@ -3671,38 +3671,20 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb) } } } else { - switch (result->format) { - // For floating point formats try it because this can be - // relevant for some use cases; if it works, then fine, if - // not, there's nothing we can do. - case QRhiTexture::RGBA16F: - result->data.resize(w * h * 8); - f->glReadPixels(x, y, w, h, GL_RGBA, GL_HALF_FLOAT, result->data.data()); - break; - case QRhiTexture::R16F: - result->data.resize(w * h * 2); - f->glReadPixels(x, y, w, h, GL_RED, GL_HALF_FLOAT, result->data.data()); - break; - case QRhiTexture::R32F: - result->data.resize(w * h * 4); - f->glReadPixels(x, y, w, h, GL_RED, GL_FLOAT, result->data.data()); - break; - case QRhiTexture::RGBA32F: - result->data.resize(w * h * 16); - f->glReadPixels(x, y, w, h, GL_RGBA, GL_FLOAT, result->data.data()); - break; - case QRhiTexture::RGB10A2: - result->data.resize(w * h * 4); - f->glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, result->data.data()); - break; - default: - result->data.resize(w * h * 4); - f->glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, result->data.data()); - break; - } + // For other formats try it because this can be relevant for some use cases; + // if it works, then fine, if not, there's nothing we can do. + [[maybe_unused]] GLenum glintformat; + [[maybe_unused]] GLenum glsizedintformat; + GLenum glformat; + GLenum gltype; + toGlTextureFormat(result->format, caps, &glintformat, &glsizedintformat, &glformat, &gltype); + quint32 byteSize; + textureFormatInfo(result->format, result->pixelSize, nullptr, &byteSize, nullptr); + result->data.resizeForOverwrite(byteSize); + f->glReadPixels(x, y, w, h, glformat, gltype, result->data.data()); } } else { - result->data.resize(w * h * 4); + result->data.resizeForOverwrite(w * h * 4); result->data.fill('\0'); } if (fbo) {