464void Q_TRACE_INSTRUMENT(qtopengl) QOpenGLFramebufferObjectPrivate::init(
465 QOpenGLFramebufferObject *qfbo,
const QSize &size,
466 QOpenGLFramebufferObject::Attachment attachment,
467 GLenum texture_target, GLenum internal_format,
468 GLint samples,
bool mipmap)
470 Q_TRACE_SCOPE(QOpenGLFramebufferObjectPrivate_init, qfbo, size, attachment, texture_target, internal_format, samples, mipmap);
473 QOpenGLContext *ctx = QOpenGLContext::currentContext();
475 funcs.initializeOpenGLFunctions();
477 if (!funcs.hasOpenGLFeature(QOpenGLFunctions::Framebuffers))
481 if (!funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)
482 || !funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) {
484 }
else if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
487 samples = qBound(0,
int(samples),
int(maxSamples));
490 colorAttachments.append(ColorAttachment(size, internal_format));
494 samples = qMax(0, samples);
495 requestedSamples = samples;
497 target = texture_target;
502 funcs.glGenFramebuffers(1, &fbo);
503 funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo);
505 QOpenGLContextPrivate::get(ctx)->qgl_current_fbo_invalid =
true;
509 format.setTextureTarget(target);
510 format.setInternalTextureFormat(internal_format);
511 format.setMipmap(mipmap);
516 initColorBuffer(0, &samples);
518 format.setSamples(
int(samples));
520 initDepthStencilAttachments(ctx, attachment);
523 fbo_guard =
new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
525 funcs.glDeleteFramebuffers(1, &fbo);
530void QOpenGLFramebufferObjectPrivate::initTexture(
int idx)
532 QOpenGLContext *ctx = QOpenGLContext::currentContext();
535 funcs.glGenTextures(1, &texture);
536 funcs.glBindTexture(target, texture);
538 funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
539 funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
540 funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
541 funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
543 ColorAttachment &color(colorAttachments[idx]);
545 GLuint pixelType = GL_UNSIGNED_BYTE;
549 pixelType = GL_UNSIGNED_SHORT;
553 bool isOpaque =
false;
554 switch (color.internalFormat) {
565 const GLuint textureFormat = isOpaque ? GL_RGB : GL_RGBA;
567 funcs.glTexImage2D(target, 0, color.internalFormat, color.size.width(), color.size.height(), 0,
568 textureFormat, pixelType,
nullptr);
569 if (format.mipmap()) {
570 int width = color.size.width();
571 int height = color.size.height();
573 while (width > 1 || height > 1) {
574 width = qMax(1, width >> 1);
575 height = qMax(1, height >> 1);
577 funcs.glTexImage2D(target, level, color.internalFormat, width, height, 0, textureFormat,
581 funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + idx,
585 funcs.glBindTexture(target, 0);
586 valid = checkFramebufferStatus(ctx);
588 color.guard =
new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);
590 funcs.glDeleteTextures(1, &texture);
634void QOpenGLFramebufferObjectPrivate::initDepthStencilAttachments(QOpenGLContext *ctx,
635 QOpenGLFramebufferObject::Attachment attachment)
640 const int samples = requestedSamples;
643 if (depth_buffer_guard) {
645 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
647 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
649 depth_buffer_guard->free();
651 if (stencil_buffer_guard) {
652 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
653 if (stencil_buffer_guard != depth_buffer_guard)
654 stencil_buffer_guard->free();
657 depth_buffer_guard =
nullptr;
658 stencil_buffer_guard =
nullptr;
660 GLuint depth_buffer = 0;
661 GLuint stencil_buffer = 0;
670 if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil) {
671 funcs.glGenRenderbuffers(1, &depth_buffer);
672 funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
673 Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
676 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
677 GL_DEPTH24_STENCIL8, dsSize.width(), dsSize.height());
679 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL,
680 dsSize.width(), dsSize.height());
683 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
684 GL_RENDERBUFFER, depth_buffer);
686 valid = checkFramebufferStatus(ctx);
688 funcs.glDeleteRenderbuffers(1, &depth_buffer);
693 if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil
694 && funcs.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil))
697 funcs.glGenRenderbuffers(1, &depth_buffer);
698 funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
699 Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
700 if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
701 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
704 funcs.glRenderbufferStorage(GL_RENDERBUFFER,
707 stencil_buffer = depth_buffer;
708 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
709 GL_RENDERBUFFER, depth_buffer);
710 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
711 GL_RENDERBUFFER, stencil_buffer);
713 valid = checkFramebufferStatus(ctx);
715 funcs.glDeleteRenderbuffers(1, &depth_buffer);
716 stencil_buffer = depth_buffer = 0;
720 if (depth_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil
721 || (attachment == QOpenGLFramebufferObject::Depth)))
723 funcs.glGenRenderbuffers(1, &depth_buffer);
724 funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
725 Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer));
726 if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) {
727 if (ctx->isOpenGLES()) {
728 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24))
729 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
732 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
733 GL_DEPTH_COMPONENT16, dsSize.width(), dsSize.height());
735 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples,
736 GL_DEPTH_COMPONENT, dsSize.width(), dsSize.height());
739 if (ctx->isOpenGLES()) {
740 if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) {
742 dsSize.width(), dsSize.height());
744 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
745 dsSize.width(), dsSize.height());
748 funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, dsSize.width(), dsSize.height());
751 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
752 GL_RENDERBUFFER, depth_buffer);
753 valid = checkFramebufferStatus(ctx);
755 funcs.glDeleteRenderbuffers(1, &depth_buffer);
760 if (stencil_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil)) {
761 funcs.glGenRenderbuffers(1, &stencil_buffer);
762 funcs.glBindRenderbuffer(GL_RENDERBUFFER, stencil_buffer);
763 Q_ASSERT(funcs.glIsRenderbuffer(stencil_buffer));
765#if QT_CONFIG(opengles2)
766 GLenum storage = GL_STENCIL_INDEX8;
768 GLenum storage = ctx->isOpenGLES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX;
771 if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample))
772 funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, storage, dsSize.width(), dsSize.height());
774 funcs.glRenderbufferStorage(GL_RENDERBUFFER, storage, dsSize.width(), dsSize.height());
776 funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
777 GL_RENDERBUFFER, stencil_buffer);
778 valid = checkFramebufferStatus(ctx);
780 funcs.glDeleteRenderbuffers(1, &stencil_buffer);
787 valid = checkFramebufferStatus(ctx);
792 if (depth_buffer && stencil_buffer) {
794 fbo_attachment = QOpenGLFramebufferObject::CombinedDepthStencil;
795 }
else if (depth_buffer) {
796 fbo_attachment = QOpenGLFramebufferObject::Depth;
798 fbo_attachment = QOpenGLFramebufferObject::NoAttachment;
803 depth_buffer_guard =
new QOpenGLSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
804 if (stencil_buffer) {
805 if (stencil_buffer == depth_buffer)
806 stencil_buffer_guard = depth_buffer_guard;
808 stencil_buffer_guard =
new QOpenGLSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
812 funcs.glDeleteRenderbuffers(1, &depth_buffer);
813 if (stencil_buffer && depth_buffer != stencil_buffer)
814 funcs.glDeleteRenderbuffers(1, &stencil_buffer);
818 format.setAttachment(fbo_attachment);
1412static QImage qt_gl_read_framebuffer(
const QSize &size, GLenum internal_format,
bool include_alpha,
bool flip)
1414 QOpenGLContext *ctx = QOpenGLContext::currentContext();
1415 QOpenGLFunctions *funcs = ctx->functions();
1417 GLenum error = funcs->glGetError();
1421 Qt::Orientations orient = flip ? Qt::Vertical : Qt::Orientations{};
1422 switch (internal_format) {
1425 return qt_gl_read_framebuffer_rgba8(size,
false, ctx).flipped(orient);
1427 return qt_gl_read_framebuffer_rgb10a2(size,
false, ctx).flipped(orient);
1429 return qt_gl_read_framebuffer_rgb10a2(size, include_alpha, ctx).flipped(orient);
1431 return qt_gl_read_framebuffer_rgba16(size,
false, ctx).flipped(orient);
1433 return qt_gl_read_framebuffer_rgba16(size, include_alpha, ctx).flipped(orient);
1435 return qt_gl_read_framebuffer_rgba16f(size,
false, ctx).flipped(orient);
1437 return qt_gl_read_framebuffer_rgba16f(size, include_alpha, ctx).flipped(orient);
1439 return qt_gl_read_framebuffer_rgba32f(size,
false, ctx).flipped(orient);
1441 return qt_gl_read_framebuffer_rgba32f(size, include_alpha, ctx).flipped(orient);
1445 return qt_gl_read_framebuffer_rgba8(size, include_alpha, ctx).flipped(orient);
1448 Q_UNREACHABLE_RETURN(QImage());
1512QImage QOpenGLFramebufferObject::toImage(
bool flipped,
int colorAttachmentIndex)
const
1514 Q_D(
const QOpenGLFramebufferObject);
1518 QOpenGLContext *ctx = QOpenGLContext::currentContext();
1520 qWarning(
"QOpenGLFramebufferObject::toImage() called without a current context");
1524 if (d->colorAttachments.size() <= colorAttachmentIndex) {
1525 qWarning(
"QOpenGLFramebufferObject::toImage() called for missing color attachment");
1530 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
1532 if (prevFbo != d->fbo())
1533 const_cast<QOpenGLFramebufferObject *>(
this)->bind();
1536 QOpenGLExtraFunctions *extraFuncs = ctx->extraFunctions();
1538 if (format().samples() != 0) {
1539 QRect rect(QPoint(0, 0), size());
1540 QOpenGLFramebufferObjectFormat fmt;
1541 if (extraFuncs->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) {
1542 fmt.setInternalTextureFormat(d->colorAttachments[colorAttachmentIndex].internalFormat);
1543 QOpenGLFramebufferObject temp(d->colorAttachments[colorAttachmentIndex].size, fmt);
1544 blitFramebuffer(&temp, rect,
const_cast<QOpenGLFramebufferObject *>(
this), rect,
1545 GL_COLOR_BUFFER_BIT, GL_NEAREST,
1546 colorAttachmentIndex, 0);
1547 image = temp.toImage(flipped);
1549 fmt.setInternalTextureFormat(d->colorAttachments[0].internalFormat);
1550 QOpenGLFramebufferObject temp(size(), fmt);
1551 blitFramebuffer(&temp, rect,
const_cast<QOpenGLFramebufferObject *>(
this), rect);
1552 image = temp.toImage(flipped);
1555 if (extraFuncs->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) {
1556 extraFuncs->glReadBuffer(GL_COLOR_ATTACHMENT0 + colorAttachmentIndex);
1557 image = qt_gl_read_framebuffer(d->colorAttachments[colorAttachmentIndex].size,
1558 d->colorAttachments[colorAttachmentIndex].internalFormat,
1560 extraFuncs->glReadBuffer(GL_COLOR_ATTACHMENT0);
1562 image = qt_gl_read_framebuffer(d->colorAttachments[0].size,
1563 d->colorAttachments[0].internalFormat,
1568 if (prevFbo != d->fbo())
1569 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
1799void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
const QRect &targetRect,
1800 QOpenGLFramebufferObject *source,
const QRect &sourceRect,
1803 int readColorAttachmentIndex,
1804 int drawColorAttachmentIndex,
1805 QOpenGLFramebufferObject::FramebufferRestorePolicy restorePolicy)
1807 QOpenGLContext *ctx = QOpenGLContext::currentContext();
1811 QOpenGLExtensions extensions(ctx);
1812 if (!extensions.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit))
1816 if (restorePolicy == RestoreFrameBufferBinding)
1817 ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo);
1819 const int sx0 = sourceRect.left();
1820 const int sx1 = sourceRect.left() + sourceRect.width();
1821 const int sy0 = sourceRect.top();
1822 const int sy1 = sourceRect.top() + sourceRect.height();
1824 const int tx0 = targetRect.left();
1825 const int tx1 = targetRect.left() + targetRect.width();
1826 const int ty0 = targetRect.top();
1827 const int ty1 = targetRect.top() + targetRect.height();
1829 const GLuint defaultFboId = ctx->defaultFramebufferObject();
1831 extensions.glBindFramebuffer(
GL_READ_FRAMEBUFFER, source ? source->handle() : defaultFboId);
1832 extensions.glBindFramebuffer(
GL_DRAW_FRAMEBUFFER, target ? target->handle() : defaultFboId);
1834 const bool supportsMRT = extensions.hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets);
1836 extensions.glReadBuffer(GL_COLOR_ATTACHMENT0 + readColorAttachmentIndex);
1838 GLenum drawBuf = GL_COLOR_ATTACHMENT0 + drawColorAttachmentIndex;
1839 extensions.glDrawBuffers(1, &drawBuf);
1843 extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1,
1848 extensions.glReadBuffer(GL_COLOR_ATTACHMENT0);
1850 switch (restorePolicy) {
1851 case RestoreFrameBufferBinding:
1852 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo);
1855 case RestoreFramebufferBindingToDefault:
1856 ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject());
1859 case DontRestoreFramebufferBinding: