| /**************************************************************************** |
| ** |
| ** Copyright (C) 2008-2012 NVIDIA Corporation. |
| ** Copyright (C) 2019 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of Qt Quick 3D. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 or (at your option) any later version |
| ** approved by the KDE Free Qt Foundation. The licenses are as published by |
| ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include <QtQuick3DRender/private/qssgrenderframebuffer_p.h> |
| #include <QtQuick3DRender/private/qssgrenderrenderbuffer_p.h> |
| #include <QtQuick3DRender/private/qssgrendertexture2d_p.h> |
| #include <QtQuick3DRender/private/qssgrenderbasetypes_p.h> |
| #include <QtQuick3DRender/private/qssgrendercontext_p.h> |
| #include <QtQuick3DUtils/private/qssgutils_p.h> |
| |
| QT_BEGIN_NAMESPACE |
| |
| QSSGRenderFrameBuffer::QSSGRenderFrameBuffer(const QSSGRef<QSSGRenderContext> &context) |
| : m_context(context), m_backend(context->backend()), m_bufferHandle(nullptr), m_attachmentBits(0) |
| { |
| m_bufferHandle = m_backend->createRenderTarget(); |
| Q_ASSERT(m_bufferHandle); |
| } |
| |
| QSSGRenderFrameBuffer::~QSSGRenderFrameBuffer() |
| { |
| m_backend->releaseRenderTarget(m_bufferHandle); |
| m_bufferHandle = nullptr; |
| m_attachmentBits = 0; |
| |
| // release attachments |
| for (int idx = 0; idx != int(QSSGRenderFrameBufferAttachment::LastAttachment); ++idx) { |
| if ((QSSGRenderFrameBufferAttachment)idx != QSSGRenderFrameBufferAttachment::DepthStencil |
| || m_context->supportsDepthStencil()) |
| releaseAttachment((QSSGRenderFrameBufferAttachment)idx); |
| } |
| } |
| |
| inline void CheckAttachment(const QSSGRef<QSSGRenderContext> &ctx, QSSGRenderFrameBufferAttachment attachment) |
| { |
| (void)ctx; |
| (void)attachment; |
| } |
| |
| QSSGRenderTextureTargetType QSSGRenderFrameBuffer::releaseAttachment(QSSGRenderFrameBufferAttachment idx) |
| { |
| QSSGRenderTextureTargetType target = QSSGRenderTextureTargetType::Unknown; |
| int index = static_cast<int>(idx); |
| |
| QSSGRenderTextureOrRenderBuffer attachment = m_attachments[index]; |
| if (attachment.hasTexture2D()) { |
| target = (attachment.texture2D()->isMultisampleTexture()) ? QSSGRenderTextureTargetType::Texture2D_MS |
| : QSSGRenderTextureTargetType::Texture2D; |
| // Attach.GetTexture2D()->release(); |
| } else if (attachment.hasTextureCube()) { |
| target = (attachment.textureCube()->isMultisampleTexture()) ? QSSGRenderTextureTargetType::Texture2D_MS |
| : QSSGRenderTextureTargetType::TextureCube; |
| // Attach.GetTextureCube()->release(); |
| } else if (attachment.hasRenderBuffer()) |
| // Attach.GetRenderBuffer()->release(); |
| |
| CheckAttachment(m_context, idx); |
| m_attachments[index] = QSSGRenderTextureOrRenderBuffer(); |
| |
| m_attachmentBits &= ~(1 << index); |
| |
| return target; |
| } |
| |
| QSSGRenderTextureOrRenderBuffer QSSGRenderFrameBuffer::attachment(QSSGRenderFrameBufferAttachment attachment) |
| { |
| if (attachment == QSSGRenderFrameBufferAttachment::Unknown || attachment > QSSGRenderFrameBufferAttachment::LastAttachment) { |
| qCCritical(RENDER_INVALID_PARAMETER, "Attachment out of range"); |
| return QSSGRenderTextureOrRenderBuffer(); |
| } |
| CheckAttachment(m_context, attachment); |
| return m_attachments[static_cast<int>(attachment)]; |
| } |
| |
| void QSSGRenderFrameBuffer::attach(QSSGRenderFrameBufferAttachment attachment, |
| const QSSGRenderTextureOrRenderBuffer &buffer, |
| QSSGRenderTextureTargetType target) |
| { |
| if (attachment == QSSGRenderFrameBufferAttachment::Unknown || attachment > QSSGRenderFrameBufferAttachment::LastAttachment) { |
| qCCritical(RENDER_INVALID_PARAMETER, "Attachment out of range"); |
| return; |
| } |
| |
| const quint32 attachmentBit = (1 << static_cast<int>(attachment)); |
| |
| // early out |
| // if there is nothing to detach |
| if (!buffer.hasTexture2D() && !buffer.hasRenderBuffer() && !(m_attachmentBits & attachmentBit)) |
| return; |
| |
| CheckAttachment(m_context, attachment); |
| // Ensure we are the bound framebuffer |
| m_context->setRenderTarget(this); |
| |
| // release previous attachments |
| QSSGRenderTextureTargetType theRelTarget = releaseAttachment(attachment); |
| |
| if (buffer.hasTexture2D()) { |
| // On the same attachment point there could be a something attached with a different |
| // target MSAA <--> NoMSAA |
| if (theRelTarget != QSSGRenderTextureTargetType::Unknown && theRelTarget != target) |
| m_backend->renderTargetAttach(m_bufferHandle, attachment, QSSGRenderBackend::QSSGRenderBackendTextureObject(nullptr), theRelTarget); |
| |
| m_backend->renderTargetAttach(m_bufferHandle, attachment, buffer.texture2D()->handle(), target); |
| // buffer.GetTexture2D()->addRef(); |
| m_attachmentBits |= attachmentBit; |
| } else if (buffer.hasRenderBuffer()) { |
| m_backend->renderTargetAttach(m_bufferHandle, attachment, buffer.renderBuffer()->handle()); |
| // buffer.GetRenderBuffer()->addRef(); |
| m_attachmentBits |= attachmentBit; |
| } else if (theRelTarget == QSSGRenderTextureTargetType::Unknown) { |
| // detach renderbuffer |
| m_backend->renderTargetAttach(m_bufferHandle, attachment, QSSGRenderBackend::QSSGRenderBackendRenderbufferObject(nullptr)); |
| } else { |
| // detach texture |
| m_backend->renderTargetAttach(m_bufferHandle, attachment, QSSGRenderBackend::QSSGRenderBackendTextureObject(nullptr), theRelTarget); |
| } |
| m_attachments[static_cast<int>(attachment)] = buffer; |
| } |
| |
| void QSSGRenderFrameBuffer::attachFace(QSSGRenderFrameBufferAttachment attachment, |
| const QSSGRenderTextureOrRenderBuffer &buffer, |
| QSSGRenderTextureCubeFace face) |
| { |
| if (attachment == QSSGRenderFrameBufferAttachment::Unknown || attachment > QSSGRenderFrameBufferAttachment::LastAttachment) { |
| qCCritical(RENDER_INVALID_PARAMETER, "Attachment out of range"); |
| return; |
| } |
| |
| if (face == QSSGRenderTextureCubeFace::InvalidFace) { |
| Q_ASSERT(false); |
| return; |
| } |
| |
| CheckAttachment(m_context, attachment); |
| // Ensure we are the bound framebuffer |
| m_context->setRenderTarget(this); |
| |
| // release previous attachments |
| QSSGRenderTextureTargetType attachTarget = static_cast<QSSGRenderTextureTargetType>( |
| (int)QSSGRenderTextureTargetType::TextureCube + (int)face); |
| QSSGRenderTextureTargetType theRelTarget = releaseAttachment(attachment); |
| |
| // If buffer has no texture cube, this call is used to detach faces. |
| // If release target is not cube, there is something else attached to that |
| // attachment point, so we want to release that first. E.g (MSAA <--> NoMSAA) |
| if (theRelTarget == QSSGRenderTextureTargetType::TextureCube && !buffer.hasTextureCube()) { |
| theRelTarget = attachTarget; |
| attachTarget = QSSGRenderTextureTargetType::Unknown; |
| } else if (theRelTarget == QSSGRenderTextureTargetType::TextureCube) { |
| theRelTarget = QSSGRenderTextureTargetType::Unknown; |
| } |
| if (theRelTarget != QSSGRenderTextureTargetType::Unknown) { |
| m_backend->renderTargetAttach(m_bufferHandle, attachment, QSSGRenderBackend::QSSGRenderBackendTextureObject(nullptr), theRelTarget); |
| } |
| |
| if (attachTarget != QSSGRenderTextureTargetType::Unknown) { |
| m_backend->renderTargetAttach(m_bufferHandle, attachment, buffer.textureCube()->handle(), attachTarget); |
| // buffer.GetTextureCube()->addRef(); |
| m_attachmentBits |= (1 << static_cast<int>(attachment)); |
| } |
| |
| m_attachments[static_cast<int>(attachment)] = buffer; |
| } |
| |
| bool QSSGRenderFrameBuffer::isComplete() |
| { |
| // Ensure we are the bound framebuffer |
| m_context->setRenderTarget(this); |
| |
| return m_backend->renderTargetIsValid(m_bufferHandle); |
| } |
| |
| QSSGRenderTextureOrRenderBuffer::QSSGRenderTextureOrRenderBuffer(const QSSGRef<QSSGRenderTexture2D> &texture) |
| : m_texture2D(texture) |
| { |
| } |
| |
| QSSGRenderTextureOrRenderBuffer::QSSGRenderTextureOrRenderBuffer(const QSSGRef<QSSGRenderRenderBuffer> &render) |
| : m_renderBuffer(render) |
| { |
| } |
| |
| QSSGRenderTextureOrRenderBuffer::QSSGRenderTextureOrRenderBuffer(const QSSGRef<QSSGRenderTextureCube> &textureCube) |
| : m_textureCube(textureCube) |
| { |
| } |
| |
| QSSGRenderTextureOrRenderBuffer::QSSGRenderTextureOrRenderBuffer() = default; |
| |
| QSSGRenderTextureOrRenderBuffer::QSSGRenderTextureOrRenderBuffer(const QSSGRenderTextureOrRenderBuffer &other) = default; |
| |
| QSSGRenderTextureOrRenderBuffer::~QSSGRenderTextureOrRenderBuffer() = default; |
| |
| |
| QSSGRenderTextureOrRenderBuffer &QSSGRenderTextureOrRenderBuffer::operator=(const QSSGRenderTextureOrRenderBuffer &other) |
| { |
| if (this != &other) { |
| m_texture2D = other.m_texture2D; |
| m_renderBuffer = other.m_renderBuffer; |
| m_textureCube = other.m_textureCube; |
| } |
| return *this; |
| } |
| |
| QSSGRef<QSSGRenderTexture2D> QSSGRenderTextureOrRenderBuffer::texture2D() const |
| { |
| Q_ASSERT(hasTexture2D()); |
| return m_texture2D; |
| } |
| |
| QSSGRef<QSSGRenderTextureCube> QSSGRenderTextureOrRenderBuffer::textureCube() const |
| { |
| Q_ASSERT(hasTextureCube()); |
| return m_textureCube; |
| } |
| |
| QSSGRef<QSSGRenderRenderBuffer> QSSGRenderTextureOrRenderBuffer::renderBuffer() const |
| { |
| Q_ASSERT(hasRenderBuffer()); |
| return m_renderBuffer; |
| } |
| |
| QT_END_NAMESPACE |