summaryrefslogtreecommitdiffstats
path: root/src/render/Qt3DSRenderFrameBuffer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/render/Qt3DSRenderFrameBuffer.cpp')
-rw-r--r--src/render/Qt3DSRenderFrameBuffer.cpp300
1 files changed, 300 insertions, 0 deletions
diff --git a/src/render/Qt3DSRenderFrameBuffer.cpp b/src/render/Qt3DSRenderFrameBuffer.cpp
new file mode 100644
index 0000000..0ab3842
--- /dev/null
+++ b/src/render/Qt3DSRenderFrameBuffer.cpp
@@ -0,0 +1,300 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $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 "foundation/Qt3DSAllocator.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "render/Qt3DSRenderFrameBuffer.h"
+#include "render/Qt3DSRenderRenderBuffer.h"
+#include "render/Qt3DSRenderTexture2D.h"
+#include "render/Qt3DSRenderBaseTypes.h"
+#include "render/Qt3DSRenderContext.h"
+
+namespace qt3ds {
+namespace render {
+
+ NVRenderFrameBuffer::NVRenderFrameBuffer(NVRenderContextImpl &context, NVFoundationBase &fnd)
+ : m_Context(context)
+ , m_Foundation(fnd)
+ , mRefCount(0)
+ , m_Backend(context.GetBackend())
+ , m_BufferHandle(NULL)
+ , m_AttachmentBits(0)
+ {
+ m_BufferHandle = m_Backend->CreateRenderTarget();
+ QT3DS_ASSERT(m_BufferHandle);
+ }
+
+ NVRenderFrameBuffer::~NVRenderFrameBuffer()
+ {
+ m_Context.FrameBufferDestroyed(*this);
+ m_Backend->ReleaseRenderTarget(m_BufferHandle);
+ m_BufferHandle = 0;
+ m_AttachmentBits = 0;
+
+ // release attachments
+ QT3DS_FOREACH(idx, (QT3DSU32)NVRenderFrameBufferAttachments::LastAttachment)
+ {
+ if ((NVRenderFrameBufferAttachments::Enum)idx
+ != NVRenderFrameBufferAttachments::DepthStencil
+ || m_Context.IsDepthStencilSupported())
+ releaseAttachment((NVRenderFrameBufferAttachments::Enum)idx);
+ }
+ }
+
+ inline void CheckAttachment(NVRenderContext &ctx,
+ NVRenderFrameBufferAttachments::Enum attachment)
+ {
+#ifdef _DEBUG
+ QT3DS_ASSERT(attachment != NVRenderFrameBufferAttachments::DepthStencil
+ || ctx.IsDepthStencilSupported());
+#endif
+ (void)ctx;
+ (void)attachment;
+ }
+
+ NVRenderTextureTargetType::Enum
+ NVRenderFrameBuffer::releaseAttachment(NVRenderFrameBufferAttachments::Enum idx)
+ {
+ NVRenderTextureTargetType::Enum target = NVRenderTextureTargetType::Unknown;
+
+ NVRenderTextureOrRenderBuffer Attach = m_Attachments[idx];
+ if (Attach.HasTexture2D()) {
+ target = (Attach.GetTexture2D()->IsMultisampleTexture())
+ ? NVRenderTextureTargetType::Texture2D_MS
+ : NVRenderTextureTargetType::Texture2D;
+ Attach.GetTexture2D()->release();
+ } else if (Attach.HasTexture2DArray()) {
+ target = (Attach.GetTexture2DArray()->IsMultisampleTexture())
+ ? NVRenderTextureTargetType::Texture2D_MS
+ : NVRenderTextureTargetType::Texture2D_Array;
+ Attach.GetTexture2DArray()->release();
+ } else if (Attach.HasTextureCube()) {
+ target = (Attach.GetTextureCube()->IsMultisampleTexture())
+ ? NVRenderTextureTargetType::Texture2D_MS
+ : NVRenderTextureTargetType::TextureCube;
+ Attach.GetTextureCube()->release();
+ } else if (Attach.HasRenderBuffer())
+ Attach.GetRenderBuffer()->release();
+
+ CheckAttachment(m_Context, idx);
+ m_Attachments[idx] = NVRenderTextureOrRenderBuffer();
+
+ m_AttachmentBits &= ~(1 << idx);
+
+ return target;
+ }
+
+ NVRenderTextureOrRenderBuffer
+ NVRenderFrameBuffer::GetAttachment(NVRenderFrameBufferAttachments::Enum attachment)
+ {
+ if (attachment == NVRenderFrameBufferAttachments::Unknown
+ || attachment > NVRenderFrameBufferAttachments::LastAttachment) {
+ qCCritical(INVALID_PARAMETER, "Attachment out of range");
+ return NVRenderTextureOrRenderBuffer();
+ }
+ CheckAttachment(m_Context, attachment);
+ return m_Attachments[attachment];
+ }
+
+ void NVRenderFrameBuffer::Attach(NVRenderFrameBufferAttachments::Enum attachment,
+ NVRenderTextureOrRenderBuffer buffer,
+ NVRenderTextureTargetType::Enum target)
+ {
+ if (attachment == NVRenderFrameBufferAttachments::Unknown
+ || attachment > NVRenderFrameBufferAttachments::LastAttachment) {
+ qCCritical(INVALID_PARAMETER, "Attachment out of range");
+ return;
+ }
+
+ // early out
+ // if there is nothing to detach
+ if (!buffer.HasTexture2D() && !buffer.HasRenderBuffer() && !buffer.HasTexture2DArray()
+ && !(m_AttachmentBits & (1 << attachment)))
+ return;
+
+ CheckAttachment(m_Context, attachment);
+ // Ensure we are the bound framebuffer
+ m_Context.SetRenderTarget(this);
+
+ // release previous attachments
+ NVRenderTextureTargetType::Enum 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 != NVRenderTextureTargetType::Unknown && theRelTarget != target)
+ m_Backend->RenderTargetAttach(m_BufferHandle, attachment,
+ NVRenderBackend::NVRenderBackendTextureObject(NULL),
+ theRelTarget);
+
+ m_Backend->RenderTargetAttach(m_BufferHandle, attachment,
+ buffer.GetTexture2D()->GetTextureObjectHandle(), target);
+ buffer.GetTexture2D()->addRef();
+ m_AttachmentBits |= (1 << attachment);
+ } else if (buffer.HasTexture2DArray()) {
+ // On the same attachment point there could be a something attached with a different
+ // target MSAA <--> NoMSAA
+ if (theRelTarget != NVRenderTextureTargetType::Unknown && theRelTarget != target)
+ m_Backend->RenderTargetAttach(m_BufferHandle, attachment,
+ NVRenderBackend::NVRenderBackendTextureObject(NULL),
+ theRelTarget);
+
+ m_Backend->RenderTargetAttach(m_BufferHandle, attachment,
+ buffer.GetTexture2D()->GetTextureObjectHandle(), target);
+ buffer.GetTexture2DArray()->addRef();
+ m_AttachmentBits |= (1 << attachment);
+ } else if (buffer.HasRenderBuffer()) {
+ m_Backend->RenderTargetAttach(m_BufferHandle, attachment,
+ buffer.GetRenderBuffer()->GetRenderBuffertHandle());
+ buffer.GetRenderBuffer()->addRef();
+ m_AttachmentBits |= (1 << attachment);
+ } else if (theRelTarget == NVRenderTextureTargetType::Unknown) {
+ // detach renderbuffer
+ m_Backend->RenderTargetAttach(m_BufferHandle, attachment,
+ NVRenderBackend::NVRenderBackendRenderbufferObject(NULL));
+ } else {
+ // detach texture
+ m_Backend->RenderTargetAttach(m_BufferHandle, attachment,
+ NVRenderBackend::NVRenderBackendTextureObject(NULL),
+ theRelTarget);
+ }
+ m_Attachments[attachment] = buffer;
+ }
+
+ void NVRenderFrameBuffer::AttachLayer(NVRenderFrameBufferAttachments::Enum attachment,
+ NVRenderTextureOrRenderBuffer buffer, QT3DSI32 layer,
+ QT3DSI32 level)
+ {
+ if (attachment == NVRenderFrameBufferAttachments::Unknown
+ || attachment > NVRenderFrameBufferAttachments::LastAttachment) {
+ qCCritical(INVALID_PARAMETER, "Attachment out of range");
+ return;
+ }
+
+ // This function is only used for attaching a layer
+ // If texture exists probably something is wrong
+ if (!buffer.HasTexture2DArray()) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+
+ CheckAttachment(m_Context, attachment);
+ // Ensure we are the bound framebuffer
+ m_Context.SetRenderTarget(this);
+
+ // release previous attachments
+ NVRenderTextureTargetType::Enum theRelTarget = releaseAttachment(attachment);
+
+ // On the same attachment point there could be a something attached with a different target
+ // MSAA <--> NoMSAA
+ if (theRelTarget != NVRenderTextureTargetType::Unknown
+ && theRelTarget != NVRenderTextureTargetType::Texture2D_Array)
+ m_Backend->RenderTargetAttach(m_BufferHandle, attachment,
+ NVRenderBackend::NVRenderBackendTextureObject(NULL),
+ theRelTarget);
+
+ m_Backend->RenderTargetAttach(m_BufferHandle, attachment,
+ buffer.GetTexture2DArray()->GetTextureObjectHandle(), level,
+ layer);
+ buffer.GetTexture2DArray()->addRef();
+ m_AttachmentBits |= (1 << attachment);
+
+ m_Attachments[attachment] = buffer;
+ }
+
+ void NVRenderFrameBuffer::AttachFace(NVRenderFrameBufferAttachments::Enum attachment,
+ NVRenderTextureOrRenderBuffer buffer,
+ NVRenderTextureCubeFaces::Enum face)
+ {
+ if (attachment == NVRenderFrameBufferAttachments::Unknown
+ || attachment > NVRenderFrameBufferAttachments::LastAttachment) {
+ qCCritical(INVALID_PARAMETER, "Attachment out of range");
+ return;
+ }
+
+ if (face == NVRenderTextureCubeFaces::InvalidFace) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+
+ CheckAttachment(m_Context, attachment);
+ // Ensure we are the bound framebuffer
+ m_Context.SetRenderTarget(this);
+
+ // release previous attachments
+ NVRenderTextureTargetType::Enum attachTarget = static_cast<NVRenderTextureTargetType::Enum>(
+ (int)NVRenderTextureTargetType::TextureCube + (int)face);
+ NVRenderTextureTargetType::Enum 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 == NVRenderTextureTargetType::TextureCube && !buffer.HasTextureCube()) {
+ theRelTarget = attachTarget;
+ attachTarget = NVRenderTextureTargetType::Unknown;
+ } else if (theRelTarget == NVRenderTextureTargetType::TextureCube) {
+ theRelTarget = NVRenderTextureTargetType::Unknown;
+ }
+ if (theRelTarget != NVRenderTextureTargetType::Unknown) {
+ m_Backend->RenderTargetAttach(m_BufferHandle, attachment,
+ NVRenderBackend::NVRenderBackendTextureObject(NULL),
+ theRelTarget);
+ }
+
+ if (attachTarget != NVRenderTextureTargetType::Unknown) {
+ m_Backend->RenderTargetAttach(m_BufferHandle, attachment,
+ buffer.GetTextureCube()->GetTextureObjectHandle(),
+ attachTarget);
+ buffer.GetTextureCube()->addRef();
+ m_AttachmentBits |= (1 << attachment);
+ }
+
+ m_Attachments[attachment] = buffer;
+ }
+
+ bool NVRenderFrameBuffer::IsComplete()
+ {
+ // Ensure we are the bound framebuffer
+ m_Context.SetRenderTarget(this);
+
+ return m_Backend->RenderTargetIsValid(m_BufferHandle);
+ }
+}
+}
+
+qt3ds::render::NVRenderFrameBuffer *
+qt3ds::render::NVRenderFrameBuffer::Create(NVRenderContextImpl &context)
+{
+ return QT3DS_NEW(context.GetFoundation().getAllocator(),
+ NVRenderFrameBuffer)(context, context.GetFoundation());
+}