summaryrefslogtreecommitdiffstats
path: root/src/runtimerender/Qt3DSRenderEffectSystem.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtimerender/Qt3DSRenderEffectSystem.cpp')
-rw-r--r--src/runtimerender/Qt3DSRenderEffectSystem.cpp1872
1 files changed, 1872 insertions, 0 deletions
diff --git a/src/runtimerender/Qt3DSRenderEffectSystem.cpp b/src/runtimerender/Qt3DSRenderEffectSystem.cpp
new file mode 100644
index 0000000..65f52a6
--- /dev/null
+++ b/src/runtimerender/Qt3DSRenderEffectSystem.cpp
@@ -0,0 +1,1872 @@
+/****************************************************************************
+**
+** 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 "Qt3DSRenderEffectSystem.h"
+#include "foundation/Qt3DSAllocatorCallback.h"
+#include "render/Qt3DSRenderContext.h"
+#include "Qt3DSRenderInputStreamFactory.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "foundation/Qt3DSContainers.h"
+#include "StringTools.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "Qt3DSRenderEffect.h"
+#include "Qt3DSRenderResourceManager.h"
+#include "Qt3DSRenderDynamicObjectSystemCommands.h"
+#include "render/Qt3DSRenderFrameBuffer.h"
+#include "render/Qt3DSRenderShaderConstant.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+#include "Qt3DSRenderContextCore.h"
+#include "Qt3DSRenderer.h"
+#include "Qt3DSTextRenderer.h"
+#include "Qt3DSRenderCamera.h"
+#include "Qt3DSRenderBufferManager.h"
+#include "Qt3DSOffscreenRenderManager.h"
+#include "foundation/PreAllocatedAllocator.h"
+#include "foundation/SerializationTypes.h"
+#include "Qt3DSRenderShaderCache.h"
+#include "foundation/FileTools.h"
+#include "Qt3DSOffscreenRenderKey.h"
+#include "Qt3DSRenderDynamicObjectSystemUtil.h"
+
+using namespace qt3ds::render;
+using namespace qt3ds::render::dynamic;
+using qt3ds::render::NVRenderContextScopedProperty;
+using qt3ds::render::NVRenderCachedShaderProperty;
+using qt3ds::render::NVRenderCachedShaderBuffer;
+
+// None of this code will work if the size of void* changes because that would mean that
+// the alignment of some of the objects isn't 4 bytes but would be 8 bytes.
+
+typedef eastl::pair<CRegisteredString, CRegisteredString> TStrStrPair;
+
+namespace eastl {
+template <>
+struct hash<TStrStrPair>
+{
+ size_t operator()(const TStrStrPair &item) const
+ {
+ return hash<CRegisteredString>()(item.first) ^ hash<CRegisteredString>()(item.second);
+ }
+};
+}
+
+namespace {
+
+/*
+ ApplyBufferValue,
+ //Apply the depth buffer as an input texture.
+ ApplyDepthValue,
+ Render, //Render to current FBO
+ */
+
+struct SEffectClass
+{
+ NVAllocatorCallback *m_Allocator;
+ IDynamicObjectClass *m_DynamicClass;
+ volatile QT3DSI32 mRefCount;
+
+ SEffectClass(NVAllocatorCallback &inFnd, IDynamicObjectClass &dynClass)
+ : m_Allocator(&inFnd)
+ , m_DynamicClass(&dynClass)
+ , mRefCount(0)
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(*m_Allocator)
+
+ void SetupThisObjectFromMemory(NVAllocatorCallback &inAlloc, IDynamicObjectClass &inClass)
+ {
+ m_Allocator = &inAlloc;
+ m_DynamicClass = &inClass;
+ mRefCount = 0;
+ }
+};
+
+struct SAllocatedBufferEntry
+{
+ CRegisteredString m_Name;
+ NVScopedRefCounted<NVRenderFrameBuffer> m_FrameBuffer;
+ NVScopedRefCounted<NVRenderTexture2D> m_Texture;
+ SAllocateBufferFlags m_Flags;
+ bool m_NeedsClear;
+
+ SAllocatedBufferEntry(CRegisteredString inName, NVRenderFrameBuffer &inFb,
+ NVRenderTexture2D &inTexture, SAllocateBufferFlags inFlags)
+ : m_Name(inName)
+ , m_FrameBuffer(&inFb)
+ , m_Texture(&inTexture)
+ , m_Flags(inFlags)
+ , m_NeedsClear(true)
+ {
+ }
+ SAllocatedBufferEntry() {}
+};
+
+struct SAllocatedImageEntry
+{
+ CRegisteredString m_Name;
+ NVScopedRefCounted<NVRenderImage2D> m_Image;
+ NVScopedRefCounted<NVRenderTexture2D> m_Texture;
+ SAllocateBufferFlags m_Flags;
+
+ SAllocatedImageEntry(CRegisteredString inName, NVRenderImage2D &inImage,
+ NVRenderTexture2D &inTexture, SAllocateBufferFlags inFlags)
+ : m_Name(inName)
+ , m_Image(&inImage)
+ , m_Texture(&inTexture)
+ , m_Flags(inFlags)
+ {
+ }
+ SAllocatedImageEntry() {}
+};
+
+struct SImageEntry
+{
+ NVScopedRefCounted<NVRenderShaderProgram> m_Shader;
+ NVRenderCachedShaderProperty<NVRenderImage2D *> m_Image;
+ volatile QT3DSI32 mRefCount;
+
+ SImageEntry(NVRenderShaderProgram &inShader, const char *inImageName)
+ : m_Shader(inShader)
+ , m_Image(inImageName, inShader)
+ , mRefCount(0)
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Shader->GetRenderContext().GetAllocator())
+
+ void Set(NVRenderImage2D *inImage) { m_Image.Set(inImage); }
+
+ static SImageEntry CreateImageEntry(NVRenderShaderProgram &inShader, const char *inStem)
+ {
+ return SImageEntry(inShader, inStem);
+ }
+};
+
+struct SAllocatedDataBufferEntry
+{
+ CRegisteredString m_Name;
+ NVScopedRefCounted<qt3ds::render::NVRenderDataBuffer> m_DataBuffer;
+ NVRenderBufferBindValues::Enum m_BufferType;
+ NVDataRef<QT3DSU8> m_BufferData;
+ SAllocateBufferFlags m_Flags;
+ bool m_NeedsClear;
+
+ SAllocatedDataBufferEntry(CRegisteredString inName,
+ qt3ds::render::NVRenderDataBuffer &inDataBuffer,
+ NVRenderBufferBindValues::Enum inType, NVDataRef<QT3DSU8> data,
+ SAllocateBufferFlags inFlags)
+ : m_Name(inName)
+ , m_DataBuffer(&inDataBuffer)
+ , m_BufferType(inType)
+ , m_BufferData(data)
+ , m_Flags(inFlags)
+ , m_NeedsClear(false)
+ {
+ }
+ SAllocatedDataBufferEntry() {}
+};
+
+struct SDataBufferEntry
+{
+ NVScopedRefCounted<NVRenderShaderProgram> m_Shader;
+ NVRenderCachedShaderBuffer<qt3ds::render::NVRenderShaderBufferBase *> m_DataBuffer;
+ volatile QT3DSI32 mRefCount;
+
+ SDataBufferEntry(NVRenderShaderProgram &inShader, const char *inBufferName)
+ : m_Shader(inShader)
+ , m_DataBuffer(inBufferName, inShader)
+ , mRefCount(0)
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Shader->GetRenderContext().GetAllocator())
+
+ void Set(qt3ds::render::NVRenderDataBuffer *inBuffer)
+ {
+ if (inBuffer)
+ inBuffer->Bind();
+
+ m_DataBuffer.Set();
+ }
+
+ static SDataBufferEntry CreateDataBufferEntry(NVRenderShaderProgram &inShader,
+ const char *inStem)
+ {
+ return SDataBufferEntry(inShader, inStem);
+ }
+};
+
+struct SEffectTextureData
+{
+ NVRenderTexture2D *m_Texture;
+ bool m_NeedsAlphaMultiply;
+ SEffectTextureData(NVRenderTexture2D *inTexture, bool inNeedsMultiply)
+ : m_Texture(inTexture)
+ , m_NeedsAlphaMultiply(inNeedsMultiply)
+ {
+ }
+ SEffectTextureData()
+ : m_Texture(NULL)
+ , m_NeedsAlphaMultiply(false)
+ {
+ }
+};
+
+struct STextureEntry
+{
+ NVScopedRefCounted<NVRenderShaderProgram> m_Shader;
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> m_Texture;
+ NVRenderCachedShaderProperty<QT3DSVec4> m_TextureData;
+ NVRenderCachedShaderProperty<QT3DSI32> m_TextureFlags;
+ volatile QT3DSI32 mRefCount;
+
+ STextureEntry(NVRenderShaderProgram &inShader, const char *inTexName, const char *inDataName,
+ const char *inFlagName)
+ : m_Shader(inShader)
+ , m_Texture(inTexName, inShader)
+ , m_TextureData(inDataName, inShader)
+ , m_TextureFlags(inFlagName, inShader)
+ , mRefCount(0)
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Shader->GetRenderContext().GetAllocator())
+
+ void Set(NVRenderTexture2D *inTexture, bool inNeedsAlphaMultiply,
+ const SPropertyDefinition *inDefinition)
+ {
+ QT3DSF32 theMixValue(inNeedsAlphaMultiply ? 0.0f : 1.0f);
+ if (inTexture && inDefinition) {
+ inTexture->SetMagFilter(inDefinition->m_MagFilterOp);
+ inTexture->SetMinFilter(
+ static_cast<NVRenderTextureMinifyingOp::Enum>(inDefinition->m_MagFilterOp));
+ inTexture->SetTextureWrapS(inDefinition->m_CoordOp);
+ inTexture->SetTextureWrapT(inDefinition->m_CoordOp);
+ }
+ m_Texture.Set(inTexture);
+ if (inTexture) {
+ STextureDetails theDetails(inTexture->GetTextureDetails());
+ m_TextureData.Set(
+ QT3DSVec4((QT3DSF32)theDetails.m_Width, (QT3DSF32)theDetails.m_Height, theMixValue, 0.0f));
+ // I have no idea what these flags do.
+ m_TextureFlags.Set(1);
+ } else
+ m_TextureFlags.Set(0);
+ }
+
+ static STextureEntry CreateTextureEntry(NVRenderShaderProgram &inShader, const char *inStem,
+ Qt3DSString &inBuilder, Qt3DSString &inBuilder2)
+ {
+ inBuilder.assign(inStem);
+ inBuilder.append("Info");
+ inBuilder2.assign("flag");
+ inBuilder2.append(inStem);
+ return STextureEntry(inShader, inStem, inBuilder.c_str(), inBuilder2.c_str());
+ }
+};
+
+typedef eastl::pair<CRegisteredString, NVScopedRefCounted<STextureEntry>> TNamedTextureEntry;
+typedef eastl::pair<CRegisteredString, NVScopedRefCounted<SImageEntry>> TNamedImageEntry;
+typedef eastl::pair<CRegisteredString, NVScopedRefCounted<SDataBufferEntry>> TNamedDataBufferEntry;
+}
+
+namespace qt3ds {
+namespace render {
+
+ struct SEffectContext
+ {
+ CRegisteredString m_ClassName;
+ IQt3DSRenderContext &m_Context;
+ IResourceManager *m_ResourceManager;
+ nvvector<SAllocatedBufferEntry> m_AllocatedBuffers;
+ nvvector<SAllocatedImageEntry> m_AllocatedImages;
+ nvvector<SAllocatedDataBufferEntry> m_AllocatedDataBuffers;
+ nvvector<TNamedTextureEntry> m_TextureEntries;
+ nvvector<TNamedImageEntry> m_ImageEntries;
+ nvvector<TNamedDataBufferEntry> m_DataBufferEntries;
+
+ SEffectContext(CRegisteredString inName, IQt3DSRenderContext &ctx, IResourceManager *inManager)
+ : m_ClassName(inName)
+ , m_Context(ctx)
+ , m_ResourceManager(inManager)
+ , m_AllocatedBuffers(ctx.GetAllocator(), "SEffectContext::m_AllocatedBuffers")
+ , m_AllocatedImages(ctx.GetAllocator(), "SEffectContext::m_AllocatedImages")
+ , m_AllocatedDataBuffers(ctx.GetAllocator(), "SEffectContext::m_AllocatedDataBuffers")
+ , m_TextureEntries(ctx.GetAllocator(), "SEffectContext::m_TextureEntries")
+ , m_ImageEntries(ctx.GetAllocator(), "SEffectContext::m_ImageEntries")
+ , m_DataBufferEntries(ctx.GetAllocator(), "SEffectContext::m_DataBufferEntries")
+ {
+ }
+
+ ~SEffectContext()
+ {
+ while (m_AllocatedBuffers.size())
+ ReleaseBuffer(0);
+
+ while (m_AllocatedImages.size())
+ ReleaseImage(0);
+
+ while (m_AllocatedDataBuffers.size())
+ ReleaseDataBuffer(0);
+ }
+
+ void ReleaseBuffer(QT3DSU32 inIdx)
+ {
+ SAllocatedBufferEntry &theEntry(m_AllocatedBuffers[inIdx]);
+ theEntry.m_FrameBuffer->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer());
+ m_ResourceManager->Release(*theEntry.m_FrameBuffer);
+ m_ResourceManager->Release(*theEntry.m_Texture);
+ m_AllocatedBuffers.replace_with_last(inIdx);
+ }
+
+ void ReleaseImage(QT3DSU32 inIdx)
+ {
+ SAllocatedImageEntry &theEntry(m_AllocatedImages[inIdx]);
+ m_ResourceManager->Release(*theEntry.m_Image);
+ m_ResourceManager->Release(*theEntry.m_Texture);
+ m_AllocatedImages.replace_with_last(inIdx);
+ }
+
+ void ReleaseDataBuffer(QT3DSU32 inIdx)
+ {
+ SAllocatedDataBufferEntry &theEntry(m_AllocatedDataBuffers[inIdx]);
+ m_Context.GetAllocator().deallocate(theEntry.m_BufferData.begin());
+
+ m_AllocatedDataBuffers.replace_with_last(inIdx);
+ }
+
+ QT3DSU32 FindBuffer(CRegisteredString inName)
+ {
+ for (QT3DSU32 idx = 0, end = m_AllocatedBuffers.size(); idx < end; ++idx)
+ if (m_AllocatedBuffers[idx].m_Name == inName)
+ return idx;
+ return m_AllocatedBuffers.size();
+ }
+
+ QT3DSU32 FindImage(CRegisteredString inName)
+ {
+ for (QT3DSU32 idx = 0, end = m_AllocatedImages.size(); idx < end; ++idx)
+ if (m_AllocatedImages[idx].m_Name == inName)
+ return idx;
+
+ return m_AllocatedImages.size();
+ }
+
+ QT3DSU32 FindDataBuffer(CRegisteredString inName)
+ {
+ for (QT3DSU32 idx = 0, end = m_AllocatedDataBuffers.size(); idx < end; ++idx) {
+ if (m_AllocatedDataBuffers[idx].m_Name == inName)
+ return idx;
+ }
+
+ return m_AllocatedDataBuffers.size();
+ }
+
+ void SetTexture(NVRenderShaderProgram &inShader, CRegisteredString inPropName,
+ NVRenderTexture2D *inTexture, bool inNeedsMultiply,
+ Qt3DSString &inStringBuilder, Qt3DSString &inStringBuilder2,
+ const SPropertyDefinition *inPropDec = NULL)
+ {
+ STextureEntry *theTextureEntry(NULL);
+ for (QT3DSU32 idx = 0, end = m_TextureEntries.size(); idx < end && theTextureEntry == NULL;
+ ++idx) {
+ if (m_TextureEntries[idx].first == inPropName
+ && m_TextureEntries[idx].second->m_Shader.mPtr == &inShader)
+ theTextureEntry = m_TextureEntries[idx].second;
+ }
+ if (theTextureEntry == NULL) {
+ NVScopedRefCounted<STextureEntry> theNewEntry = QT3DS_NEW(
+ m_Context.GetAllocator(), STextureEntry)(STextureEntry::CreateTextureEntry(
+ inShader, inPropName, inStringBuilder, inStringBuilder2));
+ m_TextureEntries.push_back(eastl::make_pair(inPropName, theNewEntry));
+ theTextureEntry = theNewEntry.mPtr;
+ }
+ theTextureEntry->Set(inTexture, inNeedsMultiply, inPropDec);
+ }
+
+ void SetImage(NVRenderShaderProgram &inShader, CRegisteredString inPropName,
+ NVRenderImage2D *inImage)
+ {
+ SImageEntry *theImageEntry(NULL);
+ for (QT3DSU32 idx = 0, end = m_ImageEntries.size(); idx < end && theImageEntry == NULL;
+ ++idx) {
+ if (m_ImageEntries[idx].first == inPropName
+ && m_ImageEntries[idx].second->m_Shader.mPtr == &inShader)
+ theImageEntry = m_ImageEntries[idx].second;
+ }
+ if (theImageEntry == NULL) {
+ NVScopedRefCounted<SImageEntry> theNewEntry =
+ QT3DS_NEW(m_Context.GetAllocator(),
+ SImageEntry)(SImageEntry::CreateImageEntry(inShader, inPropName));
+ m_ImageEntries.push_back(eastl::make_pair(inPropName, theNewEntry));
+ theImageEntry = theNewEntry.mPtr;
+ }
+
+ theImageEntry->Set(inImage);
+ }
+
+ void SetDataBuffer(NVRenderShaderProgram &inShader, CRegisteredString inPropName,
+ qt3ds::render::NVRenderDataBuffer *inBuffer)
+ {
+ SDataBufferEntry *theDataBufferEntry(NULL);
+ for (QT3DSU32 idx = 0, end = m_DataBufferEntries.size();
+ idx < end && theDataBufferEntry == NULL; ++idx) {
+ if (m_DataBufferEntries[idx].first == inPropName
+ && m_DataBufferEntries[idx].second->m_Shader.mPtr == &inShader)
+ theDataBufferEntry = m_DataBufferEntries[idx].second;
+ }
+ if (theDataBufferEntry == NULL) {
+ NVScopedRefCounted<SDataBufferEntry> theNewEntry =
+ QT3DS_NEW(m_Context.GetAllocator(), SDataBufferEntry)(
+ SDataBufferEntry::CreateDataBufferEntry(inShader, inPropName));
+ m_DataBufferEntries.push_back(eastl::make_pair(inPropName, theNewEntry));
+ theDataBufferEntry = theNewEntry.mPtr;
+ }
+
+ theDataBufferEntry->Set(inBuffer);
+ }
+ };
+}
+}
+
+namespace {
+
+using qt3ds::render::NVRenderCachedShaderProperty;
+/* We setup some shared state on the effect shaders */
+struct SEffectShader
+{
+ NVScopedRefCounted<NVRenderShaderProgram> m_Shader;
+ NVRenderCachedShaderProperty<QT3DSMat44> m_MVP;
+ NVRenderCachedShaderProperty<QT3DSVec2> m_FragColorAlphaSettings;
+ NVRenderCachedShaderProperty<QT3DSVec2> m_DestSize;
+ NVRenderCachedShaderProperty<QT3DSF32> m_AppFrame;
+ NVRenderCachedShaderProperty<QT3DSF32> m_FPS;
+ NVRenderCachedShaderProperty<QT3DSVec2> m_CameraClipRange;
+ STextureEntry m_TextureEntry;
+ volatile QT3DSI32 mRefCount;
+ SEffectShader(NVRenderShaderProgram &inShader)
+ : m_Shader(inShader)
+ , m_MVP("ModelViewProjectionMatrix", inShader)
+ , m_FragColorAlphaSettings("FragColorAlphaSettings", inShader)
+ , m_DestSize("DestSize", inShader)
+ , m_AppFrame("AppFrame", inShader)
+ , m_FPS("FPS", inShader)
+ , m_CameraClipRange("CameraClipRange", inShader)
+ , m_TextureEntry(inShader, "Texture0", "Texture0Info", "Texture0Flags")
+ , mRefCount(0)
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Shader->GetRenderContext().GetAllocator())
+};
+
+struct SEffectSystem : public IEffectSystem
+{
+ typedef nvhash_map<CRegisteredString, char8_t *> TPathDataMap;
+ typedef nvhash_set<CRegisteredString> TPathSet;
+ typedef nvhash_map<CRegisteredString, NVScopedRefCounted<SEffectClass>> TEffectClassMap;
+ typedef nvhash_map<TStrStrPair, NVScopedRefCounted<SEffectShader>> TShaderMap;
+ typedef nvvector<SEffectContext *> TContextList;
+
+ IQt3DSRenderContextCore &m_CoreContext;
+ IQt3DSRenderContext *m_Context;
+ NVScopedRefCounted<IResourceManager> m_ResourceManager;
+ mutable qt3ds::render::SPreAllocatedAllocator m_Allocator;
+ // Keep from dual-including headers.
+ TEffectClassMap m_EffectClasses;
+ nvvector<CRegisteredString> m_EffectList;
+ TContextList m_Contexts;
+ Qt3DSString m_TextureStringBuilder;
+ Qt3DSString m_TextureStringBuilder2;
+ TShaderMap m_ShaderMap;
+ NVScopedRefCounted<NVRenderDepthStencilState> m_DefaultStencilState;
+ nvvector<NVScopedRefCounted<NVRenderDepthStencilState>> m_DepthStencilStates;
+ volatile QT3DSI32 mRefCount;
+
+ SEffectSystem(IQt3DSRenderContextCore &inContext)
+ : m_CoreContext(inContext)
+ , m_Context(NULL)
+ , m_Allocator(inContext.GetAllocator())
+ , m_EffectClasses(inContext.GetAllocator(), "SEffectSystem::m_EffectClasses")
+ , m_EffectList(inContext.GetAllocator(), "SEffectSystem::m_EffectList")
+ , m_Contexts(inContext.GetAllocator(), "SEffectSystem::m_Contexts")
+ , m_ShaderMap(inContext.GetAllocator(), "SEffectSystem::m_ShaderMap")
+ , m_DepthStencilStates(inContext.GetAllocator(), "SEffectSystem::m_DepthStencilStates")
+ , mRefCount(0)
+ {
+ }
+
+ ~SEffectSystem()
+ {
+ for (QT3DSU32 idx = 0, end = m_Contexts.size(); idx < end; ++idx)
+ NVDelete(m_Allocator, m_Contexts[idx]);
+ m_Contexts.clear();
+ }
+
+ SEffectContext &GetEffectContext(SEffect &inEffect)
+ {
+ if (inEffect.m_Context == NULL) {
+ inEffect.m_Context =
+ QT3DS_NEW(m_Allocator, SEffectContext)(inEffect.m_ClassName,
+ *m_Context, m_ResourceManager);
+ m_Contexts.push_back(inEffect.m_Context);
+ }
+ return *inEffect.m_Context;
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_CoreContext.GetAllocator());
+
+ SEffectClass *GetEffectClass(CRegisteredString inStr)
+ {
+ TEffectClassMap::iterator theIter = m_EffectClasses.find(inStr);
+ if (theIter != m_EffectClasses.end())
+ return theIter->second;
+ return NULL;
+ }
+ const SEffectClass *GetEffectClass(CRegisteredString inStr) const
+ {
+ return const_cast<SEffectSystem *>(this)->GetEffectClass(inStr);
+ }
+
+ bool IsEffectRegistered(CRegisteredString inStr) override
+ {
+ return GetEffectClass(inStr) != NULL;
+ }
+ NVConstDataRef<CRegisteredString> GetRegisteredEffects() override
+ {
+ m_EffectList.clear();
+ for (TEffectClassMap::iterator theIter = m_EffectClasses.begin(),
+ theEnd = m_EffectClasses.end();
+ theIter != theEnd; ++theIter)
+ m_EffectList.push_back(theIter->first);
+ return m_EffectList;
+ }
+
+ // Registers an effect that runs via a single GLSL file.
+ bool RegisterGLSLEffect(CRegisteredString inName, const char8_t *inPathToEffect,
+ NVConstDataRef<SPropertyDeclaration> inProperties) override
+ {
+ if (IsEffectRegistered(inName))
+ return false;
+
+ m_CoreContext.GetDynamicObjectSystemCore().Register(inName, inProperties, sizeof(SEffect),
+ GraphObjectTypes::Effect);
+ IDynamicObjectClass &theClass =
+ *m_CoreContext.GetDynamicObjectSystemCore().GetDynamicObjectClass(inName);
+
+ SEffectClass *theEffect = QT3DS_NEW(m_Allocator, SEffectClass)(m_Allocator, theClass);
+ m_EffectClasses.insert(eastl::make_pair(inName, theEffect));
+
+ // Setup the commands required to run this effect
+ StaticAssert<(sizeof(SBindShader) % 4 == 0)>::valid_expression();
+ StaticAssert<(sizeof(SApplyInstanceValue) % 4 == 0)>::valid_expression();
+ StaticAssert<(sizeof(SRender) % 4 == 0)>::valid_expression();
+
+ QT3DSU32 commandAllocationSize = sizeof(SBindTarget);
+ commandAllocationSize += sizeof(SBindShader);
+ commandAllocationSize += sizeof(SApplyInstanceValue) * inProperties.size();
+ commandAllocationSize += sizeof(SRender);
+
+ QT3DSU32 commandCount = 3 + inProperties.size();
+ QT3DSU32 commandPtrAllocationSize = commandCount * sizeof(SCommand *);
+ QT3DSU32 allocationSize = Align8(commandAllocationSize) + commandPtrAllocationSize;
+ QT3DSU8 *startBuffer =
+ (QT3DSU8 *)m_Allocator.allocate(allocationSize, "dynamic::SCommand", __FILE__, __LINE__);
+ QT3DSU8 *dataBuffer = startBuffer;
+ // Setup the command buffer such that the ptrs to the commands and the commands themselves
+ // are
+ // all in the same block of memory. This enables quicker iteration (trivially quicker, most
+ // likely)
+ // but it also enables simpler memory management (single free).
+ // Furthermore, for a single glsl file the effect properties map precisely into the
+ // glsl file itself.
+ SCommand **theFirstCommandPtr =
+ (reinterpret_cast<SCommand **>(dataBuffer + Align8(commandAllocationSize)));
+ SCommand **theCommandPtr = theFirstCommandPtr;
+ memZero(dataBuffer, commandAllocationSize);
+
+ new (dataBuffer) SBindTarget();
+ *theCommandPtr = (SCommand *)dataBuffer;
+ ++theCommandPtr;
+ dataBuffer += sizeof(SBindTarget);
+
+ new (dataBuffer) SBindShader(m_CoreContext.GetStringTable().RegisterStr(inPathToEffect));
+ *theCommandPtr = (SCommand *)dataBuffer;
+ ++theCommandPtr;
+ dataBuffer += sizeof(SBindShader);
+
+ for (QT3DSU32 idx = 0, end = inProperties.size(); idx < end; ++idx) {
+ const SPropertyDefinition &theDefinition(
+ theEffect->m_DynamicClass->GetProperties()[idx]);
+ new (dataBuffer) SApplyInstanceValue(theDefinition.m_Name, theDefinition.m_DataType,
+ theDefinition.m_Offset);
+ *theCommandPtr = (SCommand *)dataBuffer;
+ ++theCommandPtr;
+ dataBuffer += sizeof(SApplyInstanceValue);
+ }
+ new (dataBuffer) SRender(false);
+ *theCommandPtr = (SCommand *)dataBuffer;
+ ++theCommandPtr;
+ dataBuffer += sizeof(SRender);
+ // Ensure we end up *exactly* where we expected to.
+ QT3DS_ASSERT(dataBuffer == startBuffer + commandAllocationSize);
+ QT3DS_ASSERT(theCommandPtr - theFirstCommandPtr == (int)inProperties.size() + 3);
+ m_CoreContext.GetDynamicObjectSystemCore().SetRenderCommands(
+ inName, NVConstDataRef<SCommand *>(theFirstCommandPtr, commandCount));
+ m_Allocator.deallocate(startBuffer);
+ return true;
+ }
+
+ void SetEffectPropertyDefaultValue(CRegisteredString inName,
+ CRegisteredString inPropName,
+ NVConstDataRef<QT3DSU8> inDefaultData) override
+ {
+ m_CoreContext.GetDynamicObjectSystemCore().SetPropertyDefaultValue(inName, inPropName,
+ inDefaultData);
+ }
+
+ void SetEffectPropertyEnumNames(CRegisteredString inName, CRegisteredString inPropName,
+ NVConstDataRef<CRegisteredString> inNames) override
+ {
+ m_CoreContext.GetDynamicObjectSystemCore().SetPropertyEnumNames(inName, inPropName,
+ inNames);
+ }
+
+ bool RegisterEffect(CRegisteredString inName,
+ NVConstDataRef<SPropertyDeclaration> inProperties) override
+ {
+ if (IsEffectRegistered(inName))
+ return false;
+ m_CoreContext.GetDynamicObjectSystemCore().Register(inName, inProperties, sizeof(SEffect),
+ GraphObjectTypes::Effect);
+ IDynamicObjectClass &theClass =
+ *m_CoreContext.GetDynamicObjectSystemCore().GetDynamicObjectClass(inName);
+ SEffectClass *theEffect = QT3DS_NEW(m_Allocator, SEffectClass)(m_Allocator, theClass);
+ m_EffectClasses.insert(eastl::make_pair(inName, theEffect));
+ return true;
+ }
+
+ bool UnregisterEffect(CRegisteredString inName) override
+ {
+ if (!IsEffectRegistered(inName))
+ return false;
+
+ m_CoreContext.GetDynamicObjectSystemCore().Unregister(inName);
+
+ TEffectClassMap::iterator iter = m_EffectClasses.find(inName);
+ if (iter != m_EffectClasses.end())
+ m_EffectClasses.erase(iter);
+
+ for (QT3DSU32 idx = 0, end = m_Contexts.size(); idx < end; ++idx) {
+ if (m_Contexts[idx]->m_ClassName == inName)
+ ReleaseEffectContext(m_Contexts[idx]);
+ }
+ return true;
+ }
+
+ virtual NVConstDataRef<CRegisteredString>
+ GetEffectPropertyEnumNames(CRegisteredString inName, CRegisteredString inPropName) const override
+ {
+ const SEffectClass *theClass = GetEffectClass(inName);
+ if (theClass == NULL) {
+ QT3DS_ASSERT(false);
+ NVConstDataRef<CRegisteredString>();
+ }
+ const SPropertyDefinition *theDefinitionPtr =
+ theClass->m_DynamicClass->FindPropertyByName(inPropName);
+ if (theDefinitionPtr)
+ return theDefinitionPtr->m_EnumValueNames;
+ return NVConstDataRef<CRegisteredString>();
+ }
+
+ virtual NVConstDataRef<SPropertyDefinition>
+ GetEffectProperties(CRegisteredString inEffectName) const override
+ {
+ const SEffectClass *theClass = GetEffectClass(inEffectName);
+ if (theClass)
+ return theClass->m_DynamicClass->GetProperties();
+ return NVConstDataRef<SPropertyDefinition>();
+ }
+
+ void SetEffectPropertyTextureSettings(CRegisteredString inName,
+ CRegisteredString inPropName,
+ CRegisteredString inPropPath,
+ NVRenderTextureTypeValue::Enum inTexType,
+ NVRenderTextureCoordOp::Enum inCoordOp,
+ NVRenderTextureMagnifyingOp::Enum inMagFilterOp,
+ NVRenderTextureMinifyingOp::Enum inMinFilterOp) override
+ {
+ m_CoreContext.GetDynamicObjectSystemCore().SetPropertyTextureSettings(
+ inName, inPropName, inPropPath, inTexType, inCoordOp, inMagFilterOp, inMinFilterOp);
+ }
+
+ void SetEffectRequiresDepthTexture(CRegisteredString inEffectName, bool inValue) override
+ {
+ SEffectClass *theClass = GetEffectClass(inEffectName);
+ if (theClass == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ theClass->m_DynamicClass->SetRequiresDepthTexture(inValue);
+ }
+
+ bool DoesEffectRequireDepthTexture(CRegisteredString inEffectName) const override
+ {
+ const SEffectClass *theClass = GetEffectClass(inEffectName);
+ if (theClass == NULL) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ return theClass->m_DynamicClass->RequiresDepthTexture();
+ }
+
+ void SetEffectRequiresCompilation(CRegisteredString inEffectName, bool inValue) override
+ {
+ SEffectClass *theClass = GetEffectClass(inEffectName);
+ if (theClass == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ theClass->m_DynamicClass->SetRequiresCompilation(inValue);
+ }
+
+ bool DoesEffectRequireCompilation(CRegisteredString inEffectName) const override
+ {
+ const SEffectClass *theClass = GetEffectClass(inEffectName);
+ if (theClass == NULL) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+ return theClass->m_DynamicClass->RequiresCompilation();
+ }
+
+ void SetEffectCommands(CRegisteredString inEffectName,
+ NVConstDataRef<dynamic::SCommand *> inCommands) override
+ {
+ m_CoreContext.GetDynamicObjectSystemCore().SetRenderCommands(inEffectName, inCommands);
+ }
+
+ virtual NVConstDataRef<dynamic::SCommand *>
+ GetEffectCommands(CRegisteredString inEffectName) const override
+ {
+ return m_CoreContext.GetDynamicObjectSystemCore().GetRenderCommands(inEffectName);
+ }
+
+ SEffect *CreateEffectInstance(CRegisteredString inEffectName,
+ NVAllocatorCallback &inSceneGraphAllocator) override
+ {
+ SEffectClass *theClass = GetEffectClass(inEffectName);
+ if (theClass == NULL)
+ return NULL;
+ StaticAssert<(sizeof(SEffect) % 4 == 0)>::valid_expression();
+
+ SEffect *theEffect = (SEffect *)m_CoreContext.GetDynamicObjectSystemCore().CreateInstance(
+ inEffectName, inSceneGraphAllocator);
+ theEffect->Initialize();
+ return theEffect;
+ }
+
+ void AllocateBuffer(SEffect &inEffect, const SAllocateBuffer &inCommand, QT3DSU32 inFinalWidth,
+ QT3DSU32 inFinalHeight, NVRenderTextureFormats::Enum inSourceTextureFormat)
+ {
+ // Check to see if it is already allocated and if it is, is it the correct size. If both of
+ // these assumptions hold, then we are good.
+ NVRenderTexture2D *theBufferTexture = NULL;
+ QT3DSU32 theWidth =
+ ITextRenderer::NextMultipleOf4((QT3DSU32)(inFinalWidth * inCommand.m_SizeMultiplier));
+ QT3DSU32 theHeight =
+ ITextRenderer::NextMultipleOf4((QT3DSU32)(inFinalHeight * inCommand.m_SizeMultiplier));
+ NVRenderTextureFormats::Enum resultFormat = inCommand.m_Format;
+ if (resultFormat == NVRenderTextureFormats::Unknown)
+ resultFormat = inSourceTextureFormat;
+
+ if (inEffect.m_Context) {
+ SEffectContext &theContext(*inEffect.m_Context);
+ // size intentionally requiried every loop;
+ QT3DSU32 bufferIdx = theContext.FindBuffer(inCommand.m_Name);
+ if (bufferIdx < theContext.m_AllocatedBuffers.size()) {
+ SAllocatedBufferEntry &theEntry(theContext.m_AllocatedBuffers[bufferIdx]);
+ STextureDetails theDetails = theEntry.m_Texture->GetTextureDetails();
+ if (theDetails.m_Width == theWidth && theDetails.m_Height == theHeight
+ && theDetails.m_Format == resultFormat) {
+ theBufferTexture = theEntry.m_Texture;
+ } else {
+ theContext.ReleaseBuffer(bufferIdx);
+ }
+ }
+ }
+ if (theBufferTexture == NULL) {
+ SEffectContext &theContext(GetEffectContext(inEffect));
+ NVRenderFrameBuffer *theFB(m_ResourceManager->AllocateFrameBuffer());
+ NVRenderTexture2D *theTexture(
+ m_ResourceManager->AllocateTexture2D(theWidth, theHeight, resultFormat));
+ theTexture->SetMagFilter(inCommand.m_FilterOp);
+ theTexture->SetMinFilter(
+ static_cast<NVRenderTextureMinifyingOp::Enum>(inCommand.m_FilterOp));
+ theTexture->SetTextureWrapS(inCommand.m_TexCoordOp);
+ theTexture->SetTextureWrapT(inCommand.m_TexCoordOp);
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0, *theTexture);
+ theContext.m_AllocatedBuffers.push_back(SAllocatedBufferEntry(
+ inCommand.m_Name, *theFB, *theTexture, inCommand.m_BufferFlags));
+ theBufferTexture = theTexture;
+ }
+ }
+
+ void AllocateImage(SEffect &inEffect, const SAllocateImage &inCommand, QT3DSU32 inFinalWidth,
+ QT3DSU32 inFinalHeight)
+ {
+ NVRenderImage2D *theImage = NULL;
+ QT3DSU32 theWidth =
+ ITextRenderer::NextMultipleOf4((QT3DSU32)(inFinalWidth * inCommand.m_SizeMultiplier));
+ QT3DSU32 theHeight =
+ ITextRenderer::NextMultipleOf4((QT3DSU32)(inFinalHeight * inCommand.m_SizeMultiplier));
+
+ QT3DS_ASSERT(inCommand.m_Format != NVRenderTextureFormats::Unknown);
+
+ if (inEffect.m_Context) {
+ SEffectContext &theContext(*inEffect.m_Context);
+ // size intentionally requiried every loop;
+ QT3DSU32 imageIdx = theContext.FindImage(inCommand.m_Name);
+ if (imageIdx < theContext.m_AllocatedImages.size()) {
+ SAllocatedImageEntry &theEntry(theContext.m_AllocatedImages[imageIdx]);
+ STextureDetails theDetails = theEntry.m_Texture->GetTextureDetails();
+ if (theDetails.m_Width == theWidth && theDetails.m_Height == theHeight
+ && theDetails.m_Format == inCommand.m_Format) {
+ theImage = theEntry.m_Image;
+ } else {
+ theContext.ReleaseImage(imageIdx);
+ }
+ }
+ }
+
+ if (theImage == NULL) {
+ SEffectContext &theContext(GetEffectContext(inEffect));
+ // allocate an immutable texture
+ NVRenderTexture2D *theTexture(m_ResourceManager->AllocateTexture2D(
+ theWidth, theHeight, inCommand.m_Format, 1, true));
+ theTexture->SetMagFilter(inCommand.m_FilterOp);
+ theTexture->SetMinFilter(
+ static_cast<NVRenderTextureMinifyingOp::Enum>(inCommand.m_FilterOp));
+ theTexture->SetTextureWrapS(inCommand.m_TexCoordOp);
+ theTexture->SetTextureWrapT(inCommand.m_TexCoordOp);
+ NVRenderImage2D *theImage =
+ (m_ResourceManager->AllocateImage2D(theTexture, inCommand.m_Access));
+ theContext.m_AllocatedImages.push_back(SAllocatedImageEntry(
+ inCommand.m_Name, *theImage, *theTexture, inCommand.m_BufferFlags));
+ }
+ }
+
+ void AllocateDataBuffer(SEffect &inEffect, const SAllocateDataBuffer &inCommand)
+ {
+ QT3DSU32 theBufferSize = (QT3DSU32)inCommand.m_Size;
+ QT3DS_ASSERT(theBufferSize);
+ qt3ds::render::NVRenderDataBuffer *theDataBuffer = NULL;
+ qt3ds::render::NVRenderDataBuffer *theDataWrapBuffer = NULL;
+
+ if (inEffect.m_Context) {
+ SEffectContext &theContext(*inEffect.m_Context);
+ // size intentionally requiried every loop;
+ QT3DSU32 bufferIdx = theContext.FindDataBuffer(inCommand.m_Name);
+ if (bufferIdx < theContext.m_AllocatedDataBuffers.size()) {
+ SAllocatedDataBufferEntry &theEntry(theContext.m_AllocatedDataBuffers[bufferIdx]);
+ if (theEntry.m_BufferType == inCommand.m_DataBufferType
+ && theEntry.m_BufferData.size() == theBufferSize) {
+ theDataBuffer = theEntry.m_DataBuffer;
+ } else {
+ // if type and size don't match something is wrong
+ QT3DS_ASSERT(false);
+ }
+ }
+ }
+
+ if (theDataBuffer == NULL) {
+ SEffectContext &theContext(GetEffectContext(inEffect));
+ NVRenderContext &theRenderContext(m_Context->GetRenderContext());
+ QT3DSU8 *initialData = (QT3DSU8 *)theContext.m_Context.GetAllocator().allocate(
+ theBufferSize, "SEffectContext::AllocateDataBuffer", __FILE__, __LINE__);
+ NVDataRef<QT3DSU8> data((QT3DSU8 *)initialData, theBufferSize);
+ memset(initialData, 0x0L, theBufferSize);
+ if (inCommand.m_DataBufferType == NVRenderBufferBindValues::Storage) {
+ theDataBuffer = theRenderContext.CreateStorageBuffer(
+ inCommand.m_Name, qt3ds::render::NVRenderBufferUsageType::Dynamic, theBufferSize,
+ data, NULL);
+ } else if (inCommand.m_DataBufferType == NVRenderBufferBindValues::Draw_Indirect) {
+ QT3DS_ASSERT(theBufferSize == sizeof(qt3ds::render::DrawArraysIndirectCommand));
+ // init a draw call
+ QT3DSU32 *pIndirectDrawCall = (QT3DSU32 *)initialData;
+ // vertex count we draw points right now only
+ // the rest we fill in by GPU
+ pIndirectDrawCall[0] = 1;
+ theDataBuffer = theRenderContext.CreateDrawIndirectBuffer(
+ qt3ds::render::NVRenderBufferUsageType::Dynamic, theBufferSize, data);
+ } else
+ QT3DS_ASSERT(false);
+
+ theContext.m_AllocatedDataBuffers.push_back(SAllocatedDataBufferEntry(
+ inCommand.m_Name, *theDataBuffer, inCommand.m_DataBufferType, data,
+ inCommand.m_BufferFlags));
+
+ // create wrapper buffer
+ if (inCommand.m_DataBufferWrapType == NVRenderBufferBindValues::Storage
+ && inCommand.m_WrapName && theDataBuffer) {
+ theDataWrapBuffer = theRenderContext.CreateStorageBuffer(
+ inCommand.m_WrapName, qt3ds::render::NVRenderBufferUsageType::Dynamic,
+ theBufferSize, data, theDataBuffer);
+ theContext.m_AllocatedDataBuffers.push_back(SAllocatedDataBufferEntry(
+ inCommand.m_WrapName, *theDataWrapBuffer, inCommand.m_DataBufferWrapType,
+ NVDataRef<QT3DSU8>(), inCommand.m_BufferFlags));
+ }
+ }
+ }
+
+ NVRenderTexture2D *FindTexture(SEffect &inEffect, CRegisteredString inName)
+ {
+ if (inEffect.m_Context) {
+ SEffectContext &theContext(*inEffect.m_Context);
+ QT3DSU32 bufferIdx = theContext.FindBuffer(inName);
+ if (bufferIdx < theContext.m_AllocatedBuffers.size()) {
+ return theContext.m_AllocatedBuffers[bufferIdx].m_Texture;
+ }
+ }
+ QT3DS_ASSERT(false);
+ return NULL;
+ }
+
+ NVRenderFrameBuffer *BindBuffer(SEffect &inEffect, const SBindBuffer &inCommand,
+ QT3DSMat44 &outMVP, QT3DSVec2 &outDestSize)
+ {
+ NVRenderFrameBuffer *theBuffer = NULL;
+ NVRenderTexture2D *theTexture = NULL;
+ if (inEffect.m_Context) {
+ SEffectContext &theContext(*inEffect.m_Context);
+ QT3DSU32 bufferIdx = theContext.FindBuffer(inCommand.m_BufferName);
+ if (bufferIdx < theContext.m_AllocatedBuffers.size()) {
+ theBuffer = theContext.m_AllocatedBuffers[bufferIdx].m_FrameBuffer;
+ theTexture = theContext.m_AllocatedBuffers[bufferIdx].m_Texture;
+ theContext.m_AllocatedBuffers[bufferIdx].m_NeedsClear = false;
+ }
+ }
+ if (theBuffer == NULL) {
+ qCCritical(INVALID_OPERATION, "Effect %s: Failed to find buffer %s for bind",
+ inEffect.m_ClassName.c_str(), inCommand.m_BufferName.c_str());
+ QString errorMsg = QObject::tr("Failed to compile \"%1\" effect.\nConsider"
+ " removing it from the presentation.")
+ .arg(inEffect.m_ClassName.c_str());
+ QT3DS_ALWAYS_ASSERT_MESSAGE(errorMsg.toUtf8());
+ outMVP = QT3DSMat44::createIdentity();
+ return NULL;
+ }
+
+ if (theTexture) {
+ SCamera::SetupOrthographicCameraForOffscreenRender(*theTexture, outMVP);
+ STextureDetails theDetails(theTexture->GetTextureDetails());
+ m_Context->GetRenderContext().SetViewport(
+ NVRenderRect(0, 0, (QT3DSU32)theDetails.m_Width, (QT3DSU32)theDetails.m_Height));
+ outDestSize = QT3DSVec2((QT3DSF32)theDetails.m_Width, (QT3DSF32)theDetails.m_Height);
+ }
+
+ return theBuffer;
+ }
+
+ SEffectShader *BindShader(CRegisteredString &inEffectId, const SBindShader &inCommand)
+ {
+ SEffectClass *theClass = GetEffectClass(inEffectId);
+ if (!theClass) {
+ QT3DS_ASSERT(false);
+ return NULL;
+ }
+
+ bool forceCompilation = theClass->m_DynamicClass->RequiresCompilation();
+
+ eastl::pair<const TStrStrPair, NVScopedRefCounted<SEffectShader>> theInserter(
+ TStrStrPair(inCommand.m_ShaderPath, inCommand.m_ShaderDefine),
+ NVScopedRefCounted<SEffectShader>());
+ eastl::pair<TShaderMap::iterator, bool> theInsertResult(m_ShaderMap.insert(theInserter));
+
+ if (theInsertResult.second || forceCompilation) {
+ NVRenderShaderProgram *theProgram =
+ m_Context->GetDynamicObjectSystem()
+ .GetShaderProgram(inCommand.m_ShaderPath, inCommand.m_ShaderDefine,
+ TShaderFeatureSet(), SDynamicShaderProgramFlags(),
+ forceCompilation).first;
+ if (theProgram)
+ theInsertResult.first->second = QT3DS_NEW(m_Allocator, SEffectShader)(*theProgram);
+ }
+ if (theInsertResult.first->second) {
+ NVRenderContext &theContext(m_Context->GetRenderContext());
+ theContext.SetActiveShader(theInsertResult.first->second->m_Shader);
+ }
+
+ return theInsertResult.first->second;
+ }
+
+ void DoApplyInstanceValue(SEffect &inEffect, QT3DSU8 *inDataPtr, CRegisteredString inPropertyName,
+ NVRenderShaderDataTypes::Enum inPropertyType,
+ NVRenderShaderProgram &inShader,
+ const SPropertyDefinition &inDefinition)
+ {
+ qt3ds::render::NVRenderShaderConstantBase *theConstant =
+ inShader.GetShaderConstant(inPropertyName);
+ using namespace qt3ds::render;
+ if (theConstant) {
+ if (theConstant->GetShaderConstantType() == inPropertyType) {
+ if (inPropertyType == NVRenderShaderDataTypes::NVRenderTexture2DPtr) {
+ StaticAssert<sizeof(CRegisteredString)
+ == sizeof(NVRenderTexture2DPtr)>::valid_expression();
+ CRegisteredString *theStrPtr = reinterpret_cast<CRegisteredString *>(inDataPtr);
+ IBufferManager &theBufferManager(m_Context->GetBufferManager());
+ IOffscreenRenderManager &theOffscreenRenderer(
+ m_Context->GetOffscreenRenderManager());
+ bool needsAlphaMultiply = true;
+ NVRenderTexture2D *theTexture = nullptr;
+ if (theStrPtr->IsValid()) {
+ if (theOffscreenRenderer.HasOffscreenRenderer(*theStrPtr)) {
+ SOffscreenRenderResult theResult
+ = theOffscreenRenderer.GetRenderedItem(*theStrPtr);
+ needsAlphaMultiply = false;
+ theTexture = theResult.m_Texture;
+ } else {
+ SImageTextureData theTextureData
+ = theBufferManager.LoadRenderImage(*theStrPtr);
+ needsAlphaMultiply = true;
+ theTexture = theTextureData.m_Texture;
+ }
+ }
+ GetEffectContext(inEffect).SetTexture(
+ inShader, inPropertyName, theTexture, needsAlphaMultiply,
+ m_TextureStringBuilder, m_TextureStringBuilder2, &inDefinition);
+ } else if (inPropertyType == NVRenderShaderDataTypes::NVRenderImage2DPtr) {
+ StaticAssert<sizeof(CRegisteredString)
+ == sizeof(NVRenderTexture2DPtr)>::valid_expression();
+ NVRenderImage2D *theImage = NULL;
+ GetEffectContext(inEffect).SetImage(inShader, inPropertyName, theImage);
+ } else if (inPropertyType == NVRenderShaderDataTypes::NVRenderDataBufferPtr) {
+ // we don't handle this here
+ } else {
+ switch (inPropertyType) {
+#define HANDLE_QT3DS_SHADER_DATA_TYPE(type) \
+ case NVRenderShaderDataTypes::type: \
+ inShader.SetPropertyValue(theConstant, *(reinterpret_cast<type *>(inDataPtr))); \
+ break;
+ ITERATE_QT3DS_SHADER_DATA_TYPES
+#undef HANDLE_QT3DS_SHADER_DATA_TYPE
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ }
+ } else {
+ qCCritical(INVALID_OPERATION,
+ "Effect ApplyInstanceValue command datatype "
+ "and shader datatypes differ for property %s",
+ inPropertyName.c_str());
+ QT3DS_ASSERT(false);
+ }
+ }
+ }
+
+ void ApplyInstanceValue(SEffect &inEffect, SEffectClass &inClass,
+ NVRenderShaderProgram &inShader, const SApplyInstanceValue &inCommand)
+ {
+ // sanity check
+ if (inCommand.m_PropertyName.IsValid()) {
+ bool canGetData =
+ inCommand.m_ValueOffset + getSizeofShaderDataType(inCommand.m_ValueType)
+ <= inEffect.m_DataSectionByteSize;
+ if (canGetData == false) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ QT3DSU8 *dataPtr = inEffect.GetDataSectionBegin() + inCommand.m_ValueOffset;
+ const SPropertyDefinition *theDefinition =
+ inClass.m_DynamicClass->FindPropertyByName(inCommand.m_PropertyName);
+ if (theDefinition)
+ DoApplyInstanceValue(inEffect, dataPtr, inCommand.m_PropertyName,
+ inCommand.m_ValueType, inShader, *theDefinition);
+ } else {
+ NVConstDataRef<SPropertyDefinition> theDefs = inClass.m_DynamicClass->GetProperties();
+ for (QT3DSU32 idx = 0, end = theDefs.size(); idx < end; ++idx) {
+ const SPropertyDefinition &theDefinition(theDefs[idx]);
+ qt3ds::render::NVRenderShaderConstantBase *theConstant =
+ inShader.GetShaderConstant(theDefinition.m_Name);
+
+ // This is fine, the property wasn't found and we continue, no problem.
+ if (!theConstant)
+ continue;
+ QT3DSU8 *dataPtr = inEffect.GetDataSectionBegin() + theDefinition.m_Offset;
+ DoApplyInstanceValue(inEffect, dataPtr, theDefinition.m_Name,
+ theDefinition.m_DataType, inShader, theDefinition);
+ }
+ }
+ }
+
+ void ApplyValue(SEffect &inEffect, SEffectClass &inClass, NVRenderShaderProgram &inShader,
+ const SApplyValue &inCommand)
+ {
+ if (inCommand.m_PropertyName.IsValid()) {
+ QT3DSU8 *dataPtr = inCommand.m_Value.mData;
+ const SPropertyDefinition *theDefinition =
+ inClass.m_DynamicClass->FindPropertyByName(inCommand.m_PropertyName);
+ if (theDefinition)
+ DoApplyInstanceValue(inEffect, dataPtr, inCommand.m_PropertyName,
+ inCommand.m_ValueType, inShader, *theDefinition);
+ }
+ }
+
+ bool ApplyBlending(const SApplyBlending &inCommand)
+ {
+ NVRenderContext &theContext(m_Context->GetRenderContext());
+
+ theContext.SetBlendingEnabled(true);
+
+ qt3ds::render::NVRenderBlendFunctionArgument blendFunc =
+ qt3ds::render::NVRenderBlendFunctionArgument(
+ inCommand.m_SrcBlendFunc, inCommand.m_DstBlendFunc, inCommand.m_SrcBlendFunc,
+ inCommand.m_DstBlendFunc);
+
+ qt3ds::render::NVRenderBlendEquationArgument blendEqu(NVRenderBlendEquation::Add,
+ NVRenderBlendEquation::Add);
+
+ theContext.SetBlendFunction(blendFunc);
+ theContext.SetBlendEquation(blendEqu);
+
+ return true;
+ }
+
+ // This has the potential to change the source texture for the current render pass
+ SEffectTextureData ApplyBufferValue(SEffect &inEffect, NVRenderShaderProgram &inShader,
+ const SApplyBufferValue &inCommand,
+ NVRenderTexture2D &inSourceTexture,
+ SEffectTextureData inCurrentSourceTexture)
+ {
+ SEffectTextureData theTextureToBind;
+ if (inCommand.m_BufferName.IsValid()) {
+ if (inEffect.m_Context) {
+ SEffectContext &theContext(*inEffect.m_Context);
+ QT3DSU32 bufferIdx = theContext.FindBuffer(inCommand.m_BufferName);
+ if (bufferIdx < theContext.m_AllocatedBuffers.size()) {
+ SAllocatedBufferEntry &theEntry(theContext.m_AllocatedBuffers[bufferIdx]);
+ if (theEntry.m_NeedsClear) {
+ NVRenderContext &theRenderContext(m_Context->GetRenderContext());
+
+ theRenderContext.SetRenderTarget(theEntry.m_FrameBuffer);
+ // Note that depth/stencil buffers need an explicit clear in their bind
+ // commands in order to ensure
+ // we clear the least amount of information possible.
+
+ if (theEntry.m_Texture) {
+ NVRenderTextureFormats::Enum theTextureFormat =
+ theEntry.m_Texture->GetTextureDetails().m_Format;
+ if (theTextureFormat != NVRenderTextureFormats::Depth16
+ && theTextureFormat != NVRenderTextureFormats::Depth24
+ && theTextureFormat != NVRenderTextureFormats::Depth32
+ && theTextureFormat != NVRenderTextureFormats::Depth24Stencil8) {
+ NVRenderContextScopedProperty<QT3DSVec4> __clearColor(
+ theRenderContext, &NVRenderContext::GetClearColor,
+ &NVRenderContext::SetClearColor, QT3DSVec4(0.0f));
+ theRenderContext.Clear(qt3ds::render::NVRenderClearValues::Color);
+ }
+ }
+ theEntry.m_NeedsClear = false;
+ }
+ theTextureToBind = SEffectTextureData(theEntry.m_Texture, false);
+ }
+ }
+ if (theTextureToBind.m_Texture == NULL) {
+ QT3DS_ASSERT(false);
+ qCCritical(INVALID_OPERATION, "Effect %s: Failed to find buffer %s for bind",
+ inEffect.m_ClassName.c_str(), inCommand.m_BufferName.c_str());
+ QT3DS_ASSERT(false);
+ }
+ } else // no name means bind the source
+ theTextureToBind = SEffectTextureData(&inSourceTexture, false);
+
+ if (inCommand.m_ParamName.IsValid()) {
+ qt3ds::render::NVRenderShaderConstantBase *theConstant =
+ inShader.GetShaderConstant(inCommand.m_ParamName);
+
+ if (theConstant) {
+ if (theConstant->GetShaderConstantType()
+ != NVRenderShaderDataTypes::NVRenderTexture2DPtr) {
+ qCCritical(INVALID_OPERATION,
+ "Effect %s: Binding buffer to parameter %s that is not a texture",
+ inEffect.m_ClassName.c_str(), inCommand.m_ParamName.c_str());
+ QT3DS_ASSERT(false);
+ } else {
+ GetEffectContext(inEffect).SetTexture(
+ inShader, inCommand.m_ParamName, theTextureToBind.m_Texture,
+ theTextureToBind.m_NeedsAlphaMultiply, m_TextureStringBuilder,
+ m_TextureStringBuilder2);
+ }
+ }
+ return inCurrentSourceTexture;
+ } else {
+ return theTextureToBind;
+ }
+ }
+
+ void ApplyDepthValue(SEffect &inEffect, NVRenderShaderProgram &inShader,
+ const SApplyDepthValue &inCommand, NVRenderTexture2D *inTexture)
+ {
+ qt3ds::render::NVRenderShaderConstantBase *theConstant =
+ inShader.GetShaderConstant(inCommand.m_ParamName);
+
+ if (theConstant) {
+ if (theConstant->GetShaderConstantType()
+ != NVRenderShaderDataTypes::NVRenderTexture2DPtr) {
+ qCCritical(INVALID_OPERATION,
+ "Effect %s: Binding buffer to parameter %s that is not a texture",
+ inEffect.m_ClassName.c_str(), inCommand.m_ParamName.c_str());
+ QT3DS_ASSERT(false);
+ } else {
+ GetEffectContext(inEffect).SetTexture(inShader, inCommand.m_ParamName, inTexture,
+ false, m_TextureStringBuilder,
+ m_TextureStringBuilder2);
+ }
+ }
+ }
+
+ void ApplyImageValue(SEffect &inEffect, NVRenderShaderProgram &inShader,
+ const SApplyImageValue &inCommand)
+ {
+ SAllocatedImageEntry theImageToBind;
+ if (inCommand.m_ImageName.IsValid()) {
+ if (inEffect.m_Context) {
+ SEffectContext &theContext(*inEffect.m_Context);
+ QT3DSU32 bufferIdx = theContext.FindImage(inCommand.m_ImageName);
+ if (bufferIdx < theContext.m_AllocatedImages.size()) {
+ theImageToBind = SAllocatedImageEntry(theContext.m_AllocatedImages[bufferIdx]);
+ }
+ }
+ }
+
+ if (theImageToBind.m_Image == NULL) {
+ qCCritical(INVALID_OPERATION, "Effect %s: Failed to find image %s for bind",
+ inEffect.m_ClassName.c_str(), inCommand.m_ImageName.c_str());
+ QT3DS_ASSERT(false);
+ }
+
+ if (inCommand.m_ParamName.IsValid()) {
+ qt3ds::render::NVRenderShaderConstantBase *theConstant =
+ inShader.GetShaderConstant(inCommand.m_ParamName);
+
+ if (theConstant) {
+ if (inCommand.m_NeedSync) {
+ NVRenderBufferBarrierFlags flags(
+ qt3ds::render::NVRenderBufferBarrierValues::TextureFetch
+ | qt3ds::render::NVRenderBufferBarrierValues::TextureUpdate);
+ inShader.GetRenderContext().SetMemoryBarrier(flags);
+ }
+
+ if (theConstant->GetShaderConstantType()
+ == NVRenderShaderDataTypes::NVRenderImage2DPtr
+ && !inCommand.m_BindAsTexture) {
+ GetEffectContext(inEffect).SetImage(inShader, inCommand.m_ParamName,
+ theImageToBind.m_Image);
+ } else if (theConstant->GetShaderConstantType()
+ == NVRenderShaderDataTypes::NVRenderTexture2DPtr
+ && inCommand.m_BindAsTexture) {
+ GetEffectContext(inEffect).SetTexture(
+ inShader, inCommand.m_ParamName, theImageToBind.m_Texture, false,
+ m_TextureStringBuilder, m_TextureStringBuilder2);
+ } else {
+ qCCritical(INVALID_OPERATION,
+ "Effect %s: Binding buffer to parameter %s that is not a texture",
+ inEffect.m_ClassName.c_str(), inCommand.m_ParamName.c_str());
+ QT3DS_ASSERT(false);
+ }
+ }
+ }
+ }
+
+ void ApplyDataBufferValue(SEffect &inEffect, NVRenderShaderProgram &inShader,
+ const SApplyDataBufferValue &inCommand)
+ {
+ SAllocatedDataBufferEntry theBufferToBind;
+ if (inCommand.m_ParamName.IsValid()) {
+ if (inEffect.m_Context) {
+ SEffectContext &theContext(*inEffect.m_Context);
+ QT3DSU32 bufferIdx = theContext.FindDataBuffer(inCommand.m_ParamName);
+ if (bufferIdx < theContext.m_AllocatedDataBuffers.size()) {
+ theBufferToBind =
+ SAllocatedDataBufferEntry(theContext.m_AllocatedDataBuffers[bufferIdx]);
+ if (theBufferToBind.m_NeedsClear) {
+ NVDataRef<QT3DSU8> pData = theBufferToBind.m_DataBuffer->MapBuffer();
+ memset(pData.begin(), 0x0L, theBufferToBind.m_BufferData.size());
+ theBufferToBind.m_DataBuffer->UnmapBuffer();
+ theBufferToBind.m_NeedsClear = false;
+ }
+ }
+ }
+
+ if (theBufferToBind.m_DataBuffer == NULL) {
+ qCCritical(INVALID_OPERATION, "Effect %s: Failed to find buffer %s for bind",
+ inEffect.m_ClassName.c_str(), inCommand.m_ParamName.c_str());
+ QT3DS_ASSERT(false);
+ }
+
+ qt3ds::render::NVRenderShaderBufferBase *theConstant =
+ inShader.GetShaderBuffer(inCommand.m_ParamName);
+
+ if (theConstant) {
+ GetEffectContext(inEffect).SetDataBuffer(inShader, inCommand.m_ParamName,
+ theBufferToBind.m_DataBuffer);
+ } else if (theBufferToBind.m_BufferType
+ == qt3ds::render::NVRenderBufferBindValues::Draw_Indirect) {
+ // since we filled part of this buffer on the GPU we need a sync before usage
+ NVRenderBufferBarrierFlags flags(
+ qt3ds::render::NVRenderBufferBarrierValues::CommandBuffer);
+ inShader.GetRenderContext().SetMemoryBarrier(flags);
+ }
+ }
+ }
+
+ void ApplyRenderStateValue(NVRenderFrameBuffer *inTarget,
+ NVRenderTexture2D *inDepthStencilTexture,
+ const SApplyRenderState &theCommand)
+ {
+ NVRenderContext &theContext(m_Context->GetRenderContext());
+ QT3DSU32 inState = (QT3DSU32)theCommand.m_RenderState;
+ bool inEnable = theCommand.m_Enabled;
+
+ switch (inState) {
+ case NVRenderState::StencilTest: {
+ if (inEnable && inTarget) {
+ inTarget->Attach(NVRenderFrameBufferAttachments::DepthStencil,
+ *inDepthStencilTexture);
+ } else if (inTarget) {
+ inTarget->Attach(NVRenderFrameBufferAttachments::DepthStencil,
+ NVRenderTextureOrRenderBuffer());
+ }
+
+ theContext.SetStencilTestEnabled(inEnable);
+ } break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ }
+
+ static bool CompareDepthStencilState(NVRenderDepthStencilState &inState,
+ SDepthStencil &inStencil)
+ {
+ qt3ds::render::NVRenderStencilFunctionArgument theFunction =
+ inState.GetStencilFunc(qt3ds::render::NVRenderFaces::Front);
+ qt3ds::render::NVRenderStencilOperationArgument theOperation =
+ inState.GetStencilOp(qt3ds::render::NVRenderFaces::Front);
+
+ return theFunction.m_Function == inStencil.m_StencilFunction
+ && theFunction.m_Mask == inStencil.m_Mask
+ && theFunction.m_ReferenceValue == inStencil.m_Reference
+ && theOperation.m_StencilFail == inStencil.m_StencilFailOperation
+ && theOperation.m_DepthFail == inStencil.m_DepthFailOperation
+ && theOperation.m_DepthPass == inStencil.m_DepthPassOperation;
+ }
+
+ void RenderPass(SEffectShader &inShader, const QT3DSMat44 &inMVP,
+ SEffectTextureData inSourceTexture, NVRenderFrameBuffer *inFrameBuffer,
+ QT3DSVec2 &inDestSize, const QT3DSVec2 &inCameraClipRange,
+ NVRenderTexture2D *inDepthStencil, Option<SDepthStencil> inDepthStencilCommand,
+ bool drawIndirect)
+ {
+ NVRenderContext &theContext(m_Context->GetRenderContext());
+ theContext.SetRenderTarget(inFrameBuffer);
+ if (inDepthStencil && inFrameBuffer) {
+ inFrameBuffer->Attach(NVRenderFrameBufferAttachments::DepthStencil, *inDepthStencil);
+ if (inDepthStencilCommand.hasValue()) {
+ SDepthStencil &theDepthStencil(*inDepthStencilCommand);
+ QT3DSU32 clearFlags = 0;
+ if (theDepthStencil.m_Flags.HasClearStencil())
+ clearFlags |= NVRenderClearValues::Stencil;
+ if (theDepthStencil.m_Flags.HasClearDepth())
+ clearFlags |= NVRenderClearValues::Depth;
+
+ if (clearFlags)
+ theContext.Clear(qt3ds::render::NVRenderClearFlags(clearFlags));
+
+ NVRenderDepthStencilState *targetState = NULL;
+ for (QT3DSU32 idx = 0, end = m_DepthStencilStates.size();
+ idx < end && targetState == NULL; ++idx) {
+ NVRenderDepthStencilState &theState = *m_DepthStencilStates[idx];
+ if (CompareDepthStencilState(theState, theDepthStencil))
+ targetState = &theState;
+ }
+ if (targetState == NULL) {
+ qt3ds::render::NVRenderStencilFunctionArgument theFunctionArg(
+ theDepthStencil.m_StencilFunction, theDepthStencil.m_Reference,
+ theDepthStencil.m_Mask);
+ qt3ds::render::NVRenderStencilOperationArgument theOpArg(
+ theDepthStencil.m_StencilFailOperation,
+ theDepthStencil.m_DepthFailOperation, theDepthStencil.m_DepthPassOperation);
+ targetState = theContext.CreateDepthStencilState(
+ theContext.IsDepthTestEnabled(), theContext.IsDepthWriteEnabled(),
+ theContext.GetDepthFunction(), true, theFunctionArg, theFunctionArg,
+ theOpArg, theOpArg);
+ m_DepthStencilStates.push_back(targetState);
+ }
+ theContext.SetDepthStencilState(targetState);
+ }
+ }
+
+ theContext.SetActiveShader(inShader.m_Shader);
+ inShader.m_MVP.Set(inMVP);
+ if (inSourceTexture.m_Texture) {
+ inShader.m_TextureEntry.Set(inSourceTexture.m_Texture,
+ inSourceTexture.m_NeedsAlphaMultiply, NULL);
+ } else {
+ qCCritical(INTERNAL_ERROR, "Failed to setup pass due to null source texture");
+ QT3DS_ASSERT(false);
+ }
+ inShader.m_FragColorAlphaSettings.Set(QT3DSVec2(1.0f, 0.0f));
+ inShader.m_DestSize.Set(inDestSize);
+ if (inShader.m_AppFrame.IsValid())
+ inShader.m_AppFrame.Set((QT3DSF32)m_Context->GetFrameCount());
+ if (inShader.m_FPS.IsValid())
+ inShader.m_FPS.Set((QT3DSF32)m_Context->GetFPS().first);
+ if (inShader.m_CameraClipRange.IsValid())
+ inShader.m_CameraClipRange.Set(inCameraClipRange);
+
+ if (!drawIndirect)
+ m_Context->GetRenderer().RenderQuad();
+ else
+ m_Context->GetRenderer().RenderPointsIndirect();
+
+ if (inDepthStencil && inFrameBuffer) {
+ inFrameBuffer->Attach(NVRenderFrameBufferAttachments::DepthStencil,
+ NVRenderTextureOrRenderBuffer());
+ theContext.SetDepthStencilState(m_DefaultStencilState);
+ }
+ }
+
+ void DoRenderEffect(SEffect &inEffect, SEffectClass &inClass,
+ NVRenderTexture2D &inSourceTexture, QT3DSMat44 &inMVP,
+ NVRenderFrameBuffer *inTarget, bool inEnableBlendWhenRenderToTarget,
+ NVRenderTexture2D *inDepthTexture, NVRenderTexture2D *inDepthStencilTexture,
+ const QT3DSVec2 inCameraClipRange)
+ {
+ // Run through the effect commands and render the effect.
+ // NVRenderTexture2D* theCurrentTexture(&inSourceTexture);
+ NVRenderContext &theContext = m_Context->GetRenderContext();
+
+ // Context variables that are updated during the course of a pass.
+ SEffectTextureData theCurrentSourceTexture(&inSourceTexture, false);
+ NVRenderTexture2D *theCurrentDepthStencilTexture = NULL;
+ NVRenderFrameBuffer *theCurrentRenderTarget(inTarget);
+ SEffectShader *theCurrentShader(NULL);
+ NVRenderRect theOriginalViewport(theContext.GetViewport());
+ bool wasScissorEnabled = theContext.IsScissorTestEnabled();
+ bool wasBlendingEnabled = theContext.IsBlendingEnabled();
+ // save current blending setup
+ qt3ds::render::NVRenderBlendFunctionArgument theBlendFunc = theContext.GetBlendFunction();
+ qt3ds::render::NVRenderBlendEquationArgument theBlendEqu = theContext.GetBlendEquation();
+ bool intermediateBlendingEnabled = false;
+ STextureDetails theDetails(inSourceTexture.GetTextureDetails());
+ QT3DSU32 theFinalWidth = (QT3DSU32)(theDetails.m_Width);
+ QT3DSU32 theFinalHeight = (QT3DSU32)(theDetails.m_Height);
+ QT3DSVec2 theDestSize;
+ {
+ // Ensure no matter the command run goes we replace the rendering system to some
+ // semblance of the approprate
+ // setting.
+ NVRenderContextScopedProperty<NVRenderFrameBuffer *> __framebuffer(
+ theContext, &NVRenderContext::GetRenderTarget, &NVRenderContext::SetRenderTarget);
+ NVRenderContextScopedProperty<NVRenderRect> __viewport(
+ theContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport);
+ NVRenderContextScopedProperty<bool> __scissorEnabled(
+ theContext, &NVRenderContext::IsScissorTestEnabled,
+ &NVRenderContext::SetScissorTestEnabled);
+ NVRenderContextScopedProperty<bool> __stencilTest(
+ theContext, &NVRenderContext::IsStencilTestEnabled,
+ &NVRenderContext::SetStencilTestEnabled);
+ NVRenderContextScopedProperty<qt3ds::render::NVRenderBoolOp::Enum> __depthFunction(
+ theContext, &NVRenderContext::GetDepthFunction, &NVRenderContext::SetDepthFunction);
+ Option<SDepthStencil> theCurrentDepthStencil;
+
+ theContext.SetScissorTestEnabled(false);
+ theContext.SetBlendingEnabled(false);
+ theContext.SetCullingEnabled(false);
+ theContext.SetDepthTestEnabled(false);
+ theContext.SetDepthWriteEnabled(false);
+
+ QT3DSMat44 theMVP(QT3DSMat44::createIdentity());
+ NVConstDataRef<dynamic::SCommand *> theCommands =
+ inClass.m_DynamicClass->GetRenderCommands();
+ for (QT3DSU32 commandIdx = 0, commandEnd = theCommands.size(); commandIdx < commandEnd;
+ ++commandIdx) {
+ const SCommand &theCommand(*theCommands[commandIdx]);
+ switch (theCommand.m_Type) {
+ case CommandTypes::AllocateBuffer:
+ AllocateBuffer(inEffect, static_cast<const SAllocateBuffer &>(theCommand),
+ theFinalWidth, theFinalHeight, theDetails.m_Format);
+ break;
+
+ case CommandTypes::AllocateImage:
+ AllocateImage(inEffect, static_cast<const SAllocateImage &>(theCommand),
+ theFinalWidth, theFinalHeight);
+ break;
+
+ case CommandTypes::AllocateDataBuffer:
+ AllocateDataBuffer(inEffect,
+ static_cast<const SAllocateDataBuffer &>(theCommand));
+ break;
+
+ case CommandTypes::BindBuffer:
+ theCurrentRenderTarget =
+ BindBuffer(inEffect, static_cast<const SBindBuffer &>(theCommand), theMVP,
+ theDestSize);
+ break;
+
+ case CommandTypes::BindTarget: {
+ m_Context->GetRenderContext().SetRenderTarget(inTarget);
+ theCurrentRenderTarget = inTarget;
+ theMVP = inMVP;
+ theContext.SetViewport(theOriginalViewport);
+ theDestSize = QT3DSVec2((QT3DSF32)theFinalWidth, (QT3DSF32)theFinalHeight);
+ // This isn't necessary if we are rendering to an offscreen buffer and not
+ // compositing
+ // with other objects.
+ if (inEnableBlendWhenRenderToTarget) {
+ theContext.SetBlendingEnabled(wasBlendingEnabled);
+ theContext.SetScissorTestEnabled(wasScissorEnabled);
+ // The blending setup was done before we apply the effect
+ theContext.SetBlendFunction(theBlendFunc);
+ theContext.SetBlendEquation(theBlendEqu);
+ }
+ } break;
+ case CommandTypes::BindShader:
+ theCurrentShader = BindShader(inEffect.m_ClassName,
+ static_cast<const SBindShader &>(theCommand));
+ break;
+ case CommandTypes::ApplyInstanceValue:
+ if (theCurrentShader)
+ ApplyInstanceValue(inEffect, inClass, *theCurrentShader->m_Shader,
+ static_cast<const SApplyInstanceValue &>(theCommand));
+ break;
+ case CommandTypes::ApplyValue:
+ if (theCurrentShader)
+ ApplyValue(inEffect, inClass, *theCurrentShader->m_Shader,
+ static_cast<const SApplyValue &>(theCommand));
+ break;
+ case CommandTypes::ApplyBlending:
+ intermediateBlendingEnabled =
+ ApplyBlending(static_cast<const SApplyBlending &>(theCommand));
+ break;
+ case CommandTypes::ApplyBufferValue:
+ if (theCurrentShader)
+ theCurrentSourceTexture =
+ ApplyBufferValue(inEffect, *theCurrentShader->m_Shader,
+ static_cast<const SApplyBufferValue &>(theCommand),
+ inSourceTexture, theCurrentSourceTexture);
+ break;
+ case CommandTypes::ApplyDepthValue:
+ if (theCurrentShader)
+ ApplyDepthValue(inEffect, *theCurrentShader->m_Shader,
+ static_cast<const SApplyDepthValue &>(theCommand),
+ inDepthTexture);
+ if (!inDepthTexture) {
+ qCCritical(INVALID_OPERATION,
+ "Depth value command detected but no "
+ "depth buffer provided for effect %s",
+ inEffect.m_ClassName.c_str());
+ QT3DS_ASSERT(false);
+ }
+ break;
+ case CommandTypes::ApplyImageValue:
+ if (theCurrentShader)
+ ApplyImageValue(inEffect, *theCurrentShader->m_Shader,
+ static_cast<const SApplyImageValue &>(theCommand));
+ break;
+ case CommandTypes::ApplyDataBufferValue:
+ if (theCurrentShader)
+ ApplyDataBufferValue(
+ inEffect, *theCurrentShader->m_Shader,
+ static_cast<const SApplyDataBufferValue &>(theCommand));
+ break;
+ case CommandTypes::DepthStencil: {
+ const SDepthStencil &theDepthStencil =
+ static_cast<const SDepthStencil &>(theCommand);
+ theCurrentDepthStencilTexture =
+ FindTexture(inEffect, theDepthStencil.m_BufferName);
+ if (theCurrentDepthStencilTexture)
+ theCurrentDepthStencil = theDepthStencil;
+ } break;
+ case CommandTypes::Render:
+ if (theCurrentShader && theCurrentSourceTexture.m_Texture) {
+ RenderPass(*theCurrentShader, theMVP, theCurrentSourceTexture,
+ theCurrentRenderTarget, theDestSize, inCameraClipRange,
+ theCurrentDepthStencilTexture, theCurrentDepthStencil,
+ static_cast<const SRender &>(theCommand).m_DrawIndirect);
+ }
+ // Reset the source texture regardless
+ theCurrentSourceTexture = SEffectTextureData(&inSourceTexture, false);
+ theCurrentDepthStencilTexture = NULL;
+ theCurrentDepthStencil = Option<SDepthStencil>();
+ // reset intermediate blending state
+ if (intermediateBlendingEnabled) {
+ theContext.SetBlendingEnabled(false);
+ intermediateBlendingEnabled = false;
+ }
+ break;
+ case CommandTypes::ApplyRenderState:
+ ApplyRenderStateValue(theCurrentRenderTarget, inDepthStencilTexture,
+ static_cast<const SApplyRenderState &>(theCommand));
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ }
+
+ SetEffectRequiresCompilation(inEffect.m_ClassName, false);
+
+ // reset to default stencil state
+ if (inDepthStencilTexture) {
+ theContext.SetDepthStencilState(m_DefaultStencilState);
+ }
+
+ // Release any per-frame buffers
+ if (inEffect.m_Context) {
+ SEffectContext &theContext(*inEffect.m_Context);
+ // Query for size on every loop intentional
+ for (QT3DSU32 idx = 0; idx < theContext.m_AllocatedBuffers.size(); ++idx) {
+ if (theContext.m_AllocatedBuffers[idx].m_Flags.IsSceneLifetime() == false) {
+ theContext.ReleaseBuffer(idx);
+ --idx;
+ }
+ }
+ for (QT3DSU32 idx = 0; idx < theContext.m_AllocatedImages.size(); ++idx) {
+ if (theContext.m_AllocatedImages[idx].m_Flags.IsSceneLifetime() == false) {
+ theContext.ReleaseImage(idx);
+ --idx;
+ }
+ }
+ }
+ }
+ }
+
+ NVRenderTexture2D *RenderEffect(SEffectRenderArgument inRenderArgument) override
+ {
+ SEffectClass *theClass = GetEffectClass(inRenderArgument.m_Effect.m_ClassName);
+ if (!theClass) {
+ QT3DS_ASSERT(false);
+ return NULL;
+ }
+ QT3DSMat44 theMVP;
+ SCamera::SetupOrthographicCameraForOffscreenRender(inRenderArgument.m_ColorBuffer, theMVP);
+ // setup a render target
+ NVRenderContext &theContext(m_Context->GetRenderContext());
+ IResourceManager &theManager(m_Context->GetResourceManager());
+ NVRenderContextScopedProperty<NVRenderFrameBuffer *> __framebuffer(
+ theContext, &NVRenderContext::GetRenderTarget, &NVRenderContext::SetRenderTarget);
+ STextureDetails theDetails(inRenderArgument.m_ColorBuffer.GetTextureDetails());
+ QT3DSU32 theFinalWidth = ITextRenderer::NextMultipleOf4((QT3DSU32)(theDetails.m_Width));
+ QT3DSU32 theFinalHeight = ITextRenderer::NextMultipleOf4((QT3DSU32)(theDetails.m_Height));
+ NVRenderFrameBuffer *theBuffer = theManager.AllocateFrameBuffer();
+ // UdoL Some Effects may need to run before HDR tonemap. This means we need to keep the
+ // input format
+ NVRenderTextureFormats::Enum theOutputFormat = NVRenderTextureFormats::RGBA8;
+ if (theClass->m_DynamicClass->GetOutputTextureFormat() == NVRenderTextureFormats::Unknown)
+ theOutputFormat = theDetails.m_Format;
+ NVRenderTexture2D *theTargetTexture =
+ theManager.AllocateTexture2D(theFinalWidth, theFinalHeight, theOutputFormat);
+ theBuffer->Attach(NVRenderFrameBufferAttachments::Color0, *theTargetTexture);
+ theContext.SetRenderTarget(theBuffer);
+ NVRenderContextScopedProperty<NVRenderRect> __viewport(
+ theContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport,
+ NVRenderRect(0, 0, theFinalWidth, theFinalHeight));
+
+ NVRenderContextScopedProperty<bool> __scissorEnable(
+ theContext, &NVRenderContext::IsScissorTestEnabled,
+ &NVRenderContext::SetScissorTestEnabled, false);
+
+ DoRenderEffect(inRenderArgument.m_Effect, *theClass, inRenderArgument.m_ColorBuffer, theMVP,
+ m_Context->GetRenderContext().GetRenderTarget(), false,
+ inRenderArgument.m_DepthTexture, inRenderArgument.m_DepthStencilBuffer,
+ inRenderArgument.m_CameraClipRange);
+
+ theBuffer->Attach(NVRenderFrameBufferAttachments::Color0, NVRenderTextureOrRenderBuffer());
+ theManager.Release(*theBuffer);
+ return theTargetTexture;
+ }
+
+ // Render the effect to the currently bound render target using this MVP
+ bool RenderEffect(SEffectRenderArgument inRenderArgument, QT3DSMat44 &inMVP,
+ bool inEnableBlendWhenRenderToTarget) override
+ {
+ SEffectClass *theClass = GetEffectClass(inRenderArgument.m_Effect.m_ClassName);
+ if (!theClass) {
+ QT3DS_ASSERT(false);
+ return false;
+ }
+
+ DoRenderEffect(inRenderArgument.m_Effect, *theClass, inRenderArgument.m_ColorBuffer, inMVP,
+ m_Context->GetRenderContext().GetRenderTarget(),
+ inEnableBlendWhenRenderToTarget, inRenderArgument.m_DepthTexture,
+ inRenderArgument.m_DepthStencilBuffer, inRenderArgument.m_CameraClipRange);
+ return true;
+ }
+
+ void ReleaseEffectContext(SEffectContext *inContext) override
+ {
+ if (inContext == NULL)
+ return;
+ for (QT3DSU32 idx = 0, end = m_Contexts.size(); idx < end; ++idx) {
+ if (m_Contexts[idx] == inContext) {
+ m_Contexts.replace_with_last(idx);
+ NVDelete(m_Allocator, inContext);
+ }
+ }
+ }
+
+ void ResetEffectFrameData(SEffectContext &inContext) override
+ { // Query for size on every loop intentional
+ for (QT3DSU32 idx = 0; idx < inContext.m_AllocatedBuffers.size(); ++idx) {
+ SAllocatedBufferEntry &theBuffer(inContext.m_AllocatedBuffers[idx]);
+ if (theBuffer.m_Flags.IsSceneLifetime() == true)
+ theBuffer.m_NeedsClear = true;
+ }
+ for (QT3DSU32 idx = 0; idx < inContext.m_AllocatedDataBuffers.size(); ++idx) {
+ SAllocatedDataBufferEntry &theDataBuffer(inContext.m_AllocatedDataBuffers[idx]);
+ if (theDataBuffer.m_Flags.IsSceneLifetime() == true)
+ theDataBuffer.m_NeedsClear = true;
+ }
+ }
+
+ void SetShaderData(CRegisteredString path, const char8_t *data,
+ const char8_t *inShaderType, const char8_t *inShaderVersion,
+ bool inHasGeomShader, bool inIsComputeShader) override
+ {
+ m_CoreContext.GetDynamicObjectSystemCore().SetShaderData(
+ path, data, inShaderType, inShaderVersion, inHasGeomShader, inIsComputeShader);
+ }
+
+ void Save(qt3ds::render::SWriteBuffer &ioBuffer,
+ const qt3ds::render::SStrRemapMap &inRemapMap, const char8_t *inProjectDir) const override
+ {
+ ioBuffer.write((QT3DSU32)m_EffectClasses.size());
+ SStringSaveRemapper theRemapper(m_Allocator, inRemapMap, inProjectDir,
+ m_CoreContext.GetStringTable());
+ for (TEffectClassMap::const_iterator theIter = m_EffectClasses.begin(),
+ end = m_EffectClasses.end();
+ theIter != end; ++theIter) {
+ const SEffectClass &theClass = *theIter->second;
+ CRegisteredString theClassName = theClass.m_DynamicClass->GetId();
+ theClassName.Remap(inRemapMap);
+ ioBuffer.write(theClassName);
+ // Effect classes do not store any additional data from the dynamic object class.
+ ioBuffer.write(theClass);
+ }
+ }
+
+ void Load(NVDataRef<QT3DSU8> inData, CStrTableOrDataRef inStrDataBlock,
+ const char8_t *inProjectDir) override
+ {
+ m_Allocator.m_PreAllocatedBlock = inData;
+ m_Allocator.m_OwnsMemory = false;
+ qt3ds::render::SDataReader theReader(inData.begin(), inData.end());
+ QT3DSU32 numEffectClasses = theReader.LoadRef<QT3DSU32>();
+ SStringLoadRemapper theRemapper(m_Allocator, inStrDataBlock, inProjectDir,
+ m_CoreContext.GetStringTable());
+ for (QT3DSU32 idx = 0, end = numEffectClasses; idx < end; ++idx) {
+ CRegisteredString theClassName = theReader.LoadRef<CRegisteredString>();
+ theClassName.Remap(inStrDataBlock);
+ IDynamicObjectClass *theBaseClass =
+ m_CoreContext.GetDynamicObjectSystemCore().GetDynamicObjectClass(theClassName);
+ if (theBaseClass == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ SEffectClass *theClass = theReader.Load<SEffectClass>();
+ theClass->SetupThisObjectFromMemory(m_Allocator, *theBaseClass);
+ NVScopedRefCounted<SEffectClass> theClassPtr(theClass);
+ m_EffectClasses.insert(eastl::make_pair(theBaseClass->GetId(), theClassPtr));
+ }
+ }
+
+ IEffectSystem &GetEffectSystem(IQt3DSRenderContext &context) override
+ {
+ m_Context = &context;
+
+ NVRenderContext &theContext(m_Context->GetRenderContext());
+
+ m_ResourceManager = &IResourceManager::CreateResourceManager(theContext);
+
+ // create default stencil state
+ qt3ds::render::NVRenderStencilFunctionArgument stencilDefaultFunc(
+ qt3ds::render::NVRenderBoolOp::AlwaysTrue, 0x0, 0xFF);
+ qt3ds::render::NVRenderStencilOperationArgument stencilDefaultOp(
+ qt3ds::render::NVRenderStencilOp::Keep, qt3ds::render::NVRenderStencilOp::Keep,
+ qt3ds::render::NVRenderStencilOp::Keep);
+ m_DefaultStencilState = theContext.CreateDepthStencilState(
+ theContext.IsDepthTestEnabled(), theContext.IsDepthWriteEnabled(),
+ theContext.GetDepthFunction(), theContext.IsStencilTestEnabled(), stencilDefaultFunc,
+ stencilDefaultFunc, stencilDefaultOp, stencilDefaultOp);
+
+ return *this;
+ }
+
+ IResourceManager &GetResourceManager() override
+ {
+ return *m_ResourceManager;
+ }
+
+ void renderSubpresentations(SEffect &inEffect) override
+ {
+ SEffectClass *theClass = GetEffectClass(inEffect.m_ClassName);
+ if (!theClass)
+ return;
+
+ NVConstDataRef<SPropertyDefinition> theDefs = theClass->m_DynamicClass->GetProperties();
+ for (QT3DSU32 idx = 0, end = theDefs.size(); idx < end; ++idx) {
+ const SPropertyDefinition &theDefinition(theDefs[idx]);
+ if (theDefinition.m_DataType == NVRenderShaderDataTypes::NVRenderTexture2DPtr) {
+ QT3DSU8 *dataPtr = inEffect.GetDataSectionBegin() + theDefinition.m_Offset;
+ StaticAssert<sizeof(CRegisteredString)
+ == sizeof(NVRenderTexture2DPtr)>::valid_expression();
+ CRegisteredString *theStrPtr = reinterpret_cast<CRegisteredString *>(dataPtr);
+ IOffscreenRenderManager &theOffscreenRenderer(
+ m_Context->GetOffscreenRenderManager());
+
+ if (theStrPtr->IsValid()) {
+ if (theOffscreenRenderer.HasOffscreenRenderer(*theStrPtr))
+ theOffscreenRenderer.GetRenderedItem(*theStrPtr);
+ }
+ }
+ }
+ }
+};
+}
+
+IEffectSystemCore &IEffectSystemCore::CreateEffectSystemCore(IQt3DSRenderContextCore &inContext)
+{
+ return *QT3DS_NEW(inContext.GetAllocator(), SEffectSystem)(inContext);
+}