diff options
Diffstat (limited to 'src/Runtime/Source/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp')
-rw-r--r-- | src/Runtime/Source/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp | 2203 |
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); } +} +} |