summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntti Määttä <antti.maatta@qt.io>2016-08-26 09:51:19 +0300
committerAntti Määttä <antti.maatta@qt.io>2016-10-21 11:10:07 +0000
commitaaf18f4ad42ad63d309e04559b4e304fd1472638 (patch)
treea9c1c00c302038f5c5145b6ad5de1874d3210e7f
parent4428b5d8699ad3feb55dc49411beb86b79773ef8 (diff)
Implement readFramebuffer
Add readFramebuffer function to GraphicsContext to avoid using imported qt_gl_read_framebuffer function. Change-Id: If620960fc828e46152915234c57c432d57c6e989 Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io> Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp177
-rw-r--r--src/render/graphicshelpers/graphicscontext_p.h2
2 files changed, 174 insertions, 5 deletions
diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp
index d694012fc..281488b47 100644
--- a/src/render/graphicshelpers/graphicscontext.cpp
+++ b/src/render/graphicshelpers/graphicscontext.cpp
@@ -80,8 +80,6 @@
QT_BEGIN_NAMESPACE
-extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-
namespace {
QOpenGLShader::ShaderType shaderType(Qt3DRender::QShaderProgram::ShaderType type)
@@ -203,6 +201,31 @@ void GraphicsContext::initialize()
qCDebug(Backend) << "VAO support = " << m_supportsVAO;
}
+void GraphicsContext::resolveRenderTargetFormat()
+{
+ const QSurfaceFormat format = m_gl->format();
+ const uint a = format.alphaBufferSize();
+ const uint r = format.redBufferSize();
+ const uint g = format.greenBufferSize();
+ const uint b = format.blueBufferSize();
+
+#define RGBA_BITS(r,g,b,a) (r | (g << 6) | (b << 12) | (a << 18))
+
+ const uint bits = RGBA_BITS(r,g,b,a);
+ switch (bits) {
+ case RGBA_BITS(8,8,8,8):
+ m_renderTargetFormat = QAbstractTexture::RGBA8U;
+ break;
+ case RGBA_BITS(8,8,8,0):
+ m_renderTargetFormat = QAbstractTexture::RGB8U;
+ break;
+ case RGBA_BITS(5,6,5,0):
+ m_renderTargetFormat = QAbstractTexture::R5G6B5;
+ break;
+ }
+#undef RGBA_BITS
+}
+
bool GraphicsContext::beginDrawing(QSurface *surface)
{
Q_ASSERT(surface);
@@ -224,6 +247,9 @@ bool GraphicsContext::beginDrawing(QSurface *surface)
if (m_ownCurrent && !makeCurrent(m_surface))
return false;
+ // TODO: cache surface format somewhere rather than doing this every time render surface changes
+ resolveRenderTargetFormat();
+
// Sets or Create the correct m_glHelper
// for the current surface
activateGLHelper();
@@ -528,8 +554,11 @@ void GraphicsContext::activateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId,
const auto attachments_ = attachments.attachments();
for (const Attachment &attachment : attachments_) {
Texture *rTex = textureManager->lookupResource(attachment.m_textureUuid);
- if (rTex != nullptr)
+ if (rTex != nullptr) {
needsResize |= rTex->isTextureReset();
+ if (attachment.m_point == QRenderTargetOutput::Color0)
+ m_renderTargetFormat = rTex->format();
+ }
}
if (needsResize) {
m_glHelper->bindFrameBufferObject(fboId);
@@ -1540,10 +1569,148 @@ GLint GraphicsContext::glDataTypeFromAttributeDataType(QAttribute::VertexBaseTyp
return GL_FLOAT;
}
+static void copyGLFramebufferDataToImage(QImage &img, const uchar *srcData, uint stride, uint width, uint height, QAbstractTexture::TextureFormat format)
+{
+ switch (format) {
+ case QAbstractTexture::RGBA32F:
+ {
+ uchar *srcScanline = (uchar *)srcData + stride * (height - 1);
+ for (uint i = 0; i < height; ++i) {
+ uchar *dstScanline = img.scanLine(i);
+ float *pSrc = (float*)srcScanline;
+ for (uint j = 0; j < width; j++) {
+ *dstScanline++ = (uchar)(255.0f * (pSrc[4*j+2] / (1.0f + pSrc[4*j+2])));
+ *dstScanline++ = (uchar)(255.0f * (pSrc[4*j+1] / (1.0f + pSrc[4*j+1])));
+ *dstScanline++ = (uchar)(255.0f * (pSrc[4*j+0] / (1.0f + pSrc[4*j+0])));
+ *dstScanline++ = (uchar)(255.0f * qBound(0.0f, pSrc[4*j+3], 1.0f));
+ }
+ srcScanline -= stride;
+ }
+ } break;
+ default:
+ {
+ uchar* srcScanline = (uchar *)srcData + stride * (height - 1);
+ for (uint i = 0; i < height; ++i) {
+ memcpy(img.scanLine(i), srcScanline, stride);
+ srcScanline -= stride;
+ }
+ } break;
+ }
+}
+
QImage GraphicsContext::readFramebuffer(QSize size)
{
- // todo: own implementation
- return qt_gl_read_framebuffer(size, true, true);
+ QImage img;
+ const unsigned int area = size.width() * size.height();
+ unsigned int bytes;
+ GLenum format, type;
+ GLenum internalFormat;
+ QImage::Format imageFormat;
+ uint stride;
+
+ switch (m_renderTargetFormat) {
+ case QAbstractTexture::RGBA8U:
+#ifdef QT_OPENGL_ES_2
+ format = GL_RGBA;
+ imageFormat = QImage::Format_RGBA8888_Premultiplied;
+#else
+ format = GL_BGRA;
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+ internalFormat = GL_RGBA8;
+#endif
+ type = GL_UNSIGNED_BYTE;
+ bytes = area * 4;
+ stride = size.width() * 4;
+ break;
+ case QAbstractTexture::RGB8U:
+#ifdef QT_OPENGL_ES_2
+ format = GL_RGBA;
+ imageFormat = QImage::Format_RGBX8888;
+#else
+ format = GL_BGRA;
+ imageFormat = QImage::Format_RGB32;
+ internalFormat = GL_RGB8;
+#endif
+ type = GL_UNSIGNED_BYTE;
+ bytes = area * 4;
+ stride = size.width() * 4;
+ break;
+#ifndef QT_OPENGL_ES_2
+ case QAbstractTexture::R5G6B5:
+ bytes = area * 2;
+ format = GL_RGB;
+ type = GL_UNSIGNED_SHORT;
+ internalFormat = GL_UNSIGNED_SHORT_5_6_5_REV;
+ imageFormat = QImage::Format_RGB16;
+ stride = size.width() * 2;
+ break;
+ case QAbstractTexture::RGBA32F:
+ bytes = area * 16;
+ format = GL_RGBA;
+ type = GL_RGBA32F;
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+ stride = size.width() * 16;
+ break;
+#endif
+ default:
+ // unsupported format
+ Q_UNREACHABLE();
+ return img;
+ }
+
+#ifndef QT_OPENGL_ES_2
+ GLint samples = 0;
+ m_gl->functions()->glGetIntegerv(GL_SAMPLES, &samples);
+ if (samples > 0 && !m_glHelper->supportsFeature(GraphicsHelperInterface::BlitFramebuffer))
+ return img;
+#endif
+
+ img = QImage(size.width(), size.height(), imageFormat);
+
+ QScopedArrayPointer<uchar> data(new uchar [bytes]);
+
+#ifndef QT_OPENGL_ES_2
+ if (samples > 0) {
+ // resolve multisample-framebuffer to renderbuffer and read pixels from it
+ GLuint fbo, rb;
+ QOpenGLFunctions *gl = m_gl->functions();
+ gl->glGenFramebuffers(1, &fbo);
+ gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+ gl->glGenRenderbuffers(1, &rb);
+ gl->glBindRenderbuffer(GL_RENDERBUFFER, rb);
+ gl->glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, size.width(), size.height());
+ gl->glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb);
+
+ const GLenum status = gl->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ gl->glDeleteRenderbuffers(1, &rb);
+ gl->glDeleteFramebuffers(1, &fbo);
+ return img;
+ }
+
+ m_glHelper->blitFramebuffer(0, 0, size.width(), size.height(),
+ 0, 0, size.width(), size.height(),
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ gl->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
+ gl->glReadPixels(0,0,size.width(), size.height(), format, type, data.data());
+
+ copyGLFramebufferDataToImage(img, data.data(), stride, size.width(), size.height(), m_renderTargetFormat);
+
+ gl->glBindRenderbuffer(GL_RENDERBUFFER, rb);
+ gl->glDeleteRenderbuffers(1, &rb);
+ gl->glBindFramebuffer(GL_FRAMEBUFFER, m_activeFBO);
+ gl->glDeleteFramebuffers(1, &fbo);
+ } else {
+#endif
+ // read pixels directly from framebuffer
+ m_gl->functions()->glReadPixels(0,0,size.width(), size.height(), format, type, data.data());
+ copyGLFramebufferDataToImage(img, data.data(), stride, size.width(), size.height(), m_renderTargetFormat);
+
+#ifndef QT_OPENGL_ES_2
+ }
+#endif
+
+ return img;
}
QT3D_UNIFORM_TYPE_IMPL(UniformType::Float, float, glUniform1fv)
diff --git a/src/render/graphicshelpers/graphicscontext_p.h b/src/render/graphicshelpers/graphicscontext_p.h
index c1f561a62..4a143d903 100644
--- a/src/render/graphicshelpers/graphicscontext_p.h
+++ b/src/render/graphicshelpers/graphicscontext_p.h
@@ -247,6 +247,7 @@ private:
HGLBuffer createGLBufferFor(Buffer *buffer);
void uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer = false);
bool bindGLBuffer(GLBuffer *buffer, GLBuffer::Type type);
+ void resolveRenderTargetFormat();
bool m_initialized;
const unsigned int m_id;
@@ -262,6 +263,7 @@ private:
QHash<Qt3DCore::QNodeId, HGLBuffer> m_renderBufferHash;
QHash<Qt3DCore::QNodeId, GLuint> m_renderTargets;
QHash<GLuint, QSize> m_renderTargetsSize;
+ QAbstractTexture::TextureFormat m_renderTargetFormat;
QHash<QSurface *, GraphicsHelperInterface*> m_glHelpers;