465void Q_TRACE_INSTRUMENT(qtopengl) QOpenGLFramebufferObjectPrivate::init(
466 QOpenGLFramebufferObject *qfbo,
const QSize &size,
467 QOpenGLFramebufferObject::Attachment attachment,
468 GLenum texture_target, GLenum internal_format,
469 GLint samples,
bool mipmap)
471 Q_TRACE_SCOPE(QOpenGLFramebufferObjectPrivate_init, qfbo, size, attachment, texture_target, internal_format, samples, mipmap);
474 QOpenGLContext *ctx = QOpenGLContext::currentContext();
476 funcs.initializeOpenGLFunctions();
478 if (!funcs.hasOpenGLFeature(QOpenGLFunctions::Framebuffers))
482 if (!funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
483 || !funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) {
485 }
else if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
488 samples = qBound(0,
int(samples),
int(maxSamples));
491 colorAttachments.append(ColorAttachment(size, internal_format));
495 samples = qMax(0, samples);
496 requestedSamples = samples;
498 target = texture_target;
503 funcs.glGenFramebuffers(1, &fbo);
504 funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo);
506 QOpenGLContextPrivate::get(ctx)->qgl_current_fbo_invalid =
true;
510 format.setTextureTarget(target);
511 format.setInternalTextureFormat(internal_format);
512 format.setMipmap(mipmap);
517 initColorBuffer(0, &samples);
519 format.setSamples(
int(samples));
521 initDepthStencilAttachments(ctx, attachment);
524 fbo_guard =
new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
526 funcs.glDeleteFramebuffers(1, &fbo);
531void QOpenGLFramebufferObjectPrivate::initTexture(
int idx)
533 QOpenGLContext *ctx = QOpenGLContext::currentContext();
536 funcs.glGenTextures(1, &texture);
537 funcs.glBindTexture(target, texture);
539 funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
540 funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
541 funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
542 funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
544 ColorAttachment &color(colorAttachments[idx]);
546 GLuint pixelType = GL_UNSIGNED_BYTE;
550 pixelType = GL_UNSIGNED_SHORT;
554 bool isOpaque =
false;
555 switch (color.internalFormat) {
566 const GLuint textureFormat = isOpaque ? GL_RGB : GL_RGBA;
568 funcs.glTexImage2D(target, 0, color.internalFormat, color.size.width(), color.size.height(), 0,
569 textureFormat, pixelType,
nullptr);
570 if (format.mipmap()) {
571 int width = color.size.width();
572 int height = color.size.height();
574 while (width > 1 || height > 1) {
575 width = qMax(1, width >> 1);
576 height = qMax(1, height >> 1);
578 funcs.glTexImage2D(target, level, color.internalFormat, width, height, 0, textureFormat,
582 funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + idx,
586 funcs.glBindTexture(target, 0);
587 valid = checkFramebufferStatus(ctx);
589 color.guard =
new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);
591 funcs.glDeleteTextures(1, &texture);
635void QOpenGLFramebufferObjectPrivate::initDepthStencilAttachments(QOpenGLContext *ctx,
636 QOpenGLFramebufferObject::Attachment attachment)
641 const int samples = requestedSamples;
644 if (depth_buffer_guard) {
646 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
648 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
650 depth_buffer_guard->free();
652 if (stencil_buffer_guard) {
653 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
654 if (stencil_buffer_guard != depth_buffer_guard)
655 stencil_buffer_guard->free();
658 depth_buffer_guard =
nullptr;
659 stencil_buffer_guard =
nullptr;
661 GLuint depth_buffer = 0;
662 GLuint stencil_buffer = 0;
671 if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil) {
672 funcs.glGenRenderbuffers(1, &depth_buffer);
673 funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
674 Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
677 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
678 GL_DEPTH24_STENCIL8, dsSize.width(), dsSize.height());
680 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL,
681 dsSize.width(), dsSize.height());
684 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
685 GL_RENDERBUFFER, depth_buffer);
687 valid = checkFramebufferStatus(ctx);
689 funcs.glDeleteRenderbuffers(1, &depth_buffer);
694 if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil
695 && funcs.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil))
698 funcs.glGenRenderbuffers(1, &depth_buffer);
699 funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
700 Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
701 if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
702 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
705 funcs.glRenderbufferStorage(GL_RENDERBUFFER,
708 stencil_buffer = depth_buffer;
709 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
710 GL_RENDERBUFFER, depth_buffer);
711 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
712 GL_RENDERBUFFER, stencil_buffer);
714 valid = checkFramebufferStatus(ctx);
716 funcs.glDeleteRenderbuffers(1, &depth_buffer);
717 stencil_buffer = depth_buffer = 0;
721 if (depth_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil
722 || (attachment == QOpenGLFramebufferObject::Depth)))
724 funcs.glGenRenderbuffers(1, &depth_buffer);
725 funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
726 Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
727 if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) {
728 if (ctx->isOpenGLES()) {
729 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24))
730 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
733 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
734 GL_DEPTH_COMPONENT16, dsSize.width(), dsSize.height());
736 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
737 GL_DEPTH_COMPONENT, dsSize.width(), dsSize.height());
740 if (ctx->isOpenGLES()) {
741 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) {
743 dsSize.width(), dsSize.height());
745 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
746 dsSize.width(), dsSize.height());
749 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, dsSize.width(), dsSize.height());
752 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
753 GL_RENDERBUFFER, depth_buffer);
754 valid = checkFramebufferStatus(ctx);
756 funcs.glDeleteRenderbuffers(1, &depth_buffer);
761 if (stencil_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil)) {
762 funcs.glGenRenderbuffers(1, &stencil_buffer);
763 funcs.glBindRenderbuffer(GL_RENDERBUFFER, stencil_buffer);
764 Q_ASSERT(funcs.glIsRenderbuffer(stencil_buffer));
766#if QT_CONFIG(opengles2)
767 GLenum storage = GL_STENCIL_INDEX8;
769 GLenum storage = ctx->isOpenGLES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX;
772 if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
773 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, storage, dsSize.width(), dsSize.height());
775 funcs.glRenderbufferStorage(GL_RENDERBUFFER, storage, dsSize.width(), dsSize.height());
777 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
778 GL_RENDERBUFFER, stencil_buffer);
779 valid = checkFramebufferStatus(ctx);
781 funcs.glDeleteRenderbuffers(1, &stencil_buffer);
788 valid = checkFramebufferStatus(ctx);
793 if (depth_buffer && stencil_buffer) {
795 fbo_attachment = QOpenGLFramebufferObject::CombinedDepthStencil;
796 }
else if (depth_buffer) {
797 fbo_attachment = QOpenGLFramebufferObject::Depth;
799 fbo_attachment = QOpenGLFramebufferObject::NoAttachment;
804 depth_buffer_guard =
new QOpenGLSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
805 if (stencil_buffer) {
806 if (stencil_buffer == depth_buffer)
807 stencil_buffer_guard = depth_buffer_guard;
809 stencil_buffer_guard =
new QOpenGLSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
813 funcs.glDeleteRenderbuffers(1, &depth_buffer);
814 if (stencil_buffer && depth_buffer != stencil_buffer)
815 funcs.glDeleteRenderbuffers(1, &stencil_buffer);
819 format.setAttachment(fbo_attachment);
1413static QImage qt_gl_read_framebuffer(
const QSize &size, GLenum internal_format,
bool include_alpha,
bool flip)
1415 QOpenGLContext *ctx = QOpenGLContext::currentContext();
1416 QOpenGLFunctions *funcs = ctx->functions();
1418 GLenum error = funcs->glGetError();
1422 Qt::Orientations orient = flip ? Qt::Vertical : Qt::Orientations{};
1423 switch (internal_format) {
1426 return qt_gl_read_framebuffer_rgba8(size,
false, ctx).flipped(orient);
1428 return qt_gl_read_framebuffer_rgb10a2(size,
false, ctx).flipped(orient);
1430 return qt_gl_read_framebuffer_rgb10a2(size, include_alpha, ctx).flipped(orient);
1432 return qt_gl_read_framebuffer_rgba16(size,
false, ctx).flipped(orient);
1434 return qt_gl_read_framebuffer_rgba16(size, include_alpha, ctx).flipped(orient);
1436 return qt_gl_read_framebuffer_rgba16f(size,
false, ctx).flipped(orient);
1438 return qt_gl_read_framebuffer_rgba16f(size, include_alpha, ctx).flipped(orient);
1440 return qt_gl_read_framebuffer_rgba32f(size,
false, ctx).flipped(orient);
1442 return qt_gl_read_framebuffer_rgba32f(size, include_alpha, ctx).flipped(orient);
1446 return qt_gl_read_framebuffer_rgba8(size, include_alpha, ctx).flipped(orient);
1449 Q_UNREACHABLE_RETURN(QImage());
1513QImage QOpenGLFramebufferObject::toImage(
bool flipped,
int colorAttachmentIndex)
const
1515 Q_D(
const QOpenGLFramebufferObject);
1519 QOpenGLContext *ctx = QOpenGLContext::currentContext();
1521 qWarning(
"QOpenGLFramebufferObject::toImage() called without a current context");
1525 if (d->colorAttachments.size() <= colorAttachmentIndex) {
1526 qWarning(
"QOpenGLFramebufferObject::toImage() called for missing color attachment");
1531 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
1533 if (prevFbo != d->fbo())
1534 const_cast<QOpenGLFramebufferObject *>(
this)->bind();
1537 QOpenGLExtraFunctions *extraFuncs = ctx->extraFunctions();
1539 if (format().samples() != 0) {
1540 QRect rect(QPoint(0, 0), size());
1541 QOpenGLFramebufferObjectFormat fmt;
1542 if (extraFuncs->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) {
1543 fmt.setInternalTextureFormat(d->colorAttachments[colorAttachmentIndex].internalFormat);
1544 QOpenGLFramebufferObject temp(d->colorAttachments[colorAttachmentIndex].size, fmt);
1545 blitFramebuffer(&temp, rect,
const_cast<QOpenGLFramebufferObject *>(
this), rect,
1546 GL_COLOR_BUFFER_BIT, GL_NEAREST,
1547 colorAttachmentIndex, 0);
1548 image = temp.toImage(flipped);
1550 fmt.setInternalTextureFormat(d->colorAttachments[0].internalFormat);
1551 QOpenGLFramebufferObject temp(size(), fmt);
1552 blitFramebuffer(&temp, rect,
const_cast<QOpenGLFramebufferObject *>(
this), rect);
1553 image = temp.toImage(flipped);
1556 if (extraFuncs->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) {
1557 extraFuncs->glReadBuffer(GL_COLOR_ATTACHMENT0 + colorAttachmentIndex);
1558 image = qt_gl_read_framebuffer(d->colorAttachments[colorAttachmentIndex].size,
1559 d->colorAttachments[colorAttachmentIndex].internalFormat,
1561 extraFuncs->glReadBuffer(GL_COLOR_ATTACHMENT0);
1563 image = qt_gl_read_framebuffer(d->colorAttachments[0].size,
1564 d->colorAttachments[0].internalFormat,
1569 if (prevFbo != d->fbo())
1570 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
1800void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
const QRect &targetRect,
1801 QOpenGLFramebufferObject *source,
const QRect &sourceRect,
1804 int readColorAttachmentIndex,
1805 int drawColorAttachmentIndex,
1806 QOpenGLFramebufferObject::FramebufferRestorePolicy restorePolicy)
1808 QOpenGLContext *ctx = QOpenGLContext::currentContext();
1812 QOpenGLExtensions extensions(ctx);
1813 if (!extensions.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit))
1817 if (restorePolicy == RestoreFrameBufferBinding)
1818 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
1820 const int sx0 = sourceRect.left();
1821 const int sx1 = sourceRect.left() + sourceRect.width();
1822 const int sy0 = sourceRect.top();
1823 const int sy1 = sourceRect.top() + sourceRect.height();
1825 const int tx0 = targetRect.left();
1826 const int tx1 = targetRect.left() + targetRect.width();
1827 const int ty0 = targetRect.top();
1828 const int ty1 = targetRect.top() + targetRect.height();
1830 const GLuint defaultFboId = ctx->defaultFramebufferObject();
1832 extensions.glBindFramebuffer(
GL_READ_FRAMEBUFFER, source ? source->handle() : defaultFboId);
1833 extensions.glBindFramebuffer(
GL_DRAW_FRAMEBUFFER, target ? target->handle() : defaultFboId);
1835 const bool supportsMRT = extensions.hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets);
1837 extensions.glReadBuffer(GL_COLOR_ATTACHMENT0 + readColorAttachmentIndex);
1839 GLenum drawBuf = GL_COLOR_ATTACHMENT0 + drawColorAttachmentIndex;
1840 extensions.glDrawBuffers(1, &drawBuf);
1844 extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1,
1849 extensions.glReadBuffer(GL_COLOR_ATTACHMENT0);
1851 switch (restorePolicy) {
1852 case RestoreFrameBufferBinding:
1853 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
1856 case RestoreFramebufferBindingToDefault:
1857 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
1860 case DontRestoreFramebufferBinding: