summaryrefslogtreecommitdiffstats
path: root/src/Runtime/Source/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/Source/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp')
-rw-r--r--src/Runtime/Source/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp2203
1 files changed, 2203 insertions, 0 deletions
diff --git a/src/Runtime/Source/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp b/src/Runtime/Source/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp
new file mode 100644
index 00000000..af3cb613
--- /dev/null
+++ b/src/Runtime/Source/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp
@@ -0,0 +1,2203 @@
+/****************************************************************************
+**
+** 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 "Qt3DSRender.h"
+#include "Qt3DSRenderer.h"
+#include "Qt3DSRendererImpl.h"
+#include "Qt3DSRenderLayer.h"
+#include "Qt3DSRenderEffect.h"
+#include "EASTL/sort.h"
+#include "Qt3DSRenderLight.h"
+#include "Qt3DSRenderCamera.h"
+#include "Qt3DSRenderScene.h"
+#include "Qt3DSRenderPresentation.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "Qt3DSRenderContextCore.h"
+#include "Qt3DSRenderResourceManager.h"
+#include "Qt3DSTextRenderer.h"
+#include "Qt3DSRenderEffectSystem.h"
+#include "render/Qt3DSRenderFrameBuffer.h"
+#include "render/Qt3DSRenderRenderBuffer.h"
+#include "Qt3DSOffscreenRenderKey.h"
+#include "Qt3DSRenderPlugin.h"
+#include "Qt3DSRenderPluginGraphObject.h"
+#include "Qt3DSRenderResourceBufferObjects.h"
+#include "foundation/Qt3DSPerfTimer.h"
+#include "foundation/AutoDeallocatorAllocator.h"
+#include "Qt3DSRenderMaterialHelpers.h"
+#include "Qt3DSRenderBufferManager.h"
+#include "Qt3DSRenderCustomMaterialSystem.h"
+#include "Qt3DSRenderTextTextureCache.h"
+#include "Qt3DSRenderTextTextureAtlas.h"
+#include "Qt3DSRenderRenderList.h"
+#include "Qt3DSRendererUtil.h"
+
+#ifdef WIN32
+#pragma warning(disable : 4355)
+#endif
+
+#define QT3DS_CACHED_POST_EFFECT
+const float QT3DS_DEGREES_TO_RADIANS = 0.0174532925199f;
+
+namespace qt3ds {
+namespace render {
+ using eastl::reverse;
+ using eastl::stable_sort;
+ using qt3ds::render::NVRenderContextScopedProperty;
+ using qt3ds::QT3DSVec2;
+
+ SLayerRenderData::SLayerRenderData(SLayer &inLayer, Qt3DSRendererImpl &inRenderer)
+ : SLayerRenderPreparationData(inLayer, inRenderer)
+ , m_LayerTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_TemporalAATexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerDepthTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerPrepassDepthTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerWidgetTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerSsaoTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerMultisampleTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerMultisamplePrepassDepthTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerMultisampleWidgetTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerCachedTexture(NULL)
+ , m_AdvancedBlendDrawTexture(NULL)
+ , m_AdvancedBlendBlendTexture(NULL)
+ , m_AdvancedModeDrawFB(NULL)
+ , m_AdvancedModeBlendFB(NULL)
+ , m_ProgressiveAAPassIndex(0)
+ , m_TemporalAAPassIndex(0)
+ , m_NonDirtyTemporalAAPassIndex(0)
+ , m_TextScale(1.0f)
+ , mRefCount(0)
+ , m_DepthBufferFormat(NVRenderTextureFormats::Unknown)
+ {
+ }
+
+ SLayerRenderData::~SLayerRenderData()
+ {
+ IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager());
+ if (m_LayerCachedTexture && m_LayerCachedTexture != m_LayerTexture)
+ theResourceManager.Release(*m_LayerCachedTexture);
+ if (m_AdvancedModeDrawFB) {
+ m_AdvancedModeDrawFB->release();
+ m_AdvancedModeDrawFB = NULL;
+ }
+ if (m_AdvancedModeBlendFB) {
+ m_AdvancedModeBlendFB->release();
+ m_AdvancedModeBlendFB = NULL;
+ }
+ if (m_AdvancedBlendBlendTexture)
+ m_AdvancedBlendBlendTexture = NULL;
+ if (m_AdvancedBlendDrawTexture)
+ m_AdvancedBlendDrawTexture = NULL;
+ }
+ void SLayerRenderData::PrepareForRender(const QSize &inViewportDimensions)
+ {
+ SLayerRenderPreparationData::PrepareForRender(inViewportDimensions);
+ SLayerRenderPreparationResult &thePrepResult(*m_LayerPrepResult);
+ IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager());
+ // at that time all values shoud be updated
+ m_Renderer.UpdateCbAoShadow(&m_Layer, m_Camera, m_LayerDepthTexture);
+
+ // Generate all necessary lighting keys
+
+ if (thePrepResult.m_Flags.WasLayerDataDirty()) {
+ m_ProgressiveAAPassIndex = 0;
+ }
+
+ // Get rid of the layer texture if we aren't rendering to texture this frame.
+ if (m_LayerTexture && !thePrepResult.m_Flags.ShouldRenderToTexture()) {
+ if (m_LayerCachedTexture && m_LayerCachedTexture != m_LayerTexture) {
+ theResourceManager.Release(*m_LayerCachedTexture);
+ m_LayerCachedTexture = NULL;
+ }
+
+ m_LayerTexture.ReleaseTexture();
+ m_LayerDepthTexture.ReleaseTexture();
+ m_LayerWidgetTexture.ReleaseTexture();
+ m_LayerSsaoTexture.ReleaseTexture();
+ m_LayerMultisampleTexture.ReleaseTexture();
+ m_LayerMultisamplePrepassDepthTexture.ReleaseTexture();
+ m_LayerMultisampleWidgetTexture.ReleaseTexture();
+ }
+
+ if (NeedsWidgetTexture() == false)
+ m_LayerWidgetTexture.ReleaseTexture();
+
+ if (m_LayerDepthTexture && !thePrepResult.m_Flags.RequiresDepthTexture())
+ m_LayerDepthTexture.ReleaseTexture();
+
+ if (m_LayerSsaoTexture && !thePrepResult.m_Flags.RequiresSsaoPass())
+ m_LayerSsaoTexture.ReleaseTexture();
+
+ m_Renderer.LayerNeedsFrameClear(*this);
+
+ // Clean up the texture cache if layer dimensions changed
+ if (inViewportDimensions.width() != m_previousDimensions.width()
+ || inViewportDimensions.height() != m_previousDimensions.height()) {
+ m_LayerTexture.ReleaseTexture();
+ m_LayerDepthTexture.ReleaseTexture();
+ m_LayerSsaoTexture.ReleaseTexture();
+ m_LayerWidgetTexture.ReleaseTexture();
+ m_LayerPrepassDepthTexture.ReleaseTexture();
+ m_TemporalAATexture.ReleaseTexture();
+ m_LayerMultisampleTexture.ReleaseTexture();
+ m_LayerMultisamplePrepassDepthTexture.ReleaseTexture();
+ m_LayerMultisampleWidgetTexture.ReleaseTexture();
+
+ m_previousDimensions.setWidth(inViewportDimensions.width());
+ m_previousDimensions.setHeight(inViewportDimensions.height());
+
+ theResourceManager.DestroyFreeSizedResources();
+
+ // Effect system uses different resource manager, so clean that up too
+ m_Renderer.GetQt3DSContext().GetEffectSystem().GetResourceManager()
+ .DestroyFreeSizedResources();
+ }
+ }
+
+ NVRenderTextureFormats::Enum SLayerRenderData::GetDepthBufferFormat()
+ {
+ if (m_DepthBufferFormat == NVRenderTextureFormats::Unknown) {
+ QT3DSU32 theExistingDepthBits = m_Renderer.GetContext().GetDepthBits();
+ QT3DSU32 theExistingStencilBits = m_Renderer.GetContext().GetStencilBits();
+ switch (theExistingDepthBits) {
+ case 32:
+ m_DepthBufferFormat = NVRenderTextureFormats::Depth32;
+ break;
+ case 24:
+ // check if we have stencil bits
+ if (theExistingStencilBits > 0)
+ m_DepthBufferFormat =
+ NVRenderTextureFormats::Depth24Stencil8; // currently no stencil usage
+ // should be Depth24Stencil8 in
+ // this case
+ else
+ m_DepthBufferFormat = NVRenderTextureFormats::Depth24;
+ break;
+ case 16:
+ m_DepthBufferFormat = NVRenderTextureFormats::Depth16;
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ m_DepthBufferFormat = NVRenderTextureFormats::Depth16;
+ break;
+ }
+ }
+ return m_DepthBufferFormat;
+ }
+
+ NVRenderFrameBufferAttachments::Enum
+ SLayerRenderData::GetFramebufferDepthAttachmentFormat(NVRenderTextureFormats::Enum depthFormat)
+ {
+ NVRenderFrameBufferAttachments::Enum fmt = NVRenderFrameBufferAttachments::Depth;
+
+ switch (depthFormat) {
+ case NVRenderTextureFormats::Depth16:
+ case NVRenderTextureFormats::Depth24:
+ case NVRenderTextureFormats::Depth32:
+ fmt = NVRenderFrameBufferAttachments::Depth;
+ break;
+ case NVRenderTextureFormats::Depth24Stencil8:
+ fmt = NVRenderFrameBufferAttachments::DepthStencil;
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+
+ return fmt;
+ }
+
+ void SLayerRenderData::RenderAoPass()
+ {
+ m_Renderer.BeginLayerDepthPassRender(*this);
+
+ NVRenderContext &theContext(m_Renderer.GetContext());
+ SDefaultAoPassShader *shader = m_Renderer.GetDefaultAoPassShader(GetShaderFeatureSet());
+ if (shader == NULL)
+ return;
+
+ // Set initial state
+ theContext.SetBlendingEnabled(false);
+ theContext.SetDepthWriteEnabled(false);
+ theContext.SetDepthTestEnabled(false);
+ theContext.SetActiveShader(&(shader->m_Shader));
+
+ // Setup constants
+ shader->m_CameraDirection.Set(m_CameraDirection);
+ shader->m_ViewMatrix.Set(m_Camera->m_GlobalTransform);
+
+ shader->m_DepthTexture.Set(m_LayerDepthTexture);
+ shader->m_DepthSamplerSize.Set(QT3DSVec2(m_LayerDepthTexture->GetTextureDetails().m_Width,
+ m_LayerDepthTexture->GetTextureDetails().m_Height));
+
+ // Important uniforms for AO calculations
+ QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar);
+ shader->m_CameraProperties.Set(theCameraProps);
+ shader->m_AoShadowParams.Set();
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+
+ m_Renderer.EndLayerDepthPassRender();
+ }
+
+ void SLayerRenderData::RenderFakeDepthMapPass(NVRenderTexture2D *theDepthTex,
+ NVRenderTextureCube *theDepthCube)
+ {
+ m_Renderer.BeginLayerDepthPassRender(*this);
+
+ NVRenderContext &theContext(m_Renderer.GetContext());
+ SDefaultAoPassShader *shader = theDepthTex
+ ? m_Renderer.GetFakeDepthShader(GetShaderFeatureSet())
+ : m_Renderer.GetFakeCubeDepthShader(GetShaderFeatureSet());
+ if (shader == NULL)
+ return;
+
+ // Set initial state
+ theContext.SetBlendingEnabled(false);
+ theContext.SetDepthWriteEnabled(false);
+ theContext.SetDepthTestEnabled(false);
+ theContext.SetActiveShader(&(shader->m_Shader));
+
+ // Setup constants
+ shader->m_CameraDirection.Set(m_CameraDirection);
+ shader->m_ViewMatrix.Set(m_Camera->m_GlobalTransform);
+
+ shader->m_DepthTexture.Set(theDepthTex);
+ shader->m_CubeTexture.Set(theDepthCube);
+ shader->m_DepthSamplerSize.Set(QT3DSVec2(theDepthTex->GetTextureDetails().m_Width,
+ theDepthTex->GetTextureDetails().m_Height));
+
+ // Important uniforms for AO calculations
+ QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar);
+ shader->m_CameraProperties.Set(theCameraProps);
+ shader->m_AoShadowParams.Set();
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+ }
+
+ namespace {
+
+ void computeFrustumBounds(const SCamera &inCamera, const NVRenderRectF &inViewPort,
+ QT3DSVec3 &ctrBound, QT3DSVec3 camVerts[8])
+ {
+ QT3DSVec3 camEdges[4];
+
+ const QT3DSF32 *dataPtr(inCamera.m_GlobalTransform.front());
+ QT3DSVec3 camX(dataPtr[0], dataPtr[1], dataPtr[2]);
+ QT3DSVec3 camY(dataPtr[4], dataPtr[5], dataPtr[6]);
+ QT3DSVec3 camZ(dataPtr[8], dataPtr[9], dataPtr[10]);
+
+ float tanFOV = tanf(inCamera.verticalFov(inViewPort) * 0.5f);
+ float asTanFOV = tanFOV * inViewPort.m_Width / inViewPort.m_Height;
+ camEdges[0] = -asTanFOV * camX + tanFOV * camY + camZ;
+ camEdges[1] = asTanFOV * camX + tanFOV * camY + camZ;
+ camEdges[2] = asTanFOV * camX - tanFOV * camY + camZ;
+ camEdges[3] = -asTanFOV * camX - tanFOV * camY + camZ;
+
+ for (int i = 0; i < 4; ++i) {
+ camEdges[i].x = -camEdges[i].x;
+ camEdges[i].y = -camEdges[i].y;
+ }
+
+ camVerts[0] = inCamera.m_Position + camEdges[0] * inCamera.m_ClipNear;
+ camVerts[1] = inCamera.m_Position + camEdges[0] * inCamera.m_ClipFar;
+ camVerts[2] = inCamera.m_Position + camEdges[1] * inCamera.m_ClipNear;
+ camVerts[3] = inCamera.m_Position + camEdges[1] * inCamera.m_ClipFar;
+ camVerts[4] = inCamera.m_Position + camEdges[2] * inCamera.m_ClipNear;
+ camVerts[5] = inCamera.m_Position + camEdges[2] * inCamera.m_ClipFar;
+ camVerts[6] = inCamera.m_Position + camEdges[3] * inCamera.m_ClipNear;
+ camVerts[7] = inCamera.m_Position + camEdges[3] * inCamera.m_ClipFar;
+
+ ctrBound = camVerts[0];
+ for (int i = 1; i < 8; ++i) {
+ ctrBound += camVerts[i];
+ }
+ ctrBound *= 0.125f;
+ }
+
+ void SetupCameraForShadowMap(const QT3DSVec2 &inCameraVec, NVRenderContext & /*inContext*/,
+ const NVRenderRectF &inViewport, const SCamera &inCamera,
+ const SLight *inLight, SCamera &theCamera)
+ {
+ // setup light matrix
+ QT3DSU32 mapRes = 1 << inLight->m_ShadowMapRes;
+ NVRenderRectF theViewport(0.0f, 0.0f, (float)mapRes, (float)mapRes);
+ theCamera.m_ClipNear = 1.0f;
+ theCamera.m_ClipFar = inLight->m_ShadowMapFar;
+ // Setup camera projection
+ QT3DSVec3 inLightPos = inLight->GetGlobalPos();
+ QT3DSVec3 inLightDir = inLight->GetDirection();
+
+ if (inLight->m_Flags.IsLeftHanded())
+ inLightPos.z = -inLightPos.z;
+
+ inLightPos -= inLightDir * inCamera.m_ClipNear;
+ theCamera.m_FOV = inLight->m_ShadowMapFov * QT3DS_DEGREES_TO_RADIANS;
+
+ if (inLight->m_LightType == RenderLightTypes::Directional) {
+ QT3DSVec3 frustBounds[8], boundCtr;
+ computeFrustumBounds(inCamera, inViewport, boundCtr, frustBounds);
+
+ QT3DSVec3 forward = inLightDir;
+ forward.normalize();
+ QT3DSVec3 right = forward.cross(QT3DSVec3(0, 1, 0));
+ right.normalize();
+ QT3DSVec3 up = right.cross(forward);
+ up.normalize();
+
+ // Calculate bounding box of the scene camera frustum
+ float minDistanceZ = std::numeric_limits<float>::max();
+ float maxDistanceZ = -std::numeric_limits<float>::max();
+ float minDistanceY = std::numeric_limits<float>::max();
+ float maxDistanceY = -std::numeric_limits<float>::max();
+ float minDistanceX = std::numeric_limits<float>::max();
+ float maxDistanceX = -std::numeric_limits<float>::max();
+ for (int i = 0; i < 8; ++i) {
+ float distanceZ = frustBounds[i].dot(forward);
+ if (distanceZ < minDistanceZ)
+ minDistanceZ = distanceZ;
+ if (distanceZ > maxDistanceZ)
+ maxDistanceZ = distanceZ;
+ float distanceY = frustBounds[i].dot(up);
+ if (distanceY < minDistanceY)
+ minDistanceY = distanceY;
+ if (distanceY > maxDistanceY)
+ maxDistanceY = distanceY;
+ float distanceX = frustBounds[i].dot(right);
+ if (distanceX < minDistanceX)
+ minDistanceX = distanceX;
+ if (distanceX > maxDistanceX)
+ maxDistanceX = distanceX;
+ }
+
+ // Apply bounding box parameters to shadow map camera projection matrix
+ // so that the whole scene is fit inside the shadow map
+ inLightPos = boundCtr;
+ theViewport.m_Height = abs(maxDistanceY - minDistanceY);
+ theViewport.m_Width = abs(maxDistanceX - minDistanceX);
+ theCamera.m_ClipNear = -abs(maxDistanceZ - minDistanceZ);
+ theCamera.m_ClipFar = abs(maxDistanceZ - minDistanceZ);
+ }
+
+ theCamera.m_Flags.SetLeftHanded(false);
+
+ theCamera.m_Flags.ClearOrSet(inLight->m_LightType == RenderLightTypes::Directional,
+ NodeFlagValues::Orthographic);
+ theCamera.m_Parent = NULL;
+ theCamera.m_Pivot = inLight->m_Pivot;
+
+ if (inLight->m_LightType != RenderLightTypes::Point) {
+ theCamera.LookAt(inLightPos, QT3DSVec3(0, 1.0, 0), inLightPos + inLightDir);
+ } else {
+ theCamera.LookAt(inLightPos, QT3DSVec3(0, 1.0, 0), QT3DSVec3(0, 0, 0));
+ }
+
+ theCamera.CalculateGlobalVariables(theViewport,
+ QT3DSVec2(theViewport.m_Width, theViewport.m_Height));
+ }
+ }
+
+ void SetupCubeShadowCameras(const SLight *inLight, SCamera inCameras[6])
+ {
+ // setup light matrix
+ QT3DSU32 mapRes = 1 << inLight->m_ShadowMapRes;
+ NVRenderRectF theViewport(0.0f, 0.0f, (float)mapRes, (float)mapRes);
+ QT3DSVec3 rotOfs[6];
+
+ QT3DS_ASSERT(inLight != NULL);
+ QT3DS_ASSERT(inLight->m_LightType != RenderLightTypes::Directional);
+
+ QT3DSVec3 inLightPos = inLight->GetGlobalPos();
+ if (inLight->m_Flags.IsLeftHanded())
+ inLightPos.z = -inLightPos.z;
+
+ rotOfs[0] = QT3DSVec3(0.f, -NVHalfPi, NVPi);
+ rotOfs[1] = QT3DSVec3(0.f, NVHalfPi, NVPi);
+ rotOfs[2] = QT3DSVec3(NVHalfPi, 0.f, 0.f);
+ rotOfs[3] = QT3DSVec3(-NVHalfPi, 0.f, 0.f);
+ rotOfs[4] = QT3DSVec3(0.f, NVPi, -NVPi);
+ rotOfs[5] = QT3DSVec3(0.f, 0.f, NVPi);
+
+ for (int i = 0; i < 6; ++i) {
+ inCameras[i].m_Flags.SetLeftHanded(false);
+
+ inCameras[i].m_Flags.ClearOrSet(false, NodeFlagValues::Orthographic);
+ inCameras[i].m_Parent = NULL;
+ inCameras[i].m_Pivot = inLight->m_Pivot;
+ inCameras[i].m_ClipNear = 1.0f;
+ inCameras[i].m_ClipFar = NVMax<QT3DSF32>(2.0f, inLight->m_ShadowMapFar);
+ inCameras[i].m_FOV = inLight->m_ShadowMapFov * QT3DS_DEGREES_TO_RADIANS;
+
+ inCameras[i].m_Position = inLightPos;
+ inCameras[i].m_Rotation = rotOfs[i];
+ inCameras[i].CalculateGlobalVariables(
+ theViewport, QT3DSVec2(theViewport.m_Width, theViewport.m_Height));
+ }
+
+ /*
+ if ( inLight->m_LightType == RenderLightTypes::Point ) return;
+
+ QT3DSVec3 viewDirs[6];
+ QT3DSVec3 viewUp[6];
+ QT3DSMat33 theDirMatrix( inLight->m_GlobalTransform.getUpper3x3() );
+
+ viewDirs[0] = theDirMatrix.transform( QT3DSVec3( 1.f, 0.f, 0.f ) );
+ viewDirs[2] = theDirMatrix.transform( QT3DSVec3( 0.f, -1.f, 0.f ) );
+ viewDirs[4] = theDirMatrix.transform( QT3DSVec3( 0.f, 0.f, 1.f ) );
+ viewDirs[0].normalize(); viewDirs[2].normalize(); viewDirs[4].normalize();
+ viewDirs[1] = -viewDirs[0];
+ viewDirs[3] = -viewDirs[2];
+ viewDirs[5] = -viewDirs[4];
+
+ viewUp[0] = viewDirs[2];
+ viewUp[1] = viewDirs[2];
+ viewUp[2] = viewDirs[5];
+ viewUp[3] = viewDirs[4];
+ viewUp[4] = viewDirs[2];
+ viewUp[5] = viewDirs[2];
+
+ for (int i = 0; i < 6; ++i)
+ {
+ inCameras[i].LookAt( inLightPos, viewUp[i], inLightPos + viewDirs[i] );
+ inCameras[i].CalculateGlobalVariables( theViewport, QT3DSVec2( theViewport.m_Width,
+ theViewport.m_Height ) );
+ }
+ */
+ }
+
+ inline void RenderRenderableShadowMapPass(SLayerRenderData &inData, SRenderableObject &inObject,
+ const QT3DSVec2 &inCameraProps, TShaderFeatureSet,
+ QT3DSU32 lightIndex, const SCamera &inCamera)
+ {
+ if (!inObject.m_RenderableFlags.IsShadowCaster())
+ return;
+
+ SShadowMapEntry *pEntry = inData.m_ShadowMapManager->GetShadowMapEntry(lightIndex);
+
+ if (inObject.m_RenderableFlags.IsDefaultMaterialMeshSubset())
+ static_cast<SSubsetRenderableBase &>(inObject).RenderShadowMapPass(
+ inCameraProps, inData.m_Lights[lightIndex], inCamera, pEntry);
+ else if (inObject.m_RenderableFlags.IsCustomMaterialMeshSubset()) {
+ static_cast<SSubsetRenderableBase &>(inObject).RenderShadowMapPass(
+ inCameraProps, inData.m_Lights[lightIndex], inCamera, pEntry);
+ } else if (inObject.m_RenderableFlags.IsPath()) {
+ static_cast<SPathRenderable &>(inObject).RenderShadowMapPass(
+ inCameraProps, inData.m_Lights[lightIndex], inCamera, pEntry);
+ }
+ }
+
+ void SLayerRenderData::RenderShadowCubeBlurPass(CResourceFrameBuffer *theFB,
+ NVRenderTextureCube *target0,
+ NVRenderTextureCube *target1, QT3DSF32 filterSz,
+ QT3DSF32 clipFar)
+ {
+ NVRenderContext &theContext(m_Renderer.GetContext());
+
+ SShadowmapPreblurShader *shaderX = m_Renderer.GetCubeShadowBlurXShader();
+ SShadowmapPreblurShader *shaderY = m_Renderer.GetCubeShadowBlurYShader();
+
+ if (shaderX == NULL)
+ return;
+ if (shaderY == NULL)
+ return;
+ // if ( theShader == NULL ) return;
+
+ // Enable drawing to 6 color attachment buffers for cubemap passes
+ qt3ds::QT3DSI32 buffers[6] = { 0, 1, 2, 3, 4, 5 };
+ qt3ds::foundation::NVConstDataRef<qt3ds::QT3DSI32> bufferList(buffers, 6);
+ theContext.SetDrawBuffers(bufferList);
+
+ // Attach framebuffer targets
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color0, *target1,
+ NVRenderTextureCubeFaces::CubePosX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color1, *target1,
+ NVRenderTextureCubeFaces::CubeNegX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color2, *target1,
+ NVRenderTextureCubeFaces::CubePosY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color3, *target1,
+ NVRenderTextureCubeFaces::CubeNegY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color4, *target1,
+ NVRenderTextureCubeFaces::CubePosZ);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color5, *target1,
+ NVRenderTextureCubeFaces::CubeNegZ);
+
+ // Set initial state
+ theContext.SetBlendingEnabled(false);
+ theContext.SetDepthWriteEnabled(false);
+ theContext.SetDepthTestEnabled(false);
+ // theContext.SetColorWritesEnabled(true);
+ theContext.SetActiveShader(&(shaderX->m_Shader));
+
+ shaderX->m_CameraProperties.Set(QT3DSVec2(filterSz, clipFar));
+ shaderX->m_DepthCube.Set(target0);
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+
+ theContext.SetActiveShader(&(shaderY->m_Shader));
+
+ // Lather, Rinse, and Repeat for the Y-blur pass
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color0, *target0,
+ NVRenderTextureCubeFaces::CubePosX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color1, *target0,
+ NVRenderTextureCubeFaces::CubeNegX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color2, *target0,
+ NVRenderTextureCubeFaces::CubePosY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color3, *target0,
+ NVRenderTextureCubeFaces::CubeNegY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color4, *target0,
+ NVRenderTextureCubeFaces::CubePosZ);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color5, *target0,
+ NVRenderTextureCubeFaces::CubeNegZ);
+
+ shaderY->m_CameraProperties.Set(QT3DSVec2(filterSz, clipFar));
+ shaderY->m_DepthCube.Set(target1);
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+
+ theContext.SetDepthWriteEnabled(true);
+ theContext.SetDepthTestEnabled(true);
+ // theContext.SetColorWritesEnabled(false);
+
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color0, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubePosX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color1, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubeNegX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color2, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubePosY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color3, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubeNegY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color4, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubePosZ);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color5, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubeNegZ);
+
+ theContext.SetDrawBuffers(qt3ds::foundation::toConstDataRef((qt3ds::QT3DSI32)0));
+ }
+
+ void SLayerRenderData::RenderShadowMapBlurPass(CResourceFrameBuffer *theFB,
+ NVRenderTexture2D *target0,
+ NVRenderTexture2D *target1, QT3DSF32 filterSz,
+ QT3DSF32 clipFar)
+ {
+ NVRenderContext &theContext(m_Renderer.GetContext());
+
+ SShadowmapPreblurShader *shaderX = m_Renderer.GetOrthoShadowBlurXShader();
+ SShadowmapPreblurShader *shaderY = m_Renderer.GetOrthoShadowBlurYShader();
+
+ if (shaderX == NULL)
+ return;
+ if (shaderY == NULL)
+ return;
+
+ // Attach framebuffer target
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Color0, *target1);
+ //(*theFB)->Attach( NVRenderFrameBufferAttachments::DepthStencil, *target1 );
+
+ // Set initial state
+ theContext.SetBlendingEnabled(false);
+ theContext.SetDepthWriteEnabled(false);
+ theContext.SetDepthTestEnabled(false);
+ theContext.SetColorWritesEnabled(true);
+ theContext.SetActiveShader(&(shaderX->m_Shader));
+
+ shaderX->m_CameraProperties.Set(QT3DSVec2(filterSz, clipFar));
+ shaderX->m_DepthMap.Set(target0);
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Color0, *target0);
+ //(*theFB)->Attach( NVRenderFrameBufferAttachments::DepthStencil, *target0 );
+ theContext.SetActiveShader(&(shaderY->m_Shader));
+
+ shaderY->m_CameraProperties.Set(QT3DSVec2(filterSz, clipFar));
+ shaderY->m_DepthMap.Set(target1);
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+
+ theContext.SetDepthWriteEnabled(true);
+ theContext.SetDepthTestEnabled(true);
+ theContext.SetColorWritesEnabled(false);
+
+ //(*theFB)->Attach( NVRenderFrameBufferAttachments::DepthStencil,
+ //NVRenderTextureOrRenderBuffer() );
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Color0, NVRenderTextureOrRenderBuffer());
+ }
+
+ void SLayerRenderData::RenderShadowMapPass(CResourceFrameBuffer *theFB)
+ {
+ SStackPerfTimer ___timer(m_Renderer.GetQt3DSContext().GetPerfTimer(),
+ "SLayerRenderData::RenderShadowMapPass");
+
+ if (m_Camera == NULL || !GetShadowMapManager())
+ return;
+
+ // Check if we have anything to render
+ if (m_OpaqueObjects.size() == 0 || m_Lights.size() == 0)
+ return;
+
+ m_Renderer.BeginLayerDepthPassRender(*this);
+
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+
+ // we may change the viewport
+ NVRenderContextScopedProperty<NVRenderRect> __viewport(
+ theRenderContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport);
+
+ // disable color writes
+ // theRenderContext.SetColorWritesEnabled( false );
+ theRenderContext.SetColorWritesEnabled(true);
+ theRenderContext.SetDepthWriteEnabled(true);
+ theRenderContext.SetCullingEnabled(false);
+ theRenderContext.SetClearColor(QT3DSVec4(1.0f));
+
+ // we render the shadow map with a slight offset to prevent shadow acne and cull the front
+ // faces
+ NVScopedRefCounted<qt3ds::render::NVRenderRasterizerState> rsdefaultstate =
+ theRenderContext.CreateRasterizerState(0.0, 0.0, qt3ds::render::NVRenderFaces::Back);
+ NVScopedRefCounted<qt3ds::render::NVRenderRasterizerState> rsstate =
+ theRenderContext.CreateRasterizerState(1.5, 2.0, qt3ds::render::NVRenderFaces::Front);
+ theRenderContext.SetRasterizerState(rsstate);
+
+ qt3ds::render::NVRenderClearFlags clearFlags(qt3ds::render::NVRenderClearValues::Depth
+ | qt3ds::render::NVRenderClearValues::Stencil
+ | qt3ds::render::NVRenderClearValues::Color);
+
+ for (QT3DSU32 i = 0; i < m_Lights.size(); i++) {
+ // don't render shadows when not casting
+ if (m_Lights[i]->m_CastShadow == false)
+ continue;
+ SShadowMapEntry *pEntry = m_ShadowMapManager->GetShadowMapEntry(i);
+ if (pEntry && pEntry->m_DepthMap && pEntry->m_DepthCopy && pEntry->m_DepthRender) {
+ SCamera theCamera;
+
+ QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar);
+ SetupCameraForShadowMap(theCameraProps, m_Renderer.GetContext(),
+ __viewport.m_InitialValue, *m_Camera,
+ m_Lights[i], theCamera);
+ // we need this matrix for the final rendering
+ theCamera.CalculateViewProjectionMatrix(pEntry->m_LightVP);
+ pEntry->m_LightView = theCamera.m_GlobalTransform.getInverse();
+
+ STextureDetails theDetails(pEntry->m_DepthMap->GetTextureDetails());
+ theRenderContext.SetViewport(
+ NVRenderRect(0, 0, (QT3DSU32)theDetails.m_Width, (QT3DSU32)theDetails.m_Height));
+
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Color0, *pEntry->m_DepthMap);
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::DepthStencil,
+ *pEntry->m_DepthRender);
+ theRenderContext.Clear(clearFlags);
+
+ RunRenderPass(RenderRenderableShadowMapPass, false, true, true, i, theCamera);
+ RenderShadowMapBlurPass(theFB, pEntry->m_DepthMap, pEntry->m_DepthCopy,
+ m_Lights[i]->m_ShadowFilter, m_Lights[i]->m_ShadowMapFar);
+ } else if (pEntry && pEntry->m_DepthCube && pEntry->m_CubeCopy
+ && pEntry->m_DepthRender) {
+ SCamera theCameras[6];
+
+ SetupCubeShadowCameras(m_Lights[i], theCameras);
+
+ // pEntry->m_LightView = m_Lights[i]->m_LightType == RenderLightTypes::Point ?
+ // QT3DSMat44::createIdentity()
+ // : m_Lights[i]->m_GlobalTransform;
+ pEntry->m_LightView = QT3DSMat44::createIdentity();
+
+ STextureDetails theDetails(pEntry->m_DepthCube->GetTextureDetails());
+ theRenderContext.SetViewport(
+ NVRenderRect(0, 0, (QT3DSU32)theDetails.m_Width, (QT3DSU32)theDetails.m_Height));
+
+ // int passes = m_Lights[i]->m_LightType == RenderLightTypes::Point ? 6 : 5;
+ int passes = 6;
+ for (int k = 0; k < passes; ++k) {
+ // theCameras[k].CalculateViewProjectionMatrix( pEntry->m_LightCubeVP[k] );
+ pEntry->m_LightCubeView[k] = theCameras[k].m_GlobalTransform.getInverse();
+ theCameras[k].CalculateViewProjectionMatrix(pEntry->m_LightVP);
+
+ // Geometry shader multiplication really doesn't work unless you have a
+ // 6-layered 3D depth texture...
+ // Otherwise, you have no way to depth test while rendering...
+ // which more or less completely defeats the purpose of having a cubemap render
+ // target.
+ NVRenderTextureCubeFaces::Enum curFace =
+ (NVRenderTextureCubeFaces::Enum)(k + 1);
+ //(*theFB)->AttachFace( NVRenderFrameBufferAttachments::DepthStencil,
+ //*pEntry->m_DepthCube, curFace );
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::DepthStencil,
+ *pEntry->m_DepthRender);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color0,
+ *pEntry->m_DepthCube, curFace);
+ (*theFB)->IsComplete();
+ theRenderContext.Clear(clearFlags);
+
+ RunRenderPass(RenderRenderableShadowMapPass, false, true, true, i,
+ theCameras[k]);
+ }
+
+ RenderShadowCubeBlurPass(theFB, pEntry->m_DepthCube, pEntry->m_CubeCopy,
+ m_Lights[i]->m_ShadowFilter, m_Lights[i]->m_ShadowMapFar);
+ }
+ }
+
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Depth, NVRenderTextureOrRenderBuffer());
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Color0, NVRenderTextureOrRenderBuffer());
+
+ // enable color writes
+ theRenderContext.SetColorWritesEnabled(true);
+ theRenderContext.SetCullingEnabled(true);
+ theRenderContext.SetClearColor(QT3DSVec4(0.0f));
+ // reset rasterizer state
+ theRenderContext.SetRasterizerState(rsdefaultstate);
+
+ m_Renderer.EndLayerDepthPassRender();
+ }
+
+ inline void RenderRenderableDepthPass(SLayerRenderData &inData, SRenderableObject &inObject,
+ const QT3DSVec2 &inCameraProps, TShaderFeatureSet, QT3DSU32,
+ const SCamera &inCamera)
+ {
+ if (inObject.m_RenderableFlags.IsDefaultMaterialMeshSubset())
+ static_cast<SSubsetRenderable &>(inObject).RenderDepthPass(inCameraProps);
+ else if (inObject.m_RenderableFlags.IsText())
+ static_cast<STextRenderable &>(inObject).RenderDepthPass(inCameraProps);
+ else if (inObject.m_RenderableFlags.IsCustomMaterialMeshSubset()) {
+ static_cast<SCustomMaterialRenderable &>(inObject).RenderDepthPass(
+ inCameraProps, inData.m_Layer, inData.m_Lights, inCamera, NULL);
+ } else if (inObject.m_RenderableFlags.IsPath()) {
+ static_cast<SPathRenderable &>(inObject).RenderDepthPass(
+ inCameraProps, inData.m_Layer, inData.m_Lights, inCamera, NULL);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+
+ void SLayerRenderData::RenderDepthPass(bool inEnableTransparentDepthWrite)
+ {
+ SStackPerfTimer ___timer(m_Renderer.GetQt3DSContext().GetPerfTimer(),
+ "SLayerRenderData::RenderDepthPass");
+ if (m_Camera == NULL)
+ return;
+
+ // Avoid running this method if possible.
+ if ((inEnableTransparentDepthWrite == false
+ && (m_OpaqueObjects.size() == 0
+ || m_Layer.m_Flags.IsLayerEnableDepthPrepass() == false))
+ || m_Layer.m_Flags.IsLayerEnableDepthTest() == false)
+ return;
+
+ m_Renderer.BeginLayerDepthPassRender(*this);
+
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+
+ // disable color writes
+ theRenderContext.SetColorWritesEnabled(false);
+ theRenderContext.SetDepthWriteEnabled(true);
+
+ qt3ds::render::NVRenderClearFlags clearFlags(qt3ds::render::NVRenderClearValues::Stencil
+ | qt3ds::render::NVRenderClearValues::Depth);
+ theRenderContext.Clear(clearFlags);
+
+ RunRenderPass(RenderRenderableDepthPass, false, true, inEnableTransparentDepthWrite, 0,
+ *m_Camera);
+
+ // enable color writes
+ theRenderContext.SetColorWritesEnabled(true);
+
+ m_Renderer.EndLayerDepthPassRender();
+ }
+
+ inline void RenderRenderable(SLayerRenderData &inData, SRenderableObject &inObject,
+ const QT3DSVec2 &inCameraProps, TShaderFeatureSet inFeatureSet, QT3DSU32,
+ const SCamera &inCamera)
+ {
+ if (inObject.m_RenderableFlags.IsDefaultMaterialMeshSubset())
+ static_cast<SSubsetRenderable &>(inObject).Render(inCameraProps, inFeatureSet);
+ else if (inObject.m_RenderableFlags.IsText())
+ static_cast<STextRenderable &>(inObject).Render(inCameraProps);
+ else if (inObject.m_RenderableFlags.IsCustomMaterialMeshSubset()) {
+ // PKC : Need a better place to do this.
+ SCustomMaterialRenderable &theObject =
+ static_cast<SCustomMaterialRenderable &>(inObject);
+ if (!inData.m_Layer.m_LightProbe && theObject.m_Material.m_IblProbe)
+ inData.SetShaderFeature("QT3DS_ENABLE_LIGHT_PROBE",
+ theObject.m_Material.m_IblProbe->m_TextureData.m_Texture
+ != NULL);
+ else if (inData.m_Layer.m_LightProbe)
+ inData.SetShaderFeature("QT3DS_ENABLE_LIGHT_PROBE",
+ inData.m_Layer.m_LightProbe->m_TextureData.m_Texture
+ != NULL);
+
+ static_cast<SCustomMaterialRenderable &>(inObject).Render(
+ inCameraProps, inData, inData.m_Layer, inData.m_Lights, inCamera,
+ inData.m_LayerDepthTexture, inData.m_LayerSsaoTexture, inFeatureSet);
+ } else if (inObject.m_RenderableFlags.IsPath()) {
+ static_cast<SPathRenderable &>(inObject).Render(
+ inCameraProps, inData.m_Layer, inData.m_Lights, inCamera,
+ inData.m_LayerDepthTexture, inData.m_LayerSsaoTexture, inFeatureSet);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+
+ void SLayerRenderData::RunRenderPass(TRenderRenderableFunction inRenderFn,
+ bool inEnableBlending, bool inEnableDepthWrite,
+ bool inEnableTransparentDepthWrite, QT3DSU32 indexLight,
+ const SCamera &inCamera, CResourceFrameBuffer *theFB)
+ {
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+ theRenderContext.SetDepthFunction(qt3ds::render::NVRenderBoolOp::LessThanOrEqual);
+ theRenderContext.SetBlendingEnabled(false);
+ QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar);
+ NVDataRef<SRenderableObject *> theOpaqueObjects = GetOpaqueRenderableObjects();
+ bool usingDepthBuffer =
+ m_Layer.m_Flags.IsLayerEnableDepthTest() && theOpaqueObjects.size() > 0;
+
+ if (usingDepthBuffer) {
+ theRenderContext.SetDepthTestEnabled(true);
+ theRenderContext.SetDepthWriteEnabled(inEnableDepthWrite);
+ } else {
+ theRenderContext.SetDepthWriteEnabled(false);
+ theRenderContext.SetDepthTestEnabled(false);
+ }
+
+ for (QT3DSU32 idx = 0, end = theOpaqueObjects.size(); idx < end; ++idx) {
+ SRenderableObject &theObject(*theOpaqueObjects[idx]);
+ SScopedLightsListScope lightsScope(m_Lights, m_LightDirections, m_SourceLightDirections,
+ theObject.m_ScopedLights);
+ SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false);
+ inRenderFn(*this, theObject, theCameraProps, GetShaderFeatureSet(), indexLight,
+ inCamera);
+ }
+
+ // transparent objects
+ if (inEnableBlending || m_Layer.m_Flags.IsLayerEnableDepthTest() == false) {
+ theRenderContext.SetBlendingEnabled(true && inEnableBlending);
+ theRenderContext.SetDepthWriteEnabled(inEnableTransparentDepthWrite);
+
+ NVDataRef<SRenderableObject *> theTransparentObjects = GetTransparentRenderableObjects();
+ // Assume all objects have transparency if the layer's depth test enabled flag is true.
+ if (m_Layer.m_Flags.IsLayerEnableDepthTest() == true) {
+ for (QT3DSU32 idx = 0, end = theTransparentObjects.size(); idx < end; ++idx) {
+ SRenderableObject &theObject(*theTransparentObjects[idx]);
+ if (!(theObject.m_RenderableFlags.IsCompletelyTransparent())) {
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ // SW fallback for advanced blend modes.
+ // Renders transparent objects to a separate FBO and blends them in shader
+ // with the opaque items and background.
+ DefaultMaterialBlendMode::Enum blendMode
+ = DefaultMaterialBlendMode::Enum::Normal;
+ if (theObject.m_RenderableFlags.IsDefaultMaterialMeshSubset())
+ blendMode = static_cast<SSubsetRenderable &>(theObject).getBlendingMode();
+ bool useBlendFallback = (blendMode == DefaultMaterialBlendMode::Overlay ||
+ blendMode == DefaultMaterialBlendMode::ColorBurn ||
+ blendMode == DefaultMaterialBlendMode::ColorDodge) &&
+ !theRenderContext.IsAdvancedBlendHwSupported() &&
+ !theRenderContext.IsAdvancedBlendHwSupportedKHR() &&
+ m_LayerPrepassDepthTexture;
+ if (useBlendFallback)
+ SetupDrawFB(true);
+#endif
+ SScopedLightsListScope lightsScope(m_Lights, m_LightDirections,
+ m_SourceLightDirections,
+ theObject.m_ScopedLights);
+ SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false);
+
+ inRenderFn(*this, theObject, theCameraProps, GetShaderFeatureSet(),
+ indexLight, inCamera);
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ // SW fallback for advanced blend modes.
+ // Continue blending after transparent objects have been rendered to a FBO
+ if (useBlendFallback) {
+ BlendAdvancedToFB(blendMode, true, theFB);
+ // restore blending status
+ theRenderContext.SetBlendingEnabled(inEnableBlending);
+ // restore depth test status
+ theRenderContext.SetDepthTestEnabled(usingDepthBuffer);
+ theRenderContext.SetDepthWriteEnabled(inEnableTransparentDepthWrite);
+ }
+#endif
+ }
+ }
+ }
+ // If the layer doesn't have depth enabled then we have to render via an alternate route
+ // where the transparent objects vector could have both opaque and transparent objects.
+ else {
+ for (QT3DSU32 idx = 0, end = theTransparentObjects.size(); idx < end; ++idx) {
+ SRenderableObject &theObject(*theTransparentObjects[idx]);
+ if (!(theObject.m_RenderableFlags.IsCompletelyTransparent())) {
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ DefaultMaterialBlendMode::Enum blendMode
+ = DefaultMaterialBlendMode::Enum::Normal;
+ if (theObject.m_RenderableFlags.IsDefaultMaterialMeshSubset())
+ blendMode = static_cast<SSubsetRenderable &>(theObject).getBlendingMode();
+ bool useBlendFallback = (blendMode == DefaultMaterialBlendMode::Overlay ||
+ blendMode == DefaultMaterialBlendMode::ColorBurn ||
+ blendMode == DefaultMaterialBlendMode::ColorDodge) &&
+ !theRenderContext.IsAdvancedBlendHwSupported() &&
+ !theRenderContext.IsAdvancedBlendHwSupportedKHR();
+
+ if (theObject.m_RenderableFlags.HasTransparency()) {
+ theRenderContext.SetBlendingEnabled(true && inEnableBlending);
+ // If we have SW fallback for blend mode, render to a FBO and blend back.
+ // Slow as this must be done per-object (transparent and opaque items
+ // are mixed, not batched)
+ if (useBlendFallback)
+ SetupDrawFB(false);
+ }
+#endif
+ SScopedLightsListScope lightsScope(m_Lights, m_LightDirections,
+ m_SourceLightDirections,
+ theObject.m_ScopedLights);
+ SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false);
+ inRenderFn(*this, theObject, theCameraProps, GetShaderFeatureSet(),
+ indexLight, inCamera);
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ if (useBlendFallback) {
+ BlendAdvancedToFB(blendMode, false, theFB);
+ // restore blending status
+ theRenderContext.SetBlendingEnabled(inEnableBlending);
+
+ }
+#endif
+ }
+ }
+ }
+ }
+ }
+
+ void SLayerRenderData::Render(CResourceFrameBuffer *theFB)
+ {
+ SStackPerfTimer ___timer(m_Renderer.GetQt3DSContext().GetPerfTimer(),
+ "SLayerRenderData::Render");
+ if (m_Camera == NULL)
+ return;
+
+ m_Renderer.BeginLayerRender(*this);
+ RunRenderPass(RenderRenderable, true, !m_Layer.m_Flags.IsLayerEnableDepthPrepass(), false,
+ 0, *m_Camera, theFB);
+ m_Renderer.EndLayerRender();
+ }
+
+ void SLayerRenderData::CreateGpuProfiler()
+ {
+ if (m_Renderer.GetContext().IsTimerQuerySupported()) {
+ m_LayerProfilerGpu = IRenderProfiler::CreateGpuProfiler(
+ m_Renderer.GetContext().GetFoundation(), m_Renderer.GetQt3DSContext(),
+ m_Renderer.GetContext());
+ }
+ }
+
+ void SLayerRenderData::StartProfiling(CRegisteredString &nameID, bool sync)
+ {
+ if (m_LayerProfilerGpu.mPtr) {
+ m_LayerProfilerGpu->StartTimer(nameID, false, sync);
+ }
+ }
+
+ void SLayerRenderData::EndProfiling(CRegisteredString &nameID)
+ {
+ if (m_LayerProfilerGpu.mPtr) {
+ m_LayerProfilerGpu->EndTimer(nameID);
+ }
+ }
+
+ void SLayerRenderData::StartProfiling(const char *nameID, bool sync)
+ {
+ if (m_LayerProfilerGpu.mPtr) {
+ CRegisteredString theStr(
+ m_Renderer.GetQt3DSContext().GetStringTable().RegisterStr(nameID));
+ m_LayerProfilerGpu->StartTimer(theStr, false, sync);
+ }
+ }
+
+ void SLayerRenderData::EndProfiling(const char *nameID)
+ {
+ if (m_LayerProfilerGpu.mPtr) {
+ CRegisteredString theStr(
+ m_Renderer.GetQt3DSContext().GetStringTable().RegisterStr(nameID));
+ m_LayerProfilerGpu->EndTimer(theStr);
+ }
+ }
+
+ void SLayerRenderData::AddVertexCount(QT3DSU32 count)
+ {
+ if (m_LayerProfilerGpu.mPtr) {
+ m_LayerProfilerGpu->AddVertexCount(count);
+ }
+ }
+
+ // Assumes the viewport is setup appropriately to render the widget.
+ void SLayerRenderData::RenderRenderWidgets()
+ {
+ if (m_Camera) {
+ NVRenderContext &theContext(m_Renderer.GetContext());
+ for (QT3DSU32 idx = 0, end = m_IRenderWidgets.size(); idx < end; ++idx) {
+ IRenderWidget &theWidget = *m_IRenderWidgets[idx];
+ theWidget.Render(m_Renderer, theContext);
+ }
+ }
+ }
+
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ void SLayerRenderData::BlendAdvancedEquationSwFallback(NVRenderTexture2D *drawTexture,
+ NVRenderTexture2D *layerTexture,
+ AdvancedBlendModes::Enum blendMode)
+ {
+ NVRenderContext &theContext(m_Renderer.GetContext());
+ SAdvancedModeBlendShader *shader = m_Renderer.GetAdvancedBlendModeShader(blendMode);
+ if (shader == NULL)
+ return;
+
+ theContext.SetActiveShader(&(shader->m_Shader));
+
+ shader->m_baseLayer.Set(layerTexture);
+ shader->m_blendLayer.Set(drawTexture);
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+ }
+
+ void SLayerRenderData::SetupDrawFB(bool depthEnabled)
+ {
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+ // create drawing FBO and texture, if not existing
+ if (!m_AdvancedModeDrawFB)
+ m_AdvancedModeDrawFB = theRenderContext.CreateFrameBuffer();
+ if (!m_AdvancedBlendDrawTexture) {
+ m_AdvancedBlendDrawTexture = theRenderContext.CreateTexture2D();
+ NVRenderRect theViewport = m_Renderer.GetQt3DSContext().GetRenderList().GetViewport();
+ m_AdvancedBlendDrawTexture->SetTextureData(NVDataRef<QT3DSU8>(), 0,
+ theViewport.m_Width,
+ theViewport.m_Height,
+ NVRenderTextureFormats::RGBA8);
+ m_AdvancedModeDrawFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ *m_AdvancedBlendDrawTexture);
+ // Use existing depth prepass information when rendering transparent objects to a FBO
+ if (depthEnabled)
+ m_AdvancedModeDrawFB->Attach(NVRenderFrameBufferAttachments::Depth,
+ *m_LayerPrepassDepthTexture);
+ }
+ theRenderContext.SetRenderTarget(m_AdvancedModeDrawFB);
+ // make sure that depth testing is on in order to render just the
+ // depth-passed objects (=transparent objects) and leave background intact
+ if (depthEnabled)
+ theRenderContext.SetDepthTestEnabled(true);
+ theRenderContext.SetBlendingEnabled(false);
+ // clear color commonly is the layer background, make sure that it is all-zero here
+ QT3DSVec4 originalClrColor = theRenderContext.GetClearColor();
+ theRenderContext.SetClearColor(QT3DSVec4(0.0));
+ theRenderContext.Clear(NVRenderClearValues::Color);
+ theRenderContext.SetClearColor(originalClrColor);
+
+ }
+ void SLayerRenderData::BlendAdvancedToFB(DefaultMaterialBlendMode::Enum blendMode,
+ bool depthEnabled, CResourceFrameBuffer *theFB)
+ {
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+ NVRenderRect theViewport = m_Renderer.GetQt3DSContext().GetRenderList().GetViewport();
+ AdvancedBlendModes::Enum advancedMode;
+
+ switch (blendMode) {
+ case DefaultMaterialBlendMode::Overlay:
+ advancedMode = AdvancedBlendModes::Overlay;
+ break;
+ case DefaultMaterialBlendMode::ColorBurn:
+ advancedMode = AdvancedBlendModes::ColorBurn;
+ break;
+ case DefaultMaterialBlendMode::ColorDodge:
+ advancedMode = AdvancedBlendModes::ColorDodge;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ // create blending FBO and texture if not existing
+ if (!m_AdvancedModeBlendFB)
+ m_AdvancedModeBlendFB = theRenderContext.CreateFrameBuffer();
+ if (!m_AdvancedBlendBlendTexture) {
+ m_AdvancedBlendBlendTexture = theRenderContext.CreateTexture2D();
+ m_AdvancedBlendBlendTexture->SetTextureData(NVDataRef<QT3DSU8>(), 0,
+ theViewport.m_Width,
+ theViewport.m_Height,
+ NVRenderTextureFormats::RGBA8);
+ m_AdvancedModeBlendFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ *m_AdvancedBlendBlendTexture);
+ }
+ theRenderContext.SetRenderTarget(m_AdvancedModeBlendFB);
+
+ // Blend transparent objects with SW fallback shaders.
+ // Disable depth testing as transparent objects have already been
+ // depth-checked; here we want to run shader for all layer pixels
+ if (depthEnabled)
+ {
+ theRenderContext.SetDepthTestEnabled(false);
+ theRenderContext.SetDepthWriteEnabled(false);
+ }
+ BlendAdvancedEquationSwFallback(m_AdvancedBlendDrawTexture, m_LayerTexture, advancedMode);
+ theRenderContext.SetRenderTarget(*theFB);
+ // setup read target
+ theRenderContext.SetReadTarget(m_AdvancedModeBlendFB);
+ theRenderContext.SetReadBuffer(NVReadFaces::Color0);
+ theRenderContext.BlitFramebuffer(0, 0, theViewport.m_Width, theViewport.m_Height,
+ 0, 0, theViewport.m_Width, theViewport.m_Height,
+ NVRenderClearValues::Color,
+ NVRenderTextureMagnifyingOp::Nearest);
+ }
+#endif
+
+ void SLayerRenderData::RenderToViewport()
+ {
+ if (m_LayerPrepResult->IsLayerVisible()) {
+ if (GetOffscreenRenderer()) {
+ if (m_Layer.m_Background == LayerBackground::Color) {
+ m_LastFrameOffscreenRenderer->RenderWithClear(
+ CreateOffscreenRenderEnvironment(), m_Renderer.GetContext(),
+ m_Renderer.GetQt3DSContext().GetPresentationScaleFactor(),
+ SScene::AlwaysClear, m_Layer.m_ClearColor, &m_Layer);
+ } else {
+ m_LastFrameOffscreenRenderer->Render(
+ CreateOffscreenRenderEnvironment(), m_Renderer.GetContext(),
+ m_Renderer.GetQt3DSContext().GetPresentationScaleFactor(),
+ SScene::ClearIsOptional, &m_Layer);
+ }
+ } else {
+ RenderDepthPass(false);
+ Render();
+ RenderRenderWidgets();
+ }
+ }
+ }
+ // These are meant to be pixel offsets, so you need to divide them by the width/height
+ // of the layer respectively.
+ const QT3DSVec2 s_VertexOffsets[SLayerRenderPreparationData::MAX_AA_LEVELS] = {
+ QT3DSVec2(-0.170840f, -0.553840f), // 1x
+ QT3DSVec2(0.162960f, -0.319340f), // 2x
+ QT3DSVec2(0.360260f, -0.245840f), // 3x
+ QT3DSVec2(-0.561340f, -0.149540f), // 4x
+ QT3DSVec2(0.249460f, 0.453460f), // 5x
+ QT3DSVec2(-0.336340f, 0.378260f), // 6x
+ QT3DSVec2(0.340000f, 0.166260f), // 7x
+ QT3DSVec2(0.235760f, 0.527760f), // 8x
+ };
+
+ // Blend factors are in the form of (frame blend factor, accumulator blend factor)
+ const QT3DSVec2 s_BlendFactors[SLayerRenderPreparationData::MAX_AA_LEVELS] = {
+ QT3DSVec2(0.500000f, 0.500000f), // 1x
+ QT3DSVec2(0.333333f, 0.666667f), // 2x
+ QT3DSVec2(0.250000f, 0.750000f), // 3x
+ QT3DSVec2(0.200000f, 0.800000f), // 4x
+ QT3DSVec2(0.166667f, 0.833333f), // 5x
+ QT3DSVec2(0.142857f, 0.857143f), // 6x
+ QT3DSVec2(0.125000f, 0.875000f), // 7x
+ QT3DSVec2(0.111111f, 0.888889f), // 8x
+ };
+
+ const QT3DSVec2 s_TemporalVertexOffsets[SLayerRenderPreparationData::MAX_TEMPORAL_AA_LEVELS] = {
+ QT3DSVec2(.3f, .3f), QT3DSVec2(-.3f, -.3f)
+ };
+
+ static inline void OffsetProjectionMatrix(QT3DSMat44 &inProjectionMatrix, QT3DSVec2 inVertexOffsets)
+ {
+ inProjectionMatrix.column3.x =
+ inProjectionMatrix.column3.x + inProjectionMatrix.column3.w * inVertexOffsets.x;
+ inProjectionMatrix.column3.y =
+ inProjectionMatrix.column3.y + inProjectionMatrix.column3.w * inVertexOffsets.y;
+ }
+
+ CRegisteredString depthPassStr;
+
+ // Render this layer's data to a texture. Required if we have any effects,
+ // prog AA, or if forced.
+ void SLayerRenderData::RenderToTexture()
+ {
+ QT3DS_ASSERT(m_LayerPrepResult->m_Flags.ShouldRenderToTexture());
+ SLayerRenderPreparationResult &thePrepResult(*m_LayerPrepResult);
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+ QSize theLayerTextureDimensions = thePrepResult.GetTextureDimensions();
+ QSize theLayerOriginalTextureDimensions = theLayerTextureDimensions;
+ NVRenderTextureFormats::Enum DepthTextureFormat = NVRenderTextureFormats::Depth24Stencil8;
+ NVRenderTextureFormats::Enum ColorTextureFormat = NVRenderTextureFormats::RGBA8;
+ if (thePrepResult.m_LastEffect
+ && theRenderContext.GetRenderContextType() != NVRenderContextValues::GLES2) {
+ if (m_Layer.m_Background != LayerBackground::Transparent)
+ ColorTextureFormat = NVRenderTextureFormats::R11G11B10;
+ else
+ ColorTextureFormat = NVRenderTextureFormats::RGBA16F;
+ }
+ NVRenderTextureFormats::Enum ColorSSAOTextureFormat = NVRenderTextureFormats::RGBA8;
+
+ bool needsRender = false;
+ QT3DSU32 sampleCount = 1;
+ // check multsample mode and MSAA texture support
+ if (m_Layer.m_MultisampleAAMode != AAModeValues::NoAA
+ && theRenderContext.AreMultisampleTexturesSupported())
+ sampleCount = (QT3DSU32)m_Layer.m_MultisampleAAMode;
+
+ bool isMultisamplePass = false;
+ if (theRenderContext.GetRenderContextType() != NVRenderContextValues::GLES2)
+ isMultisamplePass =
+ (sampleCount > 1) || (m_Layer.m_MultisampleAAMode == AAModeValues::SSAA);
+
+ qt3ds::render::NVRenderTextureTargetType::Enum thFboAttachTarget =
+ qt3ds::render::NVRenderTextureTargetType::Texture2D;
+
+ // If the user has disabled all layer caching this has the side effect of disabling the
+ // progressive AA algorithm.
+ if (thePrepResult.m_Flags.WasLayerDataDirty()
+ || thePrepResult.m_Flags.WasDirty()
+ || m_Renderer.IsLayerCachingEnabled() == false
+ || thePrepResult.m_Flags.ShouldRenderToTexture()) {
+ m_ProgressiveAAPassIndex = 0;
+ m_NonDirtyTemporalAAPassIndex = 0;
+ needsRender = true;
+ }
+
+ CResourceTexture2D *renderColorTexture = &m_LayerTexture;
+ CResourceTexture2D *renderPrepassDepthTexture = &m_LayerPrepassDepthTexture;
+ CResourceTexture2D *renderWidgetTexture = &m_LayerWidgetTexture;
+ NVRenderContextScopedProperty<bool> __multisampleEnabled(
+ theRenderContext, &NVRenderContext::IsMultisampleEnabled,
+ &NVRenderContext::SetMultisampleEnabled);
+ theRenderContext.SetMultisampleEnabled(false);
+ if (isMultisamplePass) {
+ renderColorTexture = &m_LayerMultisampleTexture;
+ renderPrepassDepthTexture = &m_LayerMultisamplePrepassDepthTexture;
+ renderWidgetTexture = &m_LayerMultisampleWidgetTexture;
+ // for SSAA we don't use MS textures
+ if (m_Layer.m_MultisampleAAMode != AAModeValues::SSAA)
+ thFboAttachTarget = qt3ds::render::NVRenderTextureTargetType::Texture2D_MS;
+ }
+ QT3DSU32 maxTemporalPassIndex = m_Layer.m_TemporalAAEnabled ? 2 : 0;
+
+ // If all the dimensions match then we do not have to re-render the layer.
+ if (m_LayerTexture.TextureMatches(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(), ColorTextureFormat)
+ && (!thePrepResult.m_Flags.RequiresDepthTexture()
+ || m_LayerDepthTexture.TextureMatches(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ DepthTextureFormat))
+ && m_ProgressiveAAPassIndex >= thePrepResult.m_MaxAAPassIndex
+ && m_NonDirtyTemporalAAPassIndex >= maxTemporalPassIndex && needsRender == false) {
+ return;
+ }
+
+ // adjust render size for SSAA
+ if (m_Layer.m_MultisampleAAMode == AAModeValues::SSAA) {
+ QT3DSU32 ow, oh;
+ CRendererUtil::GetSSAARenderSize(theLayerOriginalTextureDimensions.width(),
+ theLayerOriginalTextureDimensions.height(),
+ ow, oh);
+ theLayerTextureDimensions = QSize(ow, oh);
+ }
+
+ // If our pass index == thePreResult.m_MaxAAPassIndex then
+ // we shouldn't get into here.
+
+ IResourceManager &theResourceManager = m_Renderer.GetQt3DSContext().GetResourceManager();
+ bool hadLayerTexture = true;
+
+ if (renderColorTexture->EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ ColorTextureFormat, sampleCount)) {
+ m_ProgressiveAAPassIndex = 0;
+ m_NonDirtyTemporalAAPassIndex = 0;
+ hadLayerTexture = false;
+ }
+
+ if (thePrepResult.m_Flags.RequiresDepthTexture()) {
+ // The depth texture doesn't need to be multisample, the prepass depth does.
+ if (m_LayerDepthTexture.EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ DepthTextureFormat)) {
+ // Depth textures are generally not bilinear filtered.
+ m_LayerDepthTexture->SetMinFilter(NVRenderTextureMinifyingOp::Nearest);
+ m_LayerDepthTexture->SetMagFilter(NVRenderTextureMagnifyingOp::Nearest);
+ m_ProgressiveAAPassIndex = 0;
+ m_NonDirtyTemporalAAPassIndex = 0;
+ }
+ }
+
+ if (thePrepResult.m_Flags.RequiresSsaoPass()) {
+ if (m_LayerSsaoTexture.EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ ColorSSAOTextureFormat)) {
+ m_LayerSsaoTexture->SetMinFilter(NVRenderTextureMinifyingOp::Linear);
+ m_LayerSsaoTexture->SetMagFilter(NVRenderTextureMagnifyingOp::Linear);
+ m_ProgressiveAAPassIndex = 0;
+ m_NonDirtyTemporalAAPassIndex = 0;
+ }
+ }
+
+ QT3DS_ASSERT(!thePrepResult.m_Flags.RequiresDepthTexture() || m_LayerDepthTexture);
+ QT3DS_ASSERT(!thePrepResult.m_Flags.RequiresSsaoPass() || m_LayerSsaoTexture);
+
+ CResourceTexture2D theLastLayerTexture(theResourceManager);
+ SLayerProgAABlendShader *theBlendShader = NULL;
+ QT3DSU32 aaFactorIndex = 0;
+ bool isProgressiveAABlendPass =
+ m_ProgressiveAAPassIndex && m_ProgressiveAAPassIndex < thePrepResult.m_MaxAAPassIndex;
+ bool isTemporalAABlendPass = m_Layer.m_TemporalAAEnabled && m_ProgressiveAAPassIndex == 0;
+
+ if (isProgressiveAABlendPass || isTemporalAABlendPass) {
+ theBlendShader = m_Renderer.GetLayerProgAABlendShader();
+ if (theBlendShader) {
+ m_LayerTexture.EnsureTexture(theLayerOriginalTextureDimensions.width(),
+ theLayerOriginalTextureDimensions.height(),
+ ColorTextureFormat);
+ QT3DSVec2 theVertexOffsets;
+ if (isProgressiveAABlendPass) {
+ theLastLayerTexture.StealTexture(m_LayerTexture);
+ aaFactorIndex = (m_ProgressiveAAPassIndex - 1);
+ theVertexOffsets = s_VertexOffsets[aaFactorIndex];
+ } else {
+ if (m_TemporalAATexture.GetTexture())
+ theLastLayerTexture.StealTexture(m_TemporalAATexture);
+ else {
+ if (hadLayerTexture) {
+ theLastLayerTexture.StealTexture(m_LayerTexture);
+ }
+ }
+ theVertexOffsets = s_TemporalVertexOffsets[m_TemporalAAPassIndex];
+ ++m_TemporalAAPassIndex;
+ ++m_NonDirtyTemporalAAPassIndex;
+ m_TemporalAAPassIndex = m_TemporalAAPassIndex % MAX_TEMPORAL_AA_LEVELS;
+ }
+ if (theLastLayerTexture.GetTexture()) {
+ theVertexOffsets.x =
+ theVertexOffsets.x / (theLayerOriginalTextureDimensions.width() / 2.0f);
+ theVertexOffsets.y =
+ theVertexOffsets.y / (theLayerOriginalTextureDimensions.height() / 2.0f);
+ // Run through all models and update MVP.
+ // run through all texts and update MVP.
+ // run through all path and update MVP.
+
+ // TODO - optimize this exact matrix operation.
+ for (QT3DSU32 idx = 0, end = m_ModelContexts.size(); idx < end; ++idx) {
+ QT3DSMat44 &originalProjection(m_ModelContexts[idx]->m_ModelViewProjection);
+ OffsetProjectionMatrix(originalProjection, theVertexOffsets);
+ }
+ for (QT3DSU32 idx = 0, end = m_OpaqueObjects.size(); idx < end; ++idx) {
+ if (m_OpaqueObjects[idx]->m_RenderableFlags.IsPath()) {
+ SPathRenderable &theRenderable =
+ static_cast<SPathRenderable &>(*m_OpaqueObjects[idx]);
+ OffsetProjectionMatrix(theRenderable.m_ModelViewProjection,
+ theVertexOffsets);
+ }
+ }
+ for (QT3DSU32 idx = 0, end = m_TransparentObjects.size(); idx < end; ++idx) {
+ if (m_TransparentObjects[idx]->m_RenderableFlags.IsText()) {
+ STextRenderable &theRenderable =
+ static_cast<STextRenderable &>(*m_TransparentObjects[idx]);
+ OffsetProjectionMatrix(theRenderable.m_ModelViewProjection,
+ theVertexOffsets);
+ } else if (m_TransparentObjects[idx]->m_RenderableFlags.IsPath()) {
+ SPathRenderable &theRenderable =
+ static_cast<SPathRenderable &>(*m_TransparentObjects[idx]);
+ OffsetProjectionMatrix(theRenderable.m_ModelViewProjection,
+ theVertexOffsets);
+ }
+ }
+ }
+ }
+ }
+ if (theLastLayerTexture.GetTexture() == NULL) {
+ isProgressiveAABlendPass = false;
+ isTemporalAABlendPass = false;
+ }
+ // Sometimes we will have stolen the render texture.
+ renderColorTexture->EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(), ColorTextureFormat,
+ sampleCount);
+
+ if (!isTemporalAABlendPass)
+ m_TemporalAATexture.ReleaseTexture();
+
+ // Allocating a frame buffer can cause it to be bound, so we need to save state before this
+ // happens.
+ NVRenderContextScopedProperty<NVRenderFrameBuffer *> __framebuf(
+ theRenderContext, &NVRenderContext::GetRenderTarget, &NVRenderContext::SetRenderTarget);
+ // Match the bit depth of the current render target to avoid popping when we switch from aa
+ // to non aa layers
+ // We have to all this here in because once we change the FB by allocating an FB we are
+ // screwed.
+ NVRenderTextureFormats::Enum theDepthFormat(GetDepthBufferFormat());
+ NVRenderFrameBufferAttachments::Enum theDepthAttachmentFormat(
+ GetFramebufferDepthAttachmentFormat(theDepthFormat));
+
+ // Definitely disable the scissor rect if it is running right now.
+ NVRenderContextScopedProperty<bool> __scissorEnabled(
+ theRenderContext, &NVRenderContext::IsScissorTestEnabled,
+ &NVRenderContext::SetScissorTestEnabled, false);
+ CResourceFrameBuffer theFB(theResourceManager);
+ // Allocates the frame buffer which has the side effect of setting the current render target
+ // to that frame buffer.
+ theFB.EnsureFrameBuffer();
+
+ bool hasDepthObjects = m_OpaqueObjects.size() > 0;
+ bool requiresDepthStencilBuffer =
+ hasDepthObjects || thePrepResult.m_Flags.RequiresStencilBuffer();
+ NVRenderRect theNewViewport(0, 0, theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height());
+ {
+ theRenderContext.SetRenderTarget(theFB);
+ NVRenderContextScopedProperty<NVRenderRect> __viewport(
+ theRenderContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport,
+ theNewViewport);
+ QT3DSVec4 clearColor(0.0);
+ if (m_Layer.m_Background == LayerBackground::Color)
+ clearColor = QT3DSVec4(m_Layer.m_ClearColor, 1.0);
+
+ NVRenderContextScopedProperty<QT3DSVec4> __clearColor(
+ theRenderContext, &NVRenderContext::GetClearColor, &NVRenderContext::SetClearColor,
+ clearColor);
+ if (requiresDepthStencilBuffer) {
+ if (renderPrepassDepthTexture->EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ theDepthFormat, sampleCount)) {
+ (*renderPrepassDepthTexture)->SetMinFilter(NVRenderTextureMinifyingOp::Nearest);
+ (*renderPrepassDepthTexture)
+ ->SetMagFilter(NVRenderTextureMagnifyingOp::Nearest);
+ }
+ }
+
+ if (thePrepResult.m_Flags.RequiresDepthTexture() && m_ProgressiveAAPassIndex == 0) {
+ // Setup FBO with single depth buffer target.
+ // Note this does not use multisample.
+ NVRenderFrameBufferAttachments::Enum theAttachment =
+ GetFramebufferDepthAttachmentFormat(DepthTextureFormat);
+ theFB->Attach(theAttachment, *m_LayerDepthTexture);
+
+ // In this case transparent objects also may write their depth.
+ RenderDepthPass(true);
+ theFB->Attach(theAttachment, NVRenderTextureOrRenderBuffer());
+ }
+
+ if (thePrepResult.m_Flags.RequiresSsaoPass() && m_ProgressiveAAPassIndex == 0
+ && m_Camera != nullptr) {
+ StartProfiling("AO pass", false);
+ // Setup FBO with single color buffer target
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0, *m_LayerSsaoTexture);
+ theRenderContext.Clear(qt3ds::render::NVRenderClearValues::Color);
+ RenderAoPass();
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer());
+ EndProfiling("AO pass");
+ }
+
+ if (thePrepResult.m_Flags.RequiresShadowMapPass() && m_ProgressiveAAPassIndex == 0) {
+ // shadow map path
+ RenderShadowMapPass(&theFB);
+ }
+
+ if (sampleCount > 1) {
+ theRenderContext.SetMultisampleEnabled(true);
+ }
+
+ qt3ds::render::NVRenderClearFlags clearFlags = qt3ds::render::NVRenderClearValues::Color;
+
+ // render depth prepass
+ if ((*renderPrepassDepthTexture)) {
+ theFB->Attach(theDepthAttachmentFormat, **renderPrepassDepthTexture,
+ thFboAttachTarget);
+
+ if (m_Layer.m_Flags.IsLayerEnableDepthPrepass()) {
+ StartProfiling("Depth pass", false);
+ RenderDepthPass(false);
+ EndProfiling("Depth pass");
+ } else {
+ clearFlags |= (qt3ds::render::NVRenderClearValues::Depth);
+ clearFlags |= (qt3ds::render::NVRenderClearValues::Stencil);
+ // enable depth write for the clear below
+ theRenderContext.SetDepthWriteEnabled(true);
+ }
+ }
+
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0, **renderColorTexture,
+ thFboAttachTarget);
+ if (m_Layer.m_Background != LayerBackground::Unspecified)
+ theRenderContext.Clear(clearFlags);
+
+ // We don't clear the depth buffer because the layer render code we are about to call
+ // will do this.
+ StartProfiling("Render pass", false);
+ Render(&theFB);
+ // Debug measure to view the depth map to ensure we're rendering it correctly.
+ //if (m_Layer.m_TemporalAAEnabled) {
+ // RenderFakeDepthMapPass(m_ShadowMapManager->GetShadowMapEntry(0)->m_DepthMap,
+ // m_ShadowMapManager->GetShadowMapEntry(0)->m_DepthCube);
+ //}
+ EndProfiling("Render pass");
+
+ // Now before going further, we downsample and resolve the multisample information.
+ // This allows all algorithms running after
+ // this point to run unchanged.
+ if (isMultisamplePass) {
+ if (m_Layer.m_MultisampleAAMode != AAModeValues::SSAA) {
+ // Resolve the FBO to the layer texture
+ CRendererUtil::ResolveMutisampleFBOColorOnly(
+ theResourceManager, m_LayerTexture, theRenderContext,
+ theLayerTextureDimensions.width(), theLayerTextureDimensions.height(),
+ ColorTextureFormat, *theFB);
+
+ theRenderContext.SetMultisampleEnabled(false);
+ } else {
+ // Resolve the FBO to the layer texture
+ CRendererUtil::ResolveSSAAFBOColorOnly(
+ theResourceManager, m_LayerTexture,
+ theLayerOriginalTextureDimensions.width(),
+ theLayerOriginalTextureDimensions.height(), theRenderContext,
+ theLayerTextureDimensions.width(), theLayerTextureDimensions.height(),
+ ColorTextureFormat, *theFB);
+ }
+ }
+
+ // CN - when I tried to get anti-aliased widgets I lost all transparency on the widget
+ // layer which made it overwrite the object you were
+ // manipulating. When I tried to use parallel nsight on it the entire studio
+ // application crashed on startup.
+ if (NeedsWidgetTexture()) {
+ m_LayerWidgetTexture.EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ NVRenderTextureFormats::RGBA8);
+ theRenderContext.SetRenderTarget(theFB);
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0, *m_LayerWidgetTexture);
+ theFB->Attach(GetFramebufferDepthAttachmentFormat(DepthTextureFormat),
+ *m_LayerDepthTexture);
+ theRenderContext.SetClearColor(QT3DSVec4(0.0f));
+ theRenderContext.Clear(qt3ds::render::NVRenderClearValues::Color);
+ // We should already have the viewport and everything setup for this.
+ RenderRenderWidgets();
+ }
+
+ if (theLastLayerTexture.GetTexture() != NULL
+ && (isProgressiveAABlendPass || isTemporalAABlendPass)) {
+ theRenderContext.SetViewport(
+ NVRenderRect(0, 0, theLayerOriginalTextureDimensions.width(),
+ theLayerOriginalTextureDimensions.height()));
+ CResourceTexture2D targetTexture(
+ theResourceManager, theLayerOriginalTextureDimensions.width(),
+ theLayerOriginalTextureDimensions.height(), ColorTextureFormat);
+ theFB->Attach(theDepthAttachmentFormat,
+ NVRenderTextureOrRenderBuffer());
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0, *targetTexture);
+ QT3DSVec2 theBlendFactors;
+ if (isProgressiveAABlendPass)
+ theBlendFactors = s_BlendFactors[aaFactorIndex];
+ else
+ theBlendFactors = QT3DSVec2(.5f, .5f);
+
+ theRenderContext.SetDepthTestEnabled(false);
+ theRenderContext.SetBlendingEnabled(false);
+ theRenderContext.SetCullingEnabled(false);
+ theRenderContext.SetActiveShader(theBlendShader->m_Shader);
+ theBlendShader->m_AccumSampler.Set(theLastLayerTexture);
+ theBlendShader->m_LastFrame.Set(m_LayerTexture);
+ theBlendShader->m_BlendFactors.Set(theBlendFactors);
+ m_Renderer.RenderQuad();
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ qt3ds::render::NVRenderTextureOrRenderBuffer());
+ if (isTemporalAABlendPass)
+ m_TemporalAATexture.StealTexture(m_LayerTexture);
+ m_LayerTexture.StealTexture(targetTexture);
+ }
+
+ m_LayerTexture->SetMinFilter(NVRenderTextureMinifyingOp::Linear);
+ m_LayerTexture->SetMagFilter(NVRenderTextureMagnifyingOp::Linear);
+
+ // Don't remember why needs widget texture is false here.
+ // Should have commented why progAA plus widgets is a fail.
+ if (m_ProgressiveAAPassIndex < thePrepResult.m_MaxAAPassIndex
+ && NeedsWidgetTexture() == false)
+ ++m_ProgressiveAAPassIndex;
+
+// now we render all post effects
+#ifdef QT3DS_CACHED_POST_EFFECT
+ ApplyLayerPostEffects();
+#endif
+
+ if (m_LayerPrepassDepthTexture) {
+ // Detach any depth buffers.
+ theFB->Attach(theDepthAttachmentFormat, qt3ds::render::NVRenderTextureOrRenderBuffer(),
+ thFboAttachTarget);
+ }
+
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ qt3ds::render::NVRenderTextureOrRenderBuffer(), thFboAttachTarget);
+ // Let natural scoping rules destroy the other stuff.
+ }
+ }
+
+ void SLayerRenderData::ApplyLayerPostEffects()
+ {
+ if (m_Layer.m_FirstEffect == NULL) {
+ if (m_LayerCachedTexture) {
+ IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager());
+ theResourceManager.Release(*m_LayerCachedTexture);
+ m_LayerCachedTexture = NULL;
+ }
+ return;
+ }
+
+ IEffectSystem &theEffectSystem(m_Renderer.GetQt3DSContext().GetEffectSystem());
+ IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager());
+ // we use the non MSAA buffer for the effect
+ NVRenderTexture2D *theLayerColorTexture = m_LayerTexture;
+ NVRenderTexture2D *theLayerDepthTexture = m_LayerDepthTexture;
+
+ NVRenderTexture2D *theCurrentTexture = theLayerColorTexture;
+ for (SEffect *theEffect = m_Layer.m_FirstEffect; theEffect;
+ theEffect = theEffect->m_NextEffect) {
+ if (theEffect->m_Flags.IsActive() && m_Camera) {
+ StartProfiling(theEffect->m_ClassName, false);
+
+ NVRenderTexture2D *theRenderedEffect = theEffectSystem.RenderEffect(
+ SEffectRenderArgument(*theEffect, *theCurrentTexture,
+ QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar),
+ theLayerDepthTexture, m_LayerPrepassDepthTexture));
+
+ EndProfiling(theEffect->m_ClassName);
+
+ // If the texture came from rendering a chain of effects, then we don't need it
+ // after this.
+ if (theCurrentTexture != theLayerColorTexture)
+ theResourceManager.Release(*theCurrentTexture);
+
+ theCurrentTexture = theRenderedEffect;
+
+ if (!theRenderedEffect) {
+ QString errorMsg = QObject::tr("Failed to compile \"%1\" effect.\nConsider"
+ " removing it from the presentation.")
+ .arg(theEffect->m_ClassName.c_str());
+ QT3DS_ALWAYS_ASSERT_MESSAGE(errorMsg.toUtf8());
+ break;
+ }
+ }
+ }
+
+ if (m_LayerCachedTexture && m_LayerCachedTexture != m_LayerTexture) {
+ theResourceManager.Release(*m_LayerCachedTexture);
+ m_LayerCachedTexture = NULL;
+ }
+
+ if (theCurrentTexture != m_LayerTexture)
+ m_LayerCachedTexture = theCurrentTexture;
+ }
+
+ inline bool AnyCompletelyNonTransparentObjects(TRenderableObjectList &inObjects)
+ {
+ for (QT3DSU32 idx = 0, end = inObjects.size(); idx < end; ++idx) {
+ if (inObjects[idx]->m_RenderableFlags.IsCompletelyTransparent() == false)
+ return true;
+ }
+ return false;
+ }
+
+ void SLayerRenderData::RunnableRenderToViewport(qt3ds::render::NVRenderFrameBuffer *theFB)
+ {
+ // If we have an effect, an opaque object, or any transparent objects that aren't completely
+ // transparent
+ // or an offscreen renderer or a layer widget texture
+ // Then we can't possible affect the resulting render target.
+ bool needsToRender = m_Layer.m_FirstEffect != NULL || m_OpaqueObjects.empty() == false
+ || AnyCompletelyNonTransparentObjects(m_TransparentObjects) || GetOffscreenRenderer()
+ || m_LayerWidgetTexture || m_BoundingRectColor.hasValue()
+ || m_Layer.m_Background == LayerBackground::Color;
+
+ if (needsToRender == false)
+ return;
+
+ NVRenderContext &theContext(m_Renderer.GetContext());
+ theContext.resetStates();
+
+ NVRenderContextScopedProperty<NVRenderFrameBuffer *> __fbo(
+ theContext, &NVRenderContext::GetRenderTarget, &NVRenderContext::SetRenderTarget);
+ qt3ds::render::NVRenderRect theCurrentViewport = theContext.GetViewport();
+ NVRenderContextScopedProperty<NVRenderRect> __viewport(
+ theContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport);
+ NVRenderContextScopedProperty<bool> theScissorEnabled(
+ theContext, &NVRenderContext::IsScissorTestEnabled,
+ &NVRenderContext::SetScissorTestEnabled);
+ NVRenderContextScopedProperty<qt3ds::render::NVRenderRect> theScissorRect(
+ theContext, &NVRenderContext::GetScissorRect, &NVRenderContext::SetScissorRect);
+ SLayerRenderPreparationResult &thePrepResult(*m_LayerPrepResult);
+ NVRenderRectF theScreenRect(thePrepResult.GetLayerToPresentationViewport());
+
+ bool blendingEnabled = m_Layer.m_Background == LayerBackground::Transparent;
+ if (!thePrepResult.m_Flags.ShouldRenderToTexture()) {
+ theContext.SetViewport(
+ m_LayerPrepResult->GetLayerToPresentationViewport().ToIntegerRect());
+ theContext.SetScissorTestEnabled(true);
+ theContext.SetScissorRect(
+ m_LayerPrepResult->GetLayerToPresentationScissorRect().ToIntegerRect());
+ if (m_Layer.m_Background == LayerBackground::Color) {
+ NVRenderContextScopedProperty<QT3DSVec4> __clearColor(
+ theContext, &NVRenderContext::GetClearColor, &NVRenderContext::SetClearColor,
+ QT3DSVec4(m_Layer.m_ClearColor, 0.0f));
+ theContext.Clear(NVRenderClearValues::Color);
+ }
+ RenderToViewport();
+ } else {
+// First, render the layer along with whatever progressive AA is appropriate.
+// The render graph should have taken care of the render to texture step.
+#ifdef QT3DS_CACHED_POST_EFFECT
+ NVRenderTexture2D *theLayerColorTexture =
+ (m_LayerCachedTexture) ? m_LayerCachedTexture : m_LayerTexture;
+#else
+ // Then render all but the last effect
+ IEffectSystem &theEffectSystem(m_Renderer.GetQt3DSContext().GetEffectSystem());
+ IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager());
+ // we use the non MSAA buffer for the effect
+ NVRenderTexture2D *theLayerColorTexture = m_LayerTexture;
+ NVRenderTexture2D *theLayerDepthTexture = m_LayerDepthTexture;
+
+ NVRenderTexture2D *theCurrentTexture = theLayerColorTexture;
+ for (SEffect *theEffect = m_Layer.m_FirstEffect;
+ theEffect && theEffect != thePrepResult.m_LastEffect;
+ theEffect = theEffect->m_NextEffect) {
+ if (theEffect->m_Flags.IsActive() && m_Camera) {
+ StartProfiling(theEffect->m_ClassName, false);
+
+ NVRenderTexture2D *theRenderedEffect = theEffectSystem.RenderEffect(
+ SEffectRenderArgument(*theEffect, *theCurrentTexture,
+ QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar),
+ theLayerDepthTexture, m_LayerPrepassDepthTexture));
+
+ EndProfiling(theEffect->m_ClassName);
+
+ // If the texture came from rendering a chain of effects, then we don't need it
+ // after this.
+ if (theCurrentTexture != theLayerColorTexture)
+ theResourceManager.Release(*theCurrentTexture);
+
+ theCurrentTexture = theRenderedEffect;
+ }
+ }
+#endif
+ // Now the last effect or straight to the scene if we have no last effect
+ // There are two cases we need to consider here. The first is when we shouldn't
+ // transform
+ // the result and thus we need to setup an MVP that just maps to the viewport width and
+ // height.
+ // The second is when we are expected to render to the scene using some global
+ // transform.
+ QT3DSMat44 theFinalMVP(QT3DSMat44::createIdentity());
+ SCamera theTempCamera;
+ NVRenderRect theLayerViewport(
+ thePrepResult.GetLayerToPresentationViewport().ToIntegerRect());
+ NVRenderRect theLayerClip(
+ thePrepResult.GetLayerToPresentationScissorRect().ToIntegerRect());
+
+ {
+ QT3DSMat33 ignored;
+ QT3DSMat44 theViewProjection;
+ // We could cache these variables
+ theTempCamera.m_Flags.SetOrthographic(true);
+ theTempCamera.MarkDirty(NodeTransformDirtyFlag::TransformIsDirty);
+ // Move the camera back far enough that we can see everything
+ QT3DSF32 theCameraSetback(10);
+ // Attempt to ensure the layer can never be clipped.
+ theTempCamera.m_Position.z = -theCameraSetback;
+ theTempCamera.m_ClipFar = 2.0f * theCameraSetback;
+ // Render the layer texture to the entire viewport.
+ SCameraGlobalCalculationResult theResult = theTempCamera.CalculateGlobalVariables(
+ theLayerViewport,
+ QT3DSVec2((QT3DSF32)theLayerViewport.m_Width, (QT3DSF32)theLayerViewport.m_Height));
+ theTempCamera.CalculateViewProjectionMatrix(theViewProjection);
+ SNode theTempNode;
+ theFinalMVP = theViewProjection;
+ qt3ds::render::NVRenderBlendFunctionArgument blendFunc;
+ qt3ds::render::NVRenderBlendEquationArgument blendEqu;
+
+ switch (m_Layer.m_BlendType) {
+ case LayerBlendTypes::Screen:
+ blendFunc = qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::SrcAlpha, NVRenderDstBlendFunc::One,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One);
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Add, NVRenderBlendEquation::Add);
+ break;
+ case LayerBlendTypes::Multiply:
+ blendFunc = qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::DstColor, NVRenderDstBlendFunc::Zero,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One);
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Add, NVRenderBlendEquation::Add);
+ break;
+ case LayerBlendTypes::Add:
+ blendFunc = qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One);
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Add, NVRenderBlendEquation::Add);
+ break;
+ case LayerBlendTypes::Subtract:
+ blendFunc = qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One);
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::ReverseSubtract,
+ NVRenderBlendEquation::ReverseSubtract);
+ break;
+ case LayerBlendTypes::Overlay:
+ // SW fallback doesn't use blend equation
+ // note blend func is not used here anymore
+ if (theContext.IsAdvancedBlendHwSupported() ||
+ theContext.IsAdvancedBlendHwSupportedKHR())
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Overlay, NVRenderBlendEquation::Overlay);
+ break;
+ case LayerBlendTypes::ColorBurn:
+ // SW fallback doesn't use blend equation
+ // note blend func is not used here anymore
+ if (theContext.IsAdvancedBlendHwSupported() ||
+ theContext.IsAdvancedBlendHwSupportedKHR())
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::ColorBurn, NVRenderBlendEquation::ColorBurn);
+ break;
+ case LayerBlendTypes::ColorDodge:
+ // SW fallback doesn't use blend equation
+ // note blend func is not used here anymore
+ if (theContext.IsAdvancedBlendHwSupported() ||
+ theContext.IsAdvancedBlendHwSupportedKHR())
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::ColorDodge, NVRenderBlendEquation::ColorDodge);
+ break;
+ default:
+ blendFunc = qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha);
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Add, NVRenderBlendEquation::Add);
+ break;
+ }
+ theContext.SetBlendFunction(blendFunc);
+ theContext.SetBlendEquation(blendEqu);
+ theContext.SetBlendingEnabled(blendingEnabled);
+ theContext.SetDepthTestEnabled(false);
+ }
+
+ {
+ theContext.SetScissorTestEnabled(true);
+ theContext.SetViewport(theLayerViewport);
+ theContext.SetScissorRect(theLayerClip);
+
+ // Remember the camera we used so we can get a valid pick ray
+ m_SceneCamera = theTempCamera;
+ theContext.SetDepthTestEnabled(false);
+#ifndef QT3DS_CACHED_POST_EFFECT
+ if (thePrepResult.m_LastEffect && m_Camera) {
+ StartProfiling(thePrepResult.m_LastEffect->m_ClassName, false);
+ // inUseLayerMPV is true then we are rendering directly to the scene and thus we
+ // should enable blending
+ // for the final render pass. Else we should leave it.
+ theEffectSystem.RenderEffect(
+ SEffectRenderArgument(*thePrepResult.m_LastEffect, *theCurrentTexture,
+ QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar),
+ theLayerDepthTexture, m_LayerPrepassDepthTexture),
+ theFinalMVP, blendingEnabled);
+ EndProfiling(thePrepResult.m_LastEffect->m_ClassName);
+ // If the texture came from rendering a chain of effects, then we don't need it
+ // after this.
+ if (theCurrentTexture != theLayerColorTexture)
+ theResourceManager.Release(*theCurrentTexture);
+ } else
+#endif
+ {
+ theContext.SetCullingEnabled(false);
+ theContext.SetBlendingEnabled(blendingEnabled);
+ theContext.SetDepthTestEnabled(false);
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ NVScopedRefCounted<NVRenderTexture2D> screenTexture =
+ m_Renderer.GetLayerBlendTexture();
+ NVScopedRefCounted<NVRenderFrameBuffer> blendFB = m_Renderer.GetBlendFB();
+
+ // Layer blending for advanced blending modes if SW fallback is needed
+ // rendering to FBO and blending with separate shader
+ if (screenTexture) {
+ // Blending is enabled only if layer background has been chosen transparent
+ // Layers with advanced blending modes
+ if (blendingEnabled && (m_Layer.m_BlendType == LayerBlendTypes::Overlay ||
+ m_Layer.m_BlendType == LayerBlendTypes::ColorBurn ||
+ m_Layer.m_BlendType == LayerBlendTypes::ColorDodge)) {
+ theContext.SetScissorTestEnabled(false);
+ theContext.SetBlendingEnabled(false);
+
+ // Get part matching to layer from screen texture and
+ // use that for blending
+ qt3ds::render::NVRenderTexture2D *blendBlitTexture;
+ blendBlitTexture = theContext.CreateTexture2D();
+ blendBlitTexture->SetTextureData(NVDataRef<QT3DSU8>(), 0,
+ theLayerViewport.m_Width,
+ theLayerViewport.m_Height,
+ NVRenderTextureFormats::RGBA8);
+ qt3ds::render::NVRenderFrameBuffer *blitFB;
+ blitFB = theContext.CreateFrameBuffer();
+ blitFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer(*blendBlitTexture));
+ blendFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer(*screenTexture));
+ theContext.SetRenderTarget(blitFB);
+ theContext.SetReadTarget(blendFB);
+ theContext.SetReadBuffer(NVReadFaces::Color0);
+ theContext.BlitFramebuffer(theLayerViewport.m_X, theLayerViewport.m_Y,
+ theLayerViewport.m_Width +
+ theLayerViewport.m_X,
+ theLayerViewport.m_Height +
+ theLayerViewport.m_Y,
+ 0, 0,
+ theLayerViewport.m_Width,
+ theLayerViewport.m_Height,
+ NVRenderClearValues::Color,
+ NVRenderTextureMagnifyingOp::Nearest);
+
+ qt3ds::render::NVRenderTexture2D *blendResultTexture;
+ blendResultTexture = theContext.CreateTexture2D();
+ blendResultTexture->SetTextureData(NVDataRef<QT3DSU8>(), 0,
+ theLayerViewport.m_Width,
+ theLayerViewport.m_Height,
+ NVRenderTextureFormats::RGBA8);
+ qt3ds::render::NVRenderFrameBuffer *resultFB;
+ resultFB = theContext.CreateFrameBuffer();
+ resultFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer(*blendResultTexture));
+ theContext.SetRenderTarget(resultFB);
+
+ AdvancedBlendModes::Enum advancedMode;
+ switch (m_Layer.m_BlendType) {
+ case LayerBlendTypes::Overlay:
+ advancedMode = AdvancedBlendModes::Overlay;
+ break;
+ case LayerBlendTypes::ColorBurn:
+ advancedMode = AdvancedBlendModes::ColorBurn;
+ break;
+ case LayerBlendTypes::ColorDodge:
+ advancedMode = AdvancedBlendModes::ColorDodge;
+ break;
+ default:
+ advancedMode = AdvancedBlendModes::None;
+ break;
+ }
+
+ theContext.SetViewport(NVRenderRect(0, 0, theLayerViewport.m_Width,
+ theLayerViewport.m_Height));
+ BlendAdvancedEquationSwFallback(theLayerColorTexture, blendBlitTexture,
+ advancedMode);
+ blitFB->release();
+ // save blending result to screen texture for use with other layers
+ theContext.SetViewport(theLayerViewport);
+ theContext.SetRenderTarget(blendFB);
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *blendResultTexture);
+ // render the blended result
+ theContext.SetRenderTarget(theFB);
+ theContext.SetScissorTestEnabled(true);
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *blendResultTexture);
+ resultFB->release();
+ } else {
+ // Layers with normal blending modes
+ // save result for future use
+ theContext.SetViewport(theLayerViewport);
+ theContext.SetScissorTestEnabled(false);
+ theContext.SetBlendingEnabled(true);
+ theContext.SetRenderTarget(blendFB);
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *theLayerColorTexture);
+ theContext.SetRenderTarget(theFB);
+ theContext.SetScissorTestEnabled(true);
+ theContext.SetViewport(theCurrentViewport);
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *theLayerColorTexture);
+ }
+ } else {
+ // No advanced blending SW fallback needed
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *theLayerColorTexture);
+ }
+#else
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *theLayerColorTexture);
+#endif
+ }
+ if (m_LayerWidgetTexture) {
+ theContext.SetBlendingEnabled(false);
+ m_Renderer.SetupWidgetLayer();
+ SLayerRenderPreparationResult &thePrepResult(*m_LayerPrepResult);
+ NVRenderRectF thePresRect(thePrepResult.GetPresentationViewport());
+ NVRenderRectF theLayerRect(thePrepResult.GetLayerToPresentationViewport());
+
+ // Ensure we remove any offsetting in the layer rect that was caused simply by
+ // the
+ // presentation rect offsetting but then use a new rect.
+ NVRenderRectF theWidgetLayerRect(theLayerRect.m_X - thePresRect.m_X,
+ theLayerRect.m_Y - thePresRect.m_Y,
+ theLayerRect.m_Width, theLayerRect.m_Height);
+ theContext.SetScissorTestEnabled(false);
+ theContext.SetViewport(theWidgetLayerRect.ToIntegerRect());
+ m_Renderer.RenderQuad(
+ QT3DSVec2((QT3DSF32)theLayerViewport.m_Width, (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *m_LayerWidgetTexture);
+ }
+ }
+ } // End offscreen render code.
+
+ if (m_BoundingRectColor.hasValue()) {
+ NVRenderContextScopedProperty<NVRenderRect> __viewport(
+ theContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport);
+ NVRenderContextScopedProperty<bool> theScissorEnabled(
+ theContext, &NVRenderContext::IsScissorTestEnabled,
+ &NVRenderContext::SetScissorTestEnabled);
+ NVRenderContextScopedProperty<qt3ds::render::NVRenderRect> theScissorRect(
+ theContext, &NVRenderContext::GetScissorRect, &NVRenderContext::SetScissorRect);
+ m_Renderer.SetupWidgetLayer();
+ // Setup a simple viewport to render to the entire presentation viewport.
+ theContext.SetViewport(
+ NVRenderRect(0, 0, (QT3DSU32)thePrepResult.GetPresentationViewport().m_Width,
+ (QT3DSU32)thePrepResult.GetPresentationViewport().m_Height));
+
+ NVRenderRectF thePresRect(thePrepResult.GetPresentationViewport());
+
+ // Remove any offsetting from the presentation rect since the widget layer is a
+ // stand-alone fbo.
+ NVRenderRectF theWidgetScreenRect(theScreenRect.m_X - thePresRect.m_X,
+ theScreenRect.m_Y - thePresRect.m_Y,
+ theScreenRect.m_Width, theScreenRect.m_Height);
+ theContext.SetScissorTestEnabled(false);
+ m_Renderer.DrawScreenRect(theWidgetScreenRect, *m_BoundingRectColor);
+ }
+ theContext.SetBlendFunction(qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha));
+ theContext.SetBlendEquation(qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Add, NVRenderBlendEquation::Add));
+ }
+
+#define RENDER_FRAME_NEW(type) QT3DS_NEW(m_Renderer.GetPerFrameAllocator(), type)
+
+ void SLayerRenderData::AddLayerRenderStep()
+ {
+ SStackPerfTimer __perfTimer(m_Renderer.GetQt3DSContext().GetPerfTimer(),
+ "SLayerRenderData::AddLayerRenderStep");
+ QT3DS_ASSERT(m_Camera);
+ if (!m_Camera)
+ return;
+
+ IRenderList &theGraph(m_Renderer.GetQt3DSContext().GetRenderList());
+
+ qt3ds::render::NVRenderRect theCurrentViewport = theGraph.GetViewport();
+ if (!m_LayerPrepResult.hasValue())
+ PrepareForRender(
+ QSize(theCurrentViewport.m_Width, theCurrentViewport.m_Height));
+ }
+
+ void SLayerRenderData::PrepareForRender()
+ {
+ // When we render to the scene itself (as opposed to an offscreen buffer somewhere)
+ // then we use the MVP of the layer somewhat.
+ NVRenderRect theViewport = m_Renderer.GetQt3DSContext().GetRenderList().GetViewport();
+ PrepareForRender(
+ QSize((QT3DSU32)theViewport.m_Width, (QT3DSU32)theViewport.m_Height));
+ }
+
+ void SLayerRenderData::ResetForFrame()
+ {
+ SLayerRenderPreparationData::ResetForFrame();
+ m_BoundingRectColor.setEmpty();
+ }
+
+ void SLayerRenderData::PrepareAndRender(const QT3DSMat44 &inViewProjection)
+ {
+ TRenderableObjectList theTransparentObjects(m_TransparentObjects);
+ TRenderableObjectList theOpaqueObjects(m_OpaqueObjects);
+ theTransparentObjects.clear();
+ theOpaqueObjects.clear();
+ m_ModelContexts.clear();
+ SLayerRenderPreparationResultFlags theFlags;
+ PrepareRenderablesForRender(inViewProjection, Empty(), 1.0, theFlags);
+ RenderDepthPass(false);
+ Render();
+ }
+
+ struct SLayerRenderToTextureRunnable : public IRenderTask
+ {
+ SLayerRenderData &m_Data;
+ SLayerRenderToTextureRunnable(SLayerRenderData &d)
+ : m_Data(d)
+ {
+ }
+
+ void Run() override { m_Data.RenderToTexture(); }
+ };
+
+ static inline OffscreenRendererDepthValues::Enum
+ GetOffscreenRendererDepthValue(NVRenderTextureFormats::Enum inBufferFormat)
+ {
+ switch (inBufferFormat) {
+ case NVRenderTextureFormats::Depth32:
+ return OffscreenRendererDepthValues::Depth32;
+ case NVRenderTextureFormats::Depth24:
+ return OffscreenRendererDepthValues::Depth24;
+ case NVRenderTextureFormats::Depth24Stencil8:
+ return OffscreenRendererDepthValues::Depth24;
+ default:
+ QT3DS_ASSERT(false); // fallthrough intentional
+ case NVRenderTextureFormats::Depth16:
+ return OffscreenRendererDepthValues::Depth16;
+ }
+ }
+
+ SOffscreenRendererEnvironment SLayerRenderData::CreateOffscreenRenderEnvironment()
+ {
+ OffscreenRendererDepthValues::Enum theOffscreenDepth(
+ GetOffscreenRendererDepthValue(GetDepthBufferFormat()));
+ NVRenderRect theViewport = m_Renderer.GetQt3DSContext().GetRenderList().GetViewport();
+ return SOffscreenRendererEnvironment(theViewport.m_Width, theViewport.m_Height,
+ NVRenderTextureFormats::RGBA8, theOffscreenDepth,
+ false, AAModeValues::NoAA);
+ }
+
+ IRenderTask &SLayerRenderData::CreateRenderToTextureRunnable()
+ {
+ return *RENDER_FRAME_NEW(SLayerRenderToTextureRunnable)(*this);
+ }
+
+ void SLayerRenderData::addRef() { atomicIncrement(&mRefCount); }
+
+ void SLayerRenderData::release() { QT3DS_IMPLEMENT_REF_COUNT_RELEASE(m_Allocator); }
+}
+}