diff --git a/WickedEngine/WickedEngine_SHARED.vcxitems b/WickedEngine/WickedEngine_SHARED.vcxitems
index 3a7e4c433..6dc2bad60 100644
--- a/WickedEngine/WickedEngine_SHARED.vcxitems
+++ b/WickedEngine/WickedEngine_SHARED.vcxitems
@@ -260,6 +260,7 @@
+
@@ -528,6 +529,7 @@
+
diff --git a/WickedEngine/WickedEngine_SHARED.vcxitems.filters b/WickedEngine/WickedEngine_SHARED.vcxitems.filters
index fade1aa9f..5595b500f 100644
--- a/WickedEngine/WickedEngine_SHARED.vcxitems.filters
+++ b/WickedEngine/WickedEngine_SHARED.vcxitems.filters
@@ -1143,6 +1143,9 @@
ENGINE\Scripting\LuaBindings
+
+ ENGINE\Graphics
+
@@ -1934,6 +1937,9 @@
ENGINE\Scripting\LuaBindings
+
+ ENGINE\Graphics
+
diff --git a/WickedEngine/wiEnums.h b/WickedEngine/wiEnums.h
index e44f4027b..ba0008db0 100644
--- a/WickedEngine/wiEnums.h
+++ b/WickedEngine/wiEnums.h
@@ -61,7 +61,6 @@ enum CBTYPES
CBTYPE_TESSELLATION,
CBTYPE_DISPATCHPARAMS,
CBTYPE_CLOUDGENERATOR,
- CBTYPE_BVH,
CBTYPE_RAYTRACE,
CBTYPE_MIPGEN,
CBTYPE_FILTERENVMAP,
@@ -275,12 +274,6 @@ enum CSTYPES
CSTYPE_SKINNING,
CSTYPE_SKINNING_LDS,
CSTYPE_CLOUDGENERATOR,
- CSTYPE_BVH_RESET,
- CSTYPE_BVH_CLASSIFICATION,
- CSTYPE_BVH_KICKJOBS,
- CSTYPE_BVH_CLUSTERPROCESSOR,
- CSTYPE_BVH_HIERARCHY,
- CSTYPE_BVH_PROPAGATEAABB,
CSTYPE_RAYTRACE_CLEAR,
CSTYPE_RAYTRACE_LAUNCH,
CSTYPE_RAYTRACE_KICKJOBS,
diff --git a/WickedEngine/wiGPUBVH.cpp b/WickedEngine/wiGPUBVH.cpp
new file mode 100644
index 000000000..73fa93475
--- /dev/null
+++ b/WickedEngine/wiGPUBVH.cpp
@@ -0,0 +1,440 @@
+#include "wiGPUBVH.h"
+#include "wiSceneSystem.h"
+#include "wiRenderer.h"
+#include "ShaderInterop_BVH.h"
+#include "wiProfiler.h"
+#include "wiResourceManager.h"
+#include "wiGPUSortLib.h"
+
+#include
+
+using namespace std;
+using namespace wiGraphicsTypes;
+using namespace wiSceneSystem;
+using namespace wiECS;
+
+enum CSTYPES_BVH
+{
+ CSTYPE_BVH_RESET,
+ CSTYPE_BVH_CLASSIFICATION,
+ CSTYPE_BVH_KICKJOBS,
+ CSTYPE_BVH_CLUSTERPROCESSOR,
+ CSTYPE_BVH_HIERARCHY,
+ CSTYPE_BVH_PROPAGATEAABB,
+ CSTYPE_BVH_COUNT
+};
+ComputeShader* computeShaders[CSTYPE_BVH_COUNT] = {};
+ComputePSO* CPSO[CSTYPE_BVH_COUNT] = {};
+
+GPUBuffer* constantBuffer = nullptr;
+
+wiGPUBVH::wiGPUBVH()
+{
+
+}
+wiGPUBVH::~wiGPUBVH()
+{
+}
+
+
+void wiGPUBVH::Build(const Scene& scene, GRAPHICSTHREAD threadID)
+{
+ GraphicsDevice* device = wiRenderer::GetDevice();
+
+ if (constantBuffer == nullptr)
+ {
+ GPUBufferDesc bd;
+ bd.Usage = USAGE_DYNAMIC;
+ bd.CPUAccessFlags = CPU_ACCESS_WRITE;
+ bd.BindFlags = BIND_CONSTANT_BUFFER;
+ bd.ByteWidth = sizeof(BVHCB);
+
+ constantBuffer = new GPUBuffer;
+ device->CreateBuffer(&bd, nullptr, constantBuffer);
+ device->SetName(constantBuffer, "BVHGeneratorCB");
+ }
+
+ // Pre-gather scene properties:
+ uint totalTriangles = 0;
+ for (size_t i = 0; i < scene.meshes.GetCount(); ++i)
+ {
+ const MeshComponent& mesh = scene.meshes[i];
+
+ totalTriangles += (uint)mesh.indices.size() / 3;
+ }
+
+ static uint maxTriangleCount = 0;
+ static uint maxClusterCount = 0;
+
+ if (totalTriangles > maxTriangleCount)
+ {
+ maxTriangleCount = totalTriangles;
+ maxClusterCount = maxTriangleCount; // todo: cluster / triangle capacity
+
+ GPUBufferDesc desc;
+ HRESULT hr;
+
+ bvhNodeBuffer.reset(new GPUBuffer);
+ bvhAABBBuffer.reset(new GPUBuffer);
+ bvhFlagBuffer.reset(new GPUBuffer);
+ triangleBuffer.reset(new GPUBuffer);
+ clusterCounterBuffer.reset(new GPUBuffer);
+ clusterIndexBuffer.reset(new GPUBuffer);
+ clusterMortonBuffer.reset(new GPUBuffer);
+ clusterSortedMortonBuffer.reset(new GPUBuffer);
+ clusterOffsetBuffer.reset(new GPUBuffer);
+ clusterAABBBuffer.reset(new GPUBuffer);
+ clusterConeBuffer.reset(new GPUBuffer);
+
+ desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
+ desc.StructureByteStride = sizeof(BVHNode);
+ desc.ByteWidth = desc.StructureByteStride * maxClusterCount * 2;
+ desc.CPUAccessFlags = 0;
+ desc.Format = FORMAT_UNKNOWN;
+ desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
+ desc.Usage = USAGE_DEFAULT;
+ hr = device->CreateBuffer(&desc, nullptr, bvhNodeBuffer.get());
+ assert(SUCCEEDED(hr));
+ device->SetName(bvhNodeBuffer.get(), "BVHNodeBuffer");
+
+ desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
+ desc.StructureByteStride = sizeof(BVHAABB);
+ desc.ByteWidth = desc.StructureByteStride * maxClusterCount * 2;
+ desc.CPUAccessFlags = 0;
+ desc.Format = FORMAT_UNKNOWN;
+ desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
+ desc.Usage = USAGE_DEFAULT;
+ hr = device->CreateBuffer(&desc, nullptr, bvhAABBBuffer.get());
+ assert(SUCCEEDED(hr));
+ device->SetName(bvhAABBBuffer.get(), "BVHAABBBuffer");
+
+ desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
+ desc.StructureByteStride = sizeof(uint);
+ desc.ByteWidth = desc.StructureByteStride * (maxClusterCount - 1); // only for internal nodes
+ desc.CPUAccessFlags = 0;
+ desc.Format = FORMAT_UNKNOWN;
+ desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
+ desc.Usage = USAGE_DEFAULT;
+ hr = device->CreateBuffer(&desc, nullptr, bvhFlagBuffer.get());
+ assert(SUCCEEDED(hr));
+ device->SetName(bvhFlagBuffer.get(), "BVHFlagBuffer");
+
+ desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
+ desc.StructureByteStride = sizeof(BVHMeshTriangle);
+ desc.ByteWidth = desc.StructureByteStride * maxTriangleCount;
+ desc.CPUAccessFlags = 0;
+ desc.Format = FORMAT_UNKNOWN;
+ desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
+ desc.Usage = USAGE_DEFAULT;
+ hr = device->CreateBuffer(&desc, nullptr, triangleBuffer.get());
+ assert(SUCCEEDED(hr));
+ device->SetName(triangleBuffer.get(), "BVHTriangleBuffer");
+
+ desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
+ desc.StructureByteStride = sizeof(uint);
+ desc.ByteWidth = desc.StructureByteStride;
+ desc.CPUAccessFlags = 0;
+ desc.Format = FORMAT_UNKNOWN;
+ desc.MiscFlags = RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
+ desc.Usage = USAGE_DEFAULT;
+ hr = device->CreateBuffer(&desc, nullptr, clusterCounterBuffer.get());
+ assert(SUCCEEDED(hr));
+ device->SetName(clusterCounterBuffer.get(), "BVHClusterCounterBuffer");
+
+ desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
+ desc.StructureByteStride = sizeof(uint);
+ desc.ByteWidth = desc.StructureByteStride * maxClusterCount;
+ desc.CPUAccessFlags = 0;
+ desc.Format = FORMAT_UNKNOWN;
+ desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
+ desc.Usage = USAGE_DEFAULT;
+ hr = device->CreateBuffer(&desc, nullptr, clusterIndexBuffer.get());
+ assert(SUCCEEDED(hr));
+ device->SetName(clusterIndexBuffer.get(), "BVHClusterIndexBuffer");
+
+ desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
+ desc.StructureByteStride = sizeof(uint);
+ desc.ByteWidth = desc.StructureByteStride * maxClusterCount;
+ desc.CPUAccessFlags = 0;
+ desc.Format = FORMAT_UNKNOWN;
+ desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
+ desc.Usage = USAGE_DEFAULT;
+ hr = device->CreateBuffer(&desc, nullptr, clusterMortonBuffer.get());
+ hr = device->CreateBuffer(&desc, nullptr, clusterSortedMortonBuffer.get());
+ assert(SUCCEEDED(hr));
+ device->SetName(clusterMortonBuffer.get(), "BVHClusterMortonBuffer");
+ device->SetName(clusterSortedMortonBuffer.get(), "BVHSortedClusterMortonBuffer");
+
+ desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
+ desc.StructureByteStride = sizeof(uint2);
+ desc.ByteWidth = desc.StructureByteStride * maxClusterCount;
+ desc.CPUAccessFlags = 0;
+ desc.Format = FORMAT_UNKNOWN;
+ desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
+ desc.Usage = USAGE_DEFAULT;
+ hr = device->CreateBuffer(&desc, nullptr, clusterOffsetBuffer.get());
+ assert(SUCCEEDED(hr));
+ device->SetName(clusterOffsetBuffer.get(), "BVHClusterOffsetBuffer");
+
+ desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
+ desc.StructureByteStride = sizeof(BVHAABB);
+ desc.ByteWidth = desc.StructureByteStride * maxClusterCount;
+ desc.CPUAccessFlags = 0;
+ desc.Format = FORMAT_UNKNOWN;
+ desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
+ desc.Usage = USAGE_DEFAULT;
+ hr = device->CreateBuffer(&desc, nullptr, clusterAABBBuffer.get());
+ assert(SUCCEEDED(hr));
+ device->SetName(clusterAABBBuffer.get(), "BVHClusterAABBBuffer");
+
+ desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
+ desc.StructureByteStride = sizeof(ClusterCone);
+ desc.ByteWidth = desc.StructureByteStride * maxClusterCount;
+ desc.CPUAccessFlags = 0;
+ desc.Format = FORMAT_UNKNOWN;
+ desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
+ desc.Usage = USAGE_DEFAULT;
+ hr = device->CreateBuffer(&desc, nullptr, clusterConeBuffer.get());
+ assert(SUCCEEDED(hr));
+ device->SetName(clusterConeBuffer.get(), "BVHClusterConeBuffer");
+ }
+
+ static GPUBuffer* indirectBuffer = nullptr; // GPU job kicks
+ if (indirectBuffer == nullptr)
+ {
+ GPUBufferDesc desc;
+ HRESULT hr;
+
+ SAFE_DELETE(indirectBuffer);
+ indirectBuffer = new GPUBuffer;
+
+ desc.BindFlags = BIND_UNORDERED_ACCESS;
+ desc.StructureByteStride = sizeof(IndirectDispatchArgs) * 2;
+ desc.ByteWidth = desc.StructureByteStride;
+ desc.CPUAccessFlags = 0;
+ desc.Format = FORMAT_UNKNOWN;
+ desc.MiscFlags = RESOURCE_MISC_DRAWINDIRECT_ARGS | RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
+ desc.Usage = USAGE_DEFAULT;
+ hr = device->CreateBuffer(&desc, nullptr, indirectBuffer);
+ assert(SUCCEEDED(hr));
+ }
+
+
+ wiProfiler::GetInstance().BeginRange("BVH Rebuild", wiProfiler::DOMAIN_GPU, threadID);
+
+ device->EventBegin("BVH - Reset", threadID);
+ {
+ device->BindComputePSO(CPSO[CSTYPE_BVH_RESET], threadID);
+
+ GPUResource* uavs[] = {
+ clusterCounterBuffer.get(),
+ bvhNodeBuffer.get(),
+ bvhAABBBuffer.get(),
+ };
+ device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
+
+ device->Dispatch(1, 1, 1, threadID);
+ }
+ device->EventEnd(threadID);
+
+
+ uint32_t triangleCount = 0;
+ uint32_t materialCount = 0;
+
+ device->EventBegin("BVH - Classification", threadID);
+ {
+ device->BindComputePSO(CPSO[CSTYPE_BVH_CLASSIFICATION], threadID);
+ GPUResource* uavs[] = {
+ triangleBuffer.get(),
+ clusterCounterBuffer.get(),
+ clusterIndexBuffer.get(),
+ clusterMortonBuffer.get(),
+ clusterOffsetBuffer.get(),
+ clusterAABBBuffer.get(),
+ };
+ device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
+
+ for (size_t i = 0; i < scene.objects.GetCount(); ++i)
+ {
+ const ObjectComponent& object = scene.objects[i];
+
+ if (object.meshID != INVALID_ENTITY)
+ {
+ const MeshComponent& mesh = *scene.meshes.GetComponent(object.meshID);
+ Entity entity = scene.objects.GetEntity(i);
+ const TransformComponent& transform = scene.transforms[object.transformComponentIndex];
+
+ BVHCB cb;
+ cb.xTraceBVHWorld = transform.world;
+ cb.xTraceBVHMaterialOffset = materialCount;
+ cb.xTraceBVHMeshTriangleOffset = triangleCount;
+ cb.xTraceBVHMeshTriangleCount = (uint)mesh.indices.size() / 3;
+ cb.xTraceBVHMeshVertexPOSStride = sizeof(MeshComponent::Vertex_POS);
+
+ device->UpdateBuffer(constantBuffer, &cb, threadID);
+
+ triangleCount += cb.xTraceBVHMeshTriangleCount;
+
+ device->BindConstantBuffer(CS, constantBuffer, CB_GETBINDSLOT(BVHCB), threadID);
+
+ GPUResource* res[] = {
+ mesh.indexBuffer.get(),
+ mesh.vertexBuffer_POS.get(),
+ mesh.vertexBuffer_TEX.get(),
+ };
+ device->BindResources(CS, res, TEXSLOT_ONDEMAND0, ARRAYSIZE(res), threadID);
+
+ device->Dispatch((UINT)ceilf((float)cb.xTraceBVHMeshTriangleCount / (float)BVH_CLASSIFICATION_GROUPSIZE), 1, 1, threadID);
+
+ for (auto& subset : mesh.subsets)
+ {
+ materialCount++;
+ }
+ }
+ }
+
+ device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
+ device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
+ }
+ device->EventEnd(threadID);
+
+
+ device->EventBegin("BVH - Sort Cluster Mortons", threadID);
+ wiGPUSortLib::Sort(maxClusterCount, clusterMortonBuffer.get(), clusterCounterBuffer.get(), 0, clusterIndexBuffer.get(), threadID);
+ device->EventEnd(threadID);
+
+ device->EventBegin("BVH - Kick Jobs", threadID);
+ {
+ device->BindComputePSO(CPSO[CSTYPE_BVH_KICKJOBS], threadID);
+ GPUResource* uavs[] = {
+ indirectBuffer,
+ };
+ device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
+
+ GPUResource* res[] = {
+ clusterCounterBuffer.get(),
+ };
+ device->BindResources(CS, res, TEXSLOT_ONDEMAND0, ARRAYSIZE(res), threadID);
+
+ device->Dispatch(1, 1, 1, threadID);
+
+ device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
+ device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
+ }
+ device->EventEnd(threadID);
+
+ device->EventBegin("BVH - Cluster Processor", threadID);
+ {
+ device->BindComputePSO(CPSO[CSTYPE_BVH_CLUSTERPROCESSOR], threadID);
+ GPUResource* uavs[] = {
+ clusterSortedMortonBuffer.get(),
+ clusterConeBuffer.get(),
+ };
+ device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
+
+ GPUResource* res[] = {
+ clusterCounterBuffer.get(),
+ clusterIndexBuffer.get(),
+ clusterMortonBuffer.get(),
+ clusterOffsetBuffer.get(),
+ clusterAABBBuffer.get(),
+ triangleBuffer.get(),
+ };
+ device->BindResources(CS, res, TEXSLOT_ONDEMAND0, ARRAYSIZE(res), threadID);
+
+ device->DispatchIndirect(indirectBuffer, ARGUMENTBUFFER_OFFSET_CLUSTERPROCESSOR, threadID);
+
+
+ device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
+ device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
+ }
+ device->EventEnd(threadID);
+
+ device->EventBegin("BVH - Build Hierarchy", threadID);
+ {
+ device->BindComputePSO(CPSO[CSTYPE_BVH_HIERARCHY], threadID);
+ GPUResource* uavs[] = {
+ bvhNodeBuffer.get(),
+ bvhFlagBuffer.get(),
+ };
+ device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
+
+ GPUResource* res[] = {
+ clusterCounterBuffer.get(),
+ clusterSortedMortonBuffer.get(),
+ };
+ device->BindResources(CS, res, TEXSLOT_ONDEMAND0, ARRAYSIZE(res), threadID);
+
+ device->DispatchIndirect(indirectBuffer, ARGUMENTBUFFER_OFFSET_HIERARCHY, threadID);
+
+
+ device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
+ device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
+ }
+ device->EventEnd(threadID);
+
+ device->EventBegin("BVH - Propagate AABB", threadID);
+ {
+ device->BindComputePSO(CPSO[CSTYPE_BVH_PROPAGATEAABB], threadID);
+ GPUResource* uavs[] = {
+ bvhAABBBuffer.get(),
+ bvhFlagBuffer.get(),
+ };
+ device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
+
+ GPUResource* res[] = {
+ clusterCounterBuffer.get(),
+ clusterIndexBuffer.get(),
+ clusterAABBBuffer.get(),
+ bvhNodeBuffer.get(),
+ };
+ device->BindResources(CS, res, TEXSLOT_ONDEMAND0, ARRAYSIZE(res), threadID);
+
+ device->DispatchIndirect(indirectBuffer, ARGUMENTBUFFER_OFFSET_CLUSTERPROCESSOR, threadID);
+
+
+ device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
+ device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
+ }
+ device->EventEnd(threadID);
+
+ wiProfiler::GetInstance().EndRange(threadID); // BVH rebuild
+}
+void wiGPUBVH::Bind(GRAPHICSTHREAD threadID)
+{
+ GraphicsDevice* device = wiRenderer::GetDevice();
+
+ GPUResource* res[] = {
+ triangleBuffer.get(),
+ clusterCounterBuffer.get(),
+ clusterIndexBuffer.get(),
+ clusterOffsetBuffer.get(),
+ clusterConeBuffer.get(),
+ bvhNodeBuffer.get(),
+ bvhAABBBuffer.get(),
+ };
+ device->BindResources(CS, res, TEXSLOT_ONDEMAND1, ARRAYSIZE(res), threadID);
+}
+
+
+void wiGPUBVH::LoadShaders()
+{
+ GraphicsDevice* device = wiRenderer::GetDevice();
+ string SHADERPATH = wiRenderer::GetShaderPath();
+
+ computeShaders[CSTYPE_BVH_RESET] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_resetCS.cso", wiResourceManager::COMPUTESHADER));
+ computeShaders[CSTYPE_BVH_CLASSIFICATION] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_classificationCS.cso", wiResourceManager::COMPUTESHADER));
+ computeShaders[CSTYPE_BVH_KICKJOBS] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_kickjobsCS.cso", wiResourceManager::COMPUTESHADER));
+ computeShaders[CSTYPE_BVH_CLUSTERPROCESSOR] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_clusterprocessorCS.cso", wiResourceManager::COMPUTESHADER));
+ computeShaders[CSTYPE_BVH_HIERARCHY] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_hierarchyCS.cso", wiResourceManager::COMPUTESHADER));
+ computeShaders[CSTYPE_BVH_PROPAGATEAABB] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_propagateaabbCS.cso", wiResourceManager::COMPUTESHADER));
+
+
+ for (int i = 0; i < CSTYPE_BVH_COUNT; ++i)
+ {
+ ComputePSODesc desc;
+ desc.cs = computeShaders[i];
+ RECREATE(CPSO[i]);
+ device->CreateComputePSO(&desc, CPSO[i]);
+ }
+}
diff --git a/WickedEngine/wiGPUBVH.h b/WickedEngine/wiGPUBVH.h
new file mode 100644
index 000000000..9e594a0c1
--- /dev/null
+++ b/WickedEngine/wiGPUBVH.h
@@ -0,0 +1,34 @@
+#ifndef _WI_GPU_BVH_H_
+#define _WI_GPU_BVH_H_
+
+#include "CommonInclude.h"
+#include "wiGraphicsAPI.h"
+#include "wiSceneSystem_Decl.h"
+
+class wiGPUBVH
+{
+private:
+ std::unique_ptr bvhNodeBuffer;
+ std::unique_ptr bvhAABBBuffer;
+ std::unique_ptr bvhFlagBuffer;
+ std::unique_ptr triangleBuffer;
+ std::unique_ptr clusterCounterBuffer;
+ std::unique_ptr clusterIndexBuffer;
+ std::unique_ptr clusterMortonBuffer;
+ std::unique_ptr clusterSortedMortonBuffer;
+ std::unique_ptr clusterOffsetBuffer;
+ std::unique_ptr clusterAABBBuffer;
+ std::unique_ptr clusterConeBuffer;
+
+public:
+ wiGPUBVH();
+ ~wiGPUBVH();
+
+ void Build(const wiSceneSystem::Scene& scene, GRAPHICSTHREAD threadID);
+ void Bind(GRAPHICSTHREAD threadID);
+
+ static void LoadShaders();
+
+};
+
+#endif // _WI_GPU_BVH_H_
diff --git a/WickedEngine/wiGPUSortLib.cpp b/WickedEngine/wiGPUSortLib.cpp
index da86f8465..33d4b15fb 100644
--- a/WickedEngine/wiGPUSortLib.cpp
+++ b/WickedEngine/wiGPUSortLib.cpp
@@ -5,205 +5,211 @@
using namespace wiGraphicsTypes;
-GPUBuffer* wiGPUSortLib::indirectBuffer = nullptr;
-GPUBuffer* wiGPUSortLib::sortCB = nullptr;
-ComputeShader* wiGPUSortLib::kickoffSortCS = nullptr;
-ComputeShader* wiGPUSortLib::sortCS = nullptr;
-ComputeShader* wiGPUSortLib::sortInnerCS = nullptr;
-ComputeShader* wiGPUSortLib::sortStepCS = nullptr;
-ComputePSO wiGPUSortLib::CPSO_kickoffSort;
-ComputePSO wiGPUSortLib::CPSO_sort;
-ComputePSO wiGPUSortLib::CPSO_sortInner;
-ComputePSO wiGPUSortLib::CPSO_sortStep;
-
-void wiGPUSortLib::Initialize()
+namespace wiGPUSortLib
{
- GPUBufferDesc bd;
+ GPUBuffer* indirectBuffer = nullptr;
+ GPUBuffer* sortCB = nullptr;
+ ComputeShader* kickoffSortCS = nullptr;
+ ComputeShader* sortCS = nullptr;
+ ComputeShader* sortInnerCS = nullptr;
+ ComputeShader* sortStepCS = nullptr;
+ ComputePSO CPSO_kickoffSort;
+ ComputePSO CPSO_sort;
+ ComputePSO CPSO_sortInner;
+ ComputePSO CPSO_sortStep;
- bd.Usage = USAGE_DYNAMIC;
- bd.CPUAccessFlags = CPU_ACCESS_WRITE;
- bd.BindFlags = BIND_CONSTANT_BUFFER;
- bd.MiscFlags = 0;
- bd.ByteWidth = sizeof(SortConstants);
- sortCB = new GPUBuffer;
- wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, sortCB);
-
-
- bd.Usage = USAGE_DEFAULT;
- bd.CPUAccessFlags = 0;
- bd.BindFlags = BIND_UNORDERED_ACCESS;
- bd.MiscFlags = RESOURCE_MISC_DRAWINDIRECT_ARGS | RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
- bd.ByteWidth = sizeof(IndirectDispatchArgs);
- indirectBuffer = new GPUBuffer;
- wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, indirectBuffer);
-
-}
-
-void wiGPUSortLib::LoadShaders()
-{
- std::string path = wiRenderer::GetShaderPath();
-
- kickoffSortCS = static_cast(wiResourceManager::GetShaderManager()->add(path + "gpusortlib_kickoffSortCS.cso", wiResourceManager::COMPUTESHADER));
- sortCS = static_cast(wiResourceManager::GetShaderManager()->add(path + "gpusortlib_sortCS.cso", wiResourceManager::COMPUTESHADER));
- sortInnerCS = static_cast(wiResourceManager::GetShaderManager()->add(path + "gpusortlib_sortInnerCS.cso", wiResourceManager::COMPUTESHADER));
- sortStepCS = static_cast(wiResourceManager::GetShaderManager()->add(path + "gpusortlib_sortStepCS.cso", wiResourceManager::COMPUTESHADER));
-
-
- GraphicsDevice* device = wiRenderer::GetDevice();
-
- ComputePSODesc desc;
-
- desc.cs = kickoffSortCS;
- device->CreateComputePSO(&desc, &CPSO_kickoffSort);
-
- desc.cs = sortCS;
- device->CreateComputePSO(&desc, &CPSO_sort);
-
- desc.cs = sortInnerCS;
- device->CreateComputePSO(&desc, &CPSO_sortInner);
-
- desc.cs = sortStepCS;
- device->CreateComputePSO(&desc, &CPSO_sortStep);
-}
-
-void wiGPUSortLib::CleanUpStatic()
-{
-}
-
-
-void wiGPUSortLib::Sort(UINT maxCount, GPUBuffer* comparisonBuffer_read, GPUBuffer* counterBuffer_read, UINT counterReadOffset, GPUBuffer* indexBuffer_write, GRAPHICSTHREAD threadID)
-{
- static bool init = false;
- if (!init)
+ void Initialize()
{
- Initialize();
- init = true;
+ GPUBufferDesc bd;
+
+ bd.Usage = USAGE_DYNAMIC;
+ bd.CPUAccessFlags = CPU_ACCESS_WRITE;
+ bd.BindFlags = BIND_CONSTANT_BUFFER;
+ bd.MiscFlags = 0;
+ bd.ByteWidth = sizeof(SortConstants);
+ sortCB = new GPUBuffer;
+ wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, sortCB);
+
+
+ bd.Usage = USAGE_DEFAULT;
+ bd.CPUAccessFlags = 0;
+ bd.BindFlags = BIND_UNORDERED_ACCESS;
+ bd.MiscFlags = RESOURCE_MISC_DRAWINDIRECT_ARGS | RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
+ bd.ByteWidth = sizeof(IndirectDispatchArgs);
+ indirectBuffer = new GPUBuffer;
+ wiRenderer::GetDevice()->CreateBuffer(&bd, nullptr, indirectBuffer);
+
+ }
+
+ void LoadShaders()
+ {
+ std::string path = wiRenderer::GetShaderPath();
+
+ kickoffSortCS = static_cast(wiResourceManager::GetShaderManager()->add(path + "gpusortlib_kickoffSortCS.cso", wiResourceManager::COMPUTESHADER));
+ sortCS = static_cast(wiResourceManager::GetShaderManager()->add(path + "gpusortlib_sortCS.cso", wiResourceManager::COMPUTESHADER));
+ sortInnerCS = static_cast(wiResourceManager::GetShaderManager()->add(path + "gpusortlib_sortInnerCS.cso", wiResourceManager::COMPUTESHADER));
+ sortStepCS = static_cast(wiResourceManager::GetShaderManager()->add(path + "gpusortlib_sortStepCS.cso", wiResourceManager::COMPUTESHADER));
+
+
+ GraphicsDevice* device = wiRenderer::GetDevice();
+
+ ComputePSODesc desc;
+
+ desc.cs = kickoffSortCS;
+ device->CreateComputePSO(&desc, &CPSO_kickoffSort);
+
+ desc.cs = sortCS;
+ device->CreateComputePSO(&desc, &CPSO_sort);
+
+ desc.cs = sortInnerCS;
+ device->CreateComputePSO(&desc, &CPSO_sortInner);
+
+ desc.cs = sortStepCS;
+ device->CreateComputePSO(&desc, &CPSO_sortStep);
+ }
+
+ void CleanUp()
+ {
+ SAFE_DELETE(indirectBuffer);
+ SAFE_DELETE(sortCB);
}
- GraphicsDevice* device = wiRenderer::GetDevice();
-
- device->EventBegin("GPUSortLib", threadID);
-
-
- SortConstants sc;
- sc.counterReadOffset = counterReadOffset;
- device->UpdateBuffer(sortCB, &sc, threadID);
- device->BindConstantBuffer(CS, sortCB, CB_GETBINDSLOT(SortConstants), threadID);
-
- device->UnbindUAVs(0, 8, threadID);
-
- // initialize sorting arguments:
+ void Sort(UINT maxCount, GPUBuffer* comparisonBuffer_read, GPUBuffer* counterBuffer_read, UINT counterReadOffset, GPUBuffer* indexBuffer_write, GRAPHICSTHREAD threadID)
{
- device->BindComputePSO(&CPSO_kickoffSort, threadID);
+ static bool init = false;
+ if (!init)
+ {
+ Initialize();
+ init = true;
+ }
+
+
+ GraphicsDevice* device = wiRenderer::GetDevice();
+
+ device->EventBegin("GPUSortLib", threadID);
+
+
+ SortConstants sc;
+ sc.counterReadOffset = counterReadOffset;
+ device->UpdateBuffer(sortCB, &sc, threadID);
+ device->BindConstantBuffer(CS, sortCB, CB_GETBINDSLOT(SortConstants), threadID);
+
+ device->UnbindUAVs(0, 8, threadID);
+
+ // initialize sorting arguments:
+ {
+ device->BindComputePSO(&CPSO_kickoffSort, threadID);
+
+ GPUResource* res[] = {
+ counterBuffer_read,
+ };
+ device->BindResources(CS, res, 0, ARRAYSIZE(res), threadID);
+
+ GPUResource* uavs[] = {
+ indirectBuffer,
+ };
+ device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
+
+ device->Dispatch(1, 1, 1, threadID);
+ device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
+
+ device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
+ }
- GPUResource* res[] = {
- counterBuffer_read,
- };
- device->BindResources(CS, res, 0, ARRAYSIZE(res), threadID);
GPUResource* uavs[] = {
- indirectBuffer,
+ indexBuffer_write,
};
device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
- device->Dispatch(1, 1, 1, threadID);
- device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
+ GPUResource* resources[] = {
+ counterBuffer_read,
+ comparisonBuffer_read,
+ };
+ device->BindResources(CS, resources, 0, ARRAYSIZE(resources), threadID);
- device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
- }
-
-
- GPUResource* uavs[] = {
- indexBuffer_write,
- };
- device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
-
- GPUResource* resources[] = {
- counterBuffer_read,
- comparisonBuffer_read,
- };
- device->BindResources(CS, resources, 0, ARRAYSIZE(resources), threadID);
-
- // initial sorting:
- bool bDone = true;
- {
- // calculate how many threads we'll require:
- // we'll sort 512 elements per CU (threadgroupsize 256)
- // maybe need to optimize this or make it changeable during init
- // TGS=256 is a good intermediate value
-
- unsigned int numThreadGroups = ((maxCount - 1) >> 9) + 1;
-
- //assert(numThreadGroups <= 1024);
-
- if (numThreadGroups > 1)
+ // initial sorting:
+ bool bDone = true;
{
- bDone = false;
- }
+ // calculate how many threads we'll require:
+ // we'll sort 512 elements per CU (threadgroupsize 256)
+ // maybe need to optimize this or make it changeable during init
+ // TGS=256 is a good intermediate value
- // sort all buffers of size 512 (and presort bigger ones)
- device->BindComputePSO(&CPSO_sort, threadID);
- device->DispatchIndirect(indirectBuffer, 0, threadID);
- device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
- }
+ unsigned int numThreadGroups = ((maxCount - 1) >> 9) + 1;
- int presorted = 512;
- while (!bDone)
- {
- // Incremental sorting:
+ //assert(numThreadGroups <= 1024);
- bDone = true;
- device->BindComputePSO(&CPSO_sortStep, threadID);
-
- // prepare thread group description data
- uint32_t numThreadGroups = 0;
-
- if (maxCount > (uint32_t)presorted)
- {
- if (maxCount > (uint32_t)presorted * 2)
+ if (numThreadGroups > 1)
+ {
bDone = false;
-
- uint32_t pow2 = presorted;
- while (pow2 < maxCount)
- pow2 *= 2;
- numThreadGroups = pow2 >> 9;
- }
-
- uint32_t nMergeSize = presorted * 2;
- for (uint32_t nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 256; nMergeSubSize = nMergeSubSize >> 1)
- {
- SortConstants sc;
- sc.job_params.x = nMergeSubSize;
- if (nMergeSubSize == nMergeSize >> 1)
- {
- sc.job_params.y = (2 * nMergeSubSize - 1);
- sc.job_params.z = -1;
}
- else
- {
- sc.job_params.y = nMergeSubSize;
- sc.job_params.z = 1;
- }
- sc.counterReadOffset = counterReadOffset;
- device->UpdateBuffer(sortCB, &sc, threadID);
- device->BindConstantBuffer(CS, sortCB, CB_GETBINDSLOT(SortConstants), threadID);
-
- device->Dispatch(numThreadGroups, 1, 1, threadID);
+ // sort all buffers of size 512 (and presort bigger ones)
+ device->BindComputePSO(&CPSO_sort, threadID);
+ device->DispatchIndirect(indirectBuffer, 0, threadID);
device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
}
- device->BindComputePSO(&CPSO_sortInner, threadID);
- device->Dispatch(numThreadGroups, 1, 1, threadID);
- device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
+ int presorted = 512;
+ while (!bDone)
+ {
+ // Incremental sorting:
- presorted *= 2;
+ bDone = true;
+ device->BindComputePSO(&CPSO_sortStep, threadID);
+
+ // prepare thread group description data
+ uint32_t numThreadGroups = 0;
+
+ if (maxCount > (uint32_t)presorted)
+ {
+ if (maxCount > (uint32_t)presorted * 2)
+ bDone = false;
+
+ uint32_t pow2 = presorted;
+ while (pow2 < maxCount)
+ pow2 *= 2;
+ numThreadGroups = pow2 >> 9;
+ }
+
+ uint32_t nMergeSize = presorted * 2;
+ for (uint32_t nMergeSubSize = nMergeSize >> 1; nMergeSubSize > 256; nMergeSubSize = nMergeSubSize >> 1)
+ {
+ SortConstants sc;
+ sc.job_params.x = nMergeSubSize;
+ if (nMergeSubSize == nMergeSize >> 1)
+ {
+ sc.job_params.y = (2 * nMergeSubSize - 1);
+ sc.job_params.z = -1;
+ }
+ else
+ {
+ sc.job_params.y = nMergeSubSize;
+ sc.job_params.z = 1;
+ }
+ sc.counterReadOffset = counterReadOffset;
+
+ device->UpdateBuffer(sortCB, &sc, threadID);
+ device->BindConstantBuffer(CS, sortCB, CB_GETBINDSLOT(SortConstants), threadID);
+
+ device->Dispatch(numThreadGroups, 1, 1, threadID);
+ device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
+ }
+
+ device->BindComputePSO(&CPSO_sortInner, threadID);
+ device->Dispatch(numThreadGroups, 1, 1, threadID);
+ device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
+
+ presorted *= 2;
+ }
+
+ device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
+ device->UnbindResources(0, ARRAYSIZE(resources), threadID);
+
+
+ device->EventEnd(threadID);
}
- device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
- device->UnbindResources(0, ARRAYSIZE(resources), threadID);
-
-
- device->EventEnd(threadID);
}
diff --git a/WickedEngine/wiGPUSortLib.h b/WickedEngine/wiGPUSortLib.h
index bb9471e78..84351df27 100644
--- a/WickedEngine/wiGPUSortLib.h
+++ b/WickedEngine/wiGPUSortLib.h
@@ -4,33 +4,19 @@
#include "CommonInclude.h"
#include "wiGraphicsAPI.h"
-class wiGPUSortLib
+namespace wiGPUSortLib
{
-private:
- static wiGraphicsTypes::GPUBuffer* indirectBuffer;
- static wiGraphicsTypes::GPUBuffer* sortCB;
- static wiGraphicsTypes::ComputeShader* kickoffSortCS;
- static wiGraphicsTypes::ComputeShader* sortCS;
- static wiGraphicsTypes::ComputeShader* sortInnerCS;
- static wiGraphicsTypes::ComputeShader* sortStepCS;
- static wiGraphicsTypes::ComputePSO CPSO_kickoffSort;
- static wiGraphicsTypes::ComputePSO CPSO_sort;
- static wiGraphicsTypes::ComputePSO CPSO_sortInner;
- static wiGraphicsTypes::ComputePSO CPSO_sortStep;
-
-public:
-
// Perform bitonic sort on a GPU dataset
// maxCount - Maximum size of the dataset. GPU count can be smaller (see: counterBuffer_read param)
// comparisonBuffer_read - Buffer containing values to compare by (Read Only)
// counterBuffer_read - Buffer containing count of values to sort (Read Only)
// counterReadOffset - Byte offset into the counter buffer to read the count value (Read Only)
// indexBuffer_write - The index list which to sort. Contains index values which can index the sortBase_read buffer. This will be modified (Read + Write)
- static void Sort(UINT maxCount, wiGraphicsTypes::GPUBuffer* comparisonBuffer_read, wiGraphicsTypes::GPUBuffer* counterBuffer_read, UINT counterReadOffset, wiGraphicsTypes::GPUBuffer* indexBuffer_write, GRAPHICSTHREAD threadID);
+ void Sort(UINT maxCount, wiGraphicsTypes::GPUBuffer* comparisonBuffer_read, wiGraphicsTypes::GPUBuffer* counterBuffer_read, UINT counterReadOffset, wiGraphicsTypes::GPUBuffer* indexBuffer_write, GRAPHICSTHREAD threadID);
- static void Initialize();
- static void LoadShaders();
- static void CleanUpStatic();
+ void Initialize();
+ void LoadShaders();
+ void CleanUp();
};
#endif // _WI_GPU_SORTLIB_H_
diff --git a/WickedEngine/wiInitializer.cpp b/WickedEngine/wiInitializer.cpp
index 120ba55d2..52d3fb4be 100644
--- a/WickedEngine/wiInitializer.cpp
+++ b/WickedEngine/wiInitializer.cpp
@@ -11,6 +11,7 @@
#include "wiHelper.h"
#include "wiWidget.h"
#include "wiGPUSortLib.h"
+#include "wiGPUBVH.h"
#include "wiPhysicsEngine.h"
using namespace std;
@@ -32,6 +33,7 @@ namespace wiInitializer
wiWidget::LoadShaders();
wiGPUSortLib::LoadShaders();
+ wiGPUBVH::LoadShaders();
wiPhysicsEngine::Initialize();
diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp
index 08c3c3008..725a7b8af 100644
--- a/WickedEngine/wiRenderer.cpp
+++ b/WickedEngine/wiRenderer.cpp
@@ -29,6 +29,7 @@
#include "wiWidget.h"
#include "wiGPUSortLib.h"
#include "wiAllocator.h"
+#include "wiGPUBVH.h"
#include
#include
@@ -144,6 +145,8 @@ XMFLOAT4 waterPlane = XMFLOAT4(0, 1, 0, 0);
wiSpinLock deferredMIPGenLock;
unordered_set deferredMIPGens;
+wiGPUBVH sceneBVH;
+
void SetDevice(wiGraphicsTypes::GraphicsDevice* newDevice)
{
@@ -1351,8 +1354,6 @@ void RenderMeshes(const RenderQueue& renderQueue, SHADERTYPE shaderType, UINT re
tessellation = tessellation && device->CheckCapability(GraphicsDevice::GRAPHICSDEVICE_CAPABILITY_TESSELLATION);
- const XMFLOAT4X4 __identityMat = XMFLOAT4X4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
-
struct InstBuf
{
Instance instance;
@@ -2004,12 +2005,6 @@ void LoadShaders()
computeShaders[CSTYPE_SKINNING] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "skinningCS.cso", wiResourceManager::COMPUTESHADER));
computeShaders[CSTYPE_SKINNING_LDS] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "skinningCS_LDS.cso", wiResourceManager::COMPUTESHADER));
computeShaders[CSTYPE_CLOUDGENERATOR] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "cloudGeneratorCS.cso", wiResourceManager::COMPUTESHADER));
- computeShaders[CSTYPE_BVH_RESET] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_resetCS.cso", wiResourceManager::COMPUTESHADER));
- computeShaders[CSTYPE_BVH_CLASSIFICATION] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_classificationCS.cso", wiResourceManager::COMPUTESHADER));
- computeShaders[CSTYPE_BVH_KICKJOBS] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_kickjobsCS.cso", wiResourceManager::COMPUTESHADER));
- computeShaders[CSTYPE_BVH_CLUSTERPROCESSOR] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_clusterprocessorCS.cso", wiResourceManager::COMPUTESHADER));
- computeShaders[CSTYPE_BVH_HIERARCHY] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_hierarchyCS.cso", wiResourceManager::COMPUTESHADER));
- computeShaders[CSTYPE_BVH_PROPAGATEAABB] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "bvh_propagateaabbCS.cso", wiResourceManager::COMPUTESHADER));
computeShaders[CSTYPE_RAYTRACE_CLEAR] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "raytrace_clearCS.cso", wiResourceManager::COMPUTESHADER));
computeShaders[CSTYPE_RAYTRACE_LAUNCH] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "raytrace_launchCS.cso", wiResourceManager::COMPUTESHADER));
computeShaders[CSTYPE_RAYTRACE_KICKJOBS] = static_cast(wiResourceManager::GetShaderManager()->add(SHADERPATH + "raytrace_kickjobsCS.cso", wiResourceManager::COMPUTESHADER));
@@ -2830,10 +2825,6 @@ void LoadBuffers()
device->CreateBuffer(&bd, nullptr, constantBuffers[CBTYPE_RAYTRACE]);
device->SetName(constantBuffers[CBTYPE_RAYTRACE], "RayTraceCB");
- bd.ByteWidth = sizeof(BVHCB);
- device->CreateBuffer(&bd, nullptr, constantBuffers[CBTYPE_BVH]);
- device->SetName(constantBuffers[CBTYPE_BVH], "BVHGeneratorCB");
-
bd.ByteWidth = sizeof(GenerateMIPChainCB);
device->CreateBuffer(&bd, nullptr, constantBuffers[CBTYPE_MIPGEN]);
device->SetName(constantBuffers[CBTYPE_MIPGEN], "MipGeneratorCB");
@@ -6717,379 +6708,11 @@ void CopyTexture2D(Texture2D* dst, UINT DstMIP, UINT DstX, UINT DstY, Texture2D*
}
-
-GPUBuffer* bvhNodeBuffer = nullptr;
-GPUBuffer* bvhAABBBuffer = nullptr;
-GPUBuffer* bvhFlagBuffer = nullptr;
-GPUBuffer* triangleBuffer = nullptr;
-GPUBuffer* clusterCounterBuffer = nullptr;
-GPUBuffer* clusterIndexBuffer = nullptr;
-GPUBuffer* clusterMortonBuffer = nullptr;
-GPUBuffer* clusterSortedMortonBuffer = nullptr;
-GPUBuffer* clusterOffsetBuffer = nullptr;
-GPUBuffer* clusterAABBBuffer = nullptr;
-GPUBuffer* clusterConeBuffer = nullptr;
void BuildSceneBVH(GRAPHICSTHREAD threadID)
{
- GraphicsDevice* device = GetDevice();
Scene& scene = GetScene();
- // Pre-gather scene properties:
- uint totalTriangles = 0;
- for (size_t i = 0; i < scene.meshes.GetCount(); ++i)
- {
- const MeshComponent& mesh = scene.meshes[i];
-
- totalTriangles += (uint)mesh.indices.size() / 3;
- }
-
- static uint maxTriangleCount = 0;
- static uint maxClusterCount = 0;
-
- if (totalTriangles > maxTriangleCount)
- {
- maxTriangleCount = totalTriangles;
- maxClusterCount = maxTriangleCount; // todo: cluster / triangle capacity
-
- GPUBufferDesc desc;
- HRESULT hr;
-
- SAFE_DELETE(bvhNodeBuffer);
- SAFE_DELETE(bvhAABBBuffer);
- SAFE_DELETE(bvhFlagBuffer);
- SAFE_DELETE(triangleBuffer);
- SAFE_DELETE(clusterCounterBuffer);
- SAFE_DELETE(clusterIndexBuffer);
- SAFE_DELETE(clusterMortonBuffer);
- SAFE_DELETE(clusterSortedMortonBuffer);
- SAFE_DELETE(clusterOffsetBuffer);
- SAFE_DELETE(clusterAABBBuffer);
- SAFE_DELETE(clusterConeBuffer);
- bvhNodeBuffer = new GPUBuffer;
- bvhAABBBuffer = new GPUBuffer;
- bvhFlagBuffer = new GPUBuffer;
- triangleBuffer = new GPUBuffer;
- clusterCounterBuffer = new GPUBuffer;
- clusterIndexBuffer = new GPUBuffer;
- clusterMortonBuffer = new GPUBuffer;
- clusterSortedMortonBuffer = new GPUBuffer;
- clusterOffsetBuffer = new GPUBuffer;
- clusterAABBBuffer = new GPUBuffer;
- clusterConeBuffer = new GPUBuffer;
-
- desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
- desc.StructureByteStride = sizeof(BVHNode);
- desc.ByteWidth = desc.StructureByteStride * maxClusterCount * 2;
- desc.CPUAccessFlags = 0;
- desc.Format = FORMAT_UNKNOWN;
- desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
- desc.Usage = USAGE_DEFAULT;
- hr = device->CreateBuffer(&desc, nullptr, bvhNodeBuffer);
- assert(SUCCEEDED(hr));
- device->SetName(bvhNodeBuffer, "BVHNodeBuffer");
-
- desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
- desc.StructureByteStride = sizeof(BVHAABB);
- desc.ByteWidth = desc.StructureByteStride * maxClusterCount * 2;
- desc.CPUAccessFlags = 0;
- desc.Format = FORMAT_UNKNOWN;
- desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
- desc.Usage = USAGE_DEFAULT;
- hr = device->CreateBuffer(&desc, nullptr, bvhAABBBuffer);
- assert(SUCCEEDED(hr));
- device->SetName(bvhAABBBuffer, "BVHAABBBuffer");
-
- desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
- desc.StructureByteStride = sizeof(uint);
- desc.ByteWidth = desc.StructureByteStride * (maxClusterCount - 1); // only for internal nodes
- desc.CPUAccessFlags = 0;
- desc.Format = FORMAT_UNKNOWN;
- desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
- desc.Usage = USAGE_DEFAULT;
- hr = device->CreateBuffer(&desc, nullptr, bvhFlagBuffer);
- assert(SUCCEEDED(hr));
- device->SetName(bvhFlagBuffer, "BVHFlagBuffer");
-
- desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
- desc.StructureByteStride = sizeof(BVHMeshTriangle);
- desc.ByteWidth = desc.StructureByteStride * maxTriangleCount;
- desc.CPUAccessFlags = 0;
- desc.Format = FORMAT_UNKNOWN;
- desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
- desc.Usage = USAGE_DEFAULT;
- hr = device->CreateBuffer(&desc, nullptr, triangleBuffer);
- assert(SUCCEEDED(hr));
- device->SetName(triangleBuffer, "BVHTriangleBuffer");
-
- desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
- desc.StructureByteStride = sizeof(uint);
- desc.ByteWidth = desc.StructureByteStride;
- desc.CPUAccessFlags = 0;
- desc.Format = FORMAT_UNKNOWN;
- desc.MiscFlags = RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
- desc.Usage = USAGE_DEFAULT;
- hr = device->CreateBuffer(&desc, nullptr, clusterCounterBuffer);
- assert(SUCCEEDED(hr));
- device->SetName(clusterCounterBuffer, "BVHClusterCounterBuffer");
-
- desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
- desc.StructureByteStride = sizeof(uint);
- desc.ByteWidth = desc.StructureByteStride * maxClusterCount;
- desc.CPUAccessFlags = 0;
- desc.Format = FORMAT_UNKNOWN;
- desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
- desc.Usage = USAGE_DEFAULT;
- hr = device->CreateBuffer(&desc, nullptr, clusterIndexBuffer);
- assert(SUCCEEDED(hr));
- device->SetName(clusterIndexBuffer, "BVHClusterIndexBuffer");
-
- desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
- desc.StructureByteStride = sizeof(uint);
- desc.ByteWidth = desc.StructureByteStride * maxClusterCount;
- desc.CPUAccessFlags = 0;
- desc.Format = FORMAT_UNKNOWN;
- desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
- desc.Usage = USAGE_DEFAULT;
- hr = device->CreateBuffer(&desc, nullptr, clusterMortonBuffer);
- hr = device->CreateBuffer(&desc, nullptr, clusterSortedMortonBuffer);
- assert(SUCCEEDED(hr));
- device->SetName(clusterMortonBuffer, "BVHClusterMortonBuffer");
- device->SetName(clusterSortedMortonBuffer, "BVHSortedClusterMortonBuffer");
-
- desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
- desc.StructureByteStride = sizeof(uint2);
- desc.ByteWidth = desc.StructureByteStride * maxClusterCount;
- desc.CPUAccessFlags = 0;
- desc.Format = FORMAT_UNKNOWN;
- desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
- desc.Usage = USAGE_DEFAULT;
- hr = device->CreateBuffer(&desc, nullptr, clusterOffsetBuffer);
- assert(SUCCEEDED(hr));
- device->SetName(clusterOffsetBuffer, "BVHClusterOffsetBuffer");
-
- desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
- desc.StructureByteStride = sizeof(BVHAABB);
- desc.ByteWidth = desc.StructureByteStride * maxClusterCount;
- desc.CPUAccessFlags = 0;
- desc.Format = FORMAT_UNKNOWN;
- desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
- desc.Usage = USAGE_DEFAULT;
- hr = device->CreateBuffer(&desc, nullptr, clusterAABBBuffer);
- assert(SUCCEEDED(hr));
- device->SetName(clusterAABBBuffer, "BVHClusterAABBBuffer");
-
- desc.BindFlags = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS;
- desc.StructureByteStride = sizeof(ClusterCone);
- desc.ByteWidth = desc.StructureByteStride * maxClusterCount;
- desc.CPUAccessFlags = 0;
- desc.Format = FORMAT_UNKNOWN;
- desc.MiscFlags = RESOURCE_MISC_BUFFER_STRUCTURED;
- desc.Usage = USAGE_DEFAULT;
- hr = device->CreateBuffer(&desc, nullptr, clusterConeBuffer);
- assert(SUCCEEDED(hr));
- device->SetName(clusterConeBuffer, "BVHClusterConeBuffer");
- }
-
- static GPUBuffer* indirectBuffer = nullptr; // GPU job kicks
- if (indirectBuffer == nullptr)
- {
- GPUBufferDesc desc;
- HRESULT hr;
-
- SAFE_DELETE(indirectBuffer);
- indirectBuffer = new GPUBuffer;
-
- desc.BindFlags = BIND_UNORDERED_ACCESS;
- desc.StructureByteStride = sizeof(IndirectDispatchArgs) * 2;
- desc.ByteWidth = desc.StructureByteStride;
- desc.CPUAccessFlags = 0;
- desc.Format = FORMAT_UNKNOWN;
- desc.MiscFlags = RESOURCE_MISC_DRAWINDIRECT_ARGS | RESOURCE_MISC_BUFFER_ALLOW_RAW_VIEWS;
- desc.Usage = USAGE_DEFAULT;
- hr = device->CreateBuffer(&desc, nullptr, indirectBuffer);
- assert(SUCCEEDED(hr));
- }
-
-
- wiProfiler::GetInstance().BeginRange("BVH Rebuild", wiProfiler::DOMAIN_GPU, threadID);
-
- device->EventBegin("BVH - Reset", threadID);
- {
- device->BindComputePSO(CPSO[CSTYPE_BVH_RESET], threadID);
-
- GPUResource* uavs[] = {
- clusterCounterBuffer,
- bvhNodeBuffer,
- bvhAABBBuffer,
- };
- device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
-
- device->Dispatch(1, 1, 1, threadID);
- }
- device->EventEnd(threadID);
-
-
- uint32_t triangleCount = 0;
- uint32_t materialCount = 0;
-
- device->EventBegin("BVH - Classification", threadID);
- {
- device->BindComputePSO(CPSO[CSTYPE_BVH_CLASSIFICATION], threadID);
- GPUResource* uavs[] = {
- triangleBuffer,
- clusterCounterBuffer,
- clusterIndexBuffer,
- clusterMortonBuffer,
- clusterOffsetBuffer,
- clusterAABBBuffer,
- };
- device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
-
- for (size_t i = 0; i < scene.objects.GetCount(); ++i)
- {
- const ObjectComponent& object = scene.objects[i];
-
- if (object.meshID != INVALID_ENTITY)
- {
- const MeshComponent& mesh = *scene.meshes.GetComponent(object.meshID);
- Entity entity = scene.objects.GetEntity(i);
- const TransformComponent& transform = scene.transforms[object.transformComponentIndex];
-
- BVHCB cb;
- cb.xTraceBVHWorld = transform.world;
- cb.xTraceBVHMaterialOffset = materialCount;
- cb.xTraceBVHMeshTriangleOffset = triangleCount;
- cb.xTraceBVHMeshTriangleCount = (uint)mesh.indices.size() / 3;
- cb.xTraceBVHMeshVertexPOSStride = sizeof(MeshComponent::Vertex_POS);
-
- device->UpdateBuffer(constantBuffers[CBTYPE_BVH], &cb, threadID);
-
- triangleCount += cb.xTraceBVHMeshTriangleCount;
-
- device->BindConstantBuffer(CS, constantBuffers[CBTYPE_BVH], CB_GETBINDSLOT(BVHCB), threadID);
-
- GPUResource* res[] = {
- mesh.indexBuffer.get(),
- mesh.vertexBuffer_POS.get(),
- mesh.vertexBuffer_TEX.get(),
- };
- device->BindResources(CS, res, TEXSLOT_ONDEMAND0, ARRAYSIZE(res), threadID);
-
- device->Dispatch((UINT)ceilf((float)cb.xTraceBVHMeshTriangleCount / (float)BVH_CLASSIFICATION_GROUPSIZE), 1, 1, threadID);
-
- for (auto& subset : mesh.subsets)
- {
- materialCount++;
- }
- }
- }
-
- device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
- device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
- }
- device->EventEnd(threadID);
-
-
- device->EventBegin("BVH - Sort Cluster Mortons", threadID);
- wiGPUSortLib::Sort(maxClusterCount, clusterMortonBuffer, clusterCounterBuffer, 0, clusterIndexBuffer, threadID);
- device->EventEnd(threadID);
-
- device->EventBegin("BVH - Kick Jobs", threadID);
- {
- device->BindComputePSO(CPSO[CSTYPE_BVH_KICKJOBS], threadID);
- GPUResource* uavs[] = {
- indirectBuffer,
- };
- device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
-
- GPUResource* res[] = {
- clusterCounterBuffer,
- };
- device->BindResources(CS, res, TEXSLOT_ONDEMAND0, ARRAYSIZE(res), threadID);
-
- device->Dispatch(1, 1, 1, threadID);
-
- device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
- device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
- }
- device->EventEnd(threadID);
-
- device->EventBegin("BVH - Cluster Processor", threadID);
- {
- device->BindComputePSO(CPSO[CSTYPE_BVH_CLUSTERPROCESSOR], threadID);
- GPUResource* uavs[] = {
- clusterSortedMortonBuffer,
- clusterConeBuffer,
- };
- device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
-
- GPUResource* res[] = {
- clusterCounterBuffer,
- clusterIndexBuffer,
- clusterMortonBuffer,
- clusterOffsetBuffer,
- clusterAABBBuffer,
- triangleBuffer,
- };
- device->BindResources(CS, res, TEXSLOT_ONDEMAND0, ARRAYSIZE(res), threadID);
-
- device->DispatchIndirect(indirectBuffer, ARGUMENTBUFFER_OFFSET_CLUSTERPROCESSOR, threadID);
-
-
- device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
- device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
- }
- device->EventEnd(threadID);
-
- device->EventBegin("BVH - Build Hierarchy", threadID);
- {
- device->BindComputePSO(CPSO[CSTYPE_BVH_HIERARCHY], threadID);
- GPUResource* uavs[] = {
- bvhNodeBuffer,
- bvhFlagBuffer,
- };
- device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
-
- GPUResource* res[] = {
- clusterCounterBuffer,
- clusterSortedMortonBuffer,
- };
- device->BindResources(CS, res, TEXSLOT_ONDEMAND0, ARRAYSIZE(res), threadID);
-
- device->DispatchIndirect(indirectBuffer, ARGUMENTBUFFER_OFFSET_HIERARCHY, threadID);
-
-
- device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
- device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
- }
- device->EventEnd(threadID);
-
- device->EventBegin("BVH - Propagate AABB", threadID);
- {
- device->BindComputePSO(CPSO[CSTYPE_BVH_PROPAGATEAABB], threadID);
- GPUResource* uavs[] = {
- bvhAABBBuffer,
- bvhFlagBuffer,
- };
- device->BindUAVs(CS, uavs, 0, ARRAYSIZE(uavs), threadID);
-
- GPUResource* res[] = {
- clusterCounterBuffer,
- clusterIndexBuffer,
- clusterAABBBuffer,
- bvhNodeBuffer,
- };
- device->BindResources(CS, res, TEXSLOT_ONDEMAND0, ARRAYSIZE(res), threadID);
-
- device->DispatchIndirect(indirectBuffer, ARGUMENTBUFFER_OFFSET_CLUSTERPROCESSOR, threadID);
-
-
- device->UAVBarrier(uavs, ARRAYSIZE(uavs), threadID);
- device->UnbindUAVs(0, ARRAYSIZE(uavs), threadID);
- }
- device->EventEnd(threadID);
-
- wiProfiler::GetInstance().EndRange(threadID); // BVH rebuild
+ sceneBVH.Build(scene, threadID);
}
void DrawTracedScene(const CameraComponent& camera, Texture2D* result, GRAPHICSTHREAD threadID)
{
@@ -7440,16 +7063,11 @@ void DrawTracedScene(const CameraComponent& camera, Texture2D* result, GRAPHICST
// Set up tracing resources:
GPUResource* res[] = {
materialBuffer,
- triangleBuffer,
- clusterCounterBuffer,
- clusterIndexBuffer,
- clusterOffsetBuffer,
- clusterConeBuffer,
- bvhNodeBuffer,
- bvhAABBBuffer,
};
device->BindResources(CS, res, TEXSLOT_ONDEMAND0, ARRAYSIZE(res), threadID);
+ sceneBVH.Bind(threadID);
+
if (atlasTexture != nullptr)
{
device->BindResource(CS, atlasTexture, TEXSLOT_ONDEMAND8, threadID);
diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp
index b8c39dce0..41e6db95b 100644
--- a/WickedEngine/wiVersion.cpp
+++ b/WickedEngine/wiVersion.cpp
@@ -9,7 +9,7 @@ namespace wiVersion
// minor features, major updates
const int minor = 21;
// minor bug fixes, alterations, refactors, updates
- const int revision = 9;
+ const int revision = 10;
long GetVersion()