Adding basic CBT Terrain implementation
This commit is contained in:
@@ -0,0 +1,797 @@
|
||||
#include "CBT.h"
|
||||
#include "Graphics/Shader.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
Array<Vector4> basePoints = {
|
||||
Vector4(000.0f / 3, 0, 000.0f / 3, 1), Vector4(000.0f / 3, 0, 100.0f / 3, 1), Vector4(000.0f / 3, 0, 200.0f / 3, 1),
|
||||
Vector4(000.0f / 3, 0, 300.0f / 3, 1), Vector4(100.0f / 3, 0, 000.0f / 3, 1), Vector4(100.0f / 3, 0, 100.0f / 3, 1),
|
||||
Vector4(100.0f / 3, 0, 200.0f / 3, 1), Vector4(100.0f / 3, 0, 300.0f / 3, 1), Vector4(200.0f / 3, 0, 000.0f / 3, 1),
|
||||
Vector4(200.0f / 3, 0, 100.0f / 3, 1), Vector4(200.0f / 3, 0, 200.0f / 3, 1), Vector4(200.0f / 3, 0, 300.0f / 3, 1),
|
||||
Vector4(300.0f / 3, 0, 000.0f / 3, 1), Vector4(300.0f / 3, 0, 100.0f / 3, 1), Vector4(300.0f / 3, 0, 200.0f / 3, 1),
|
||||
Vector4(300.0f / 3, 0, 300.0f / 3, 1),
|
||||
};
|
||||
struct Halfedge {
|
||||
uint32 vertexID;
|
||||
uint32 nextID;
|
||||
uint32 prevID;
|
||||
uint32 twinID;
|
||||
};
|
||||
Array<Halfedge> edges = {
|
||||
Halfedge{0, 1, 2, 4294967295},
|
||||
Halfedge{1, 2, 0, 3},
|
||||
Halfedge{4, 0, 1, 4294967295},
|
||||
Halfedge{4, 4, 5, 1},
|
||||
Halfedge{1, 5, 3, 8},
|
||||
Halfedge{5, 3, 4, 18},
|
||||
Halfedge{1, 7, 8, 4294967295},
|
||||
Halfedge{2, 8, 6, 9},
|
||||
Halfedge{5, 6, 7, 4},
|
||||
Halfedge{5, 10, 11, 7},
|
||||
Halfedge{2, 11, 9, 14},
|
||||
Halfedge{6, 9, 10, 24},
|
||||
Halfedge{2, 13, 14, 4294967295},
|
||||
Halfedge{3, 14, 12, 15},
|
||||
Halfedge{6, 12, 13, 10},
|
||||
Halfedge{6, 16, 17, 13},
|
||||
Halfedge{3, 17, 15, 4294967295},
|
||||
Halfedge{7, 15, 16, 30},
|
||||
Halfedge{4, 19, 20, 5},
|
||||
Halfedge{5, 20, 18, 21},
|
||||
Halfedge{8, 18, 19, 4294967295},
|
||||
Halfedge{8, 22, 23, 19},
|
||||
Halfedge{5, 23, 21, 26},
|
||||
Halfedge{9, 21, 22, 36},
|
||||
Halfedge{5, 25, 26, 11},
|
||||
Halfedge{6, 26, 24, 27},
|
||||
Halfedge{9, 24, 25, 22},
|
||||
Halfedge{9, 28, 29, 25},
|
||||
Halfedge{6, 29, 27, 32},
|
||||
Halfedge{10, 27, 28, 42},
|
||||
Halfedge{6, 31, 32, 17},
|
||||
Halfedge{7, 32, 30, 33},
|
||||
Halfedge{10, 30, 31, 28},
|
||||
Halfedge{10, 34, 35, 31},
|
||||
Halfedge{7, 35, 33, 4294967295},
|
||||
Halfedge{11, 33, 34, 48},
|
||||
Halfedge{8, 37, 38, 23},
|
||||
Halfedge{9, 38, 36, 39},
|
||||
Halfedge{12, 36, 37, 4294967295},
|
||||
Halfedge{12, 40, 41, 37},
|
||||
Halfedge{9, 41, 39, 44},
|
||||
Halfedge{13, 39, 40, 4294967295},
|
||||
Halfedge{9, 43, 44, 29},
|
||||
Halfedge{10, 44, 42, 45},
|
||||
Halfedge{13, 42, 43, 40},
|
||||
Halfedge{13, 46, 47, 43},
|
||||
Halfedge{10, 47, 45, 50},
|
||||
Halfedge{14, 45, 46, 4294967295},
|
||||
Halfedge{10, 49, 50, 35},
|
||||
Halfedge{11, 50, 48, 51},
|
||||
Halfedge{14, 48, 49, 46},
|
||||
Halfedge{14, 52, 53, 49},
|
||||
Halfedge{11, 53, 51, 4294967295},
|
||||
Halfedge{15, 51, 52, 4294967295},
|
||||
};
|
||||
|
||||
uint32_t find_msb_64(uint64_t x) {
|
||||
uint32_t depth = 0;
|
||||
while (x > 0u) {
|
||||
++depth;
|
||||
x >>= 1uLL;
|
||||
}
|
||||
return depth;
|
||||
}
|
||||
|
||||
CPUMesh Seele::generateCPUMesh(uint32 cbtNumElements) {
|
||||
CPUMesh result;
|
||||
result.totalNumElements = edges.size() + cbtNumElements;
|
||||
|
||||
result.heapIDArray.resize(result.totalNumElements);
|
||||
result.neighborsArray.resize(result.totalNumElements);
|
||||
std::memset(result.heapIDArray.data(), 0, result.totalNumElements * sizeof(uint64));
|
||||
std::memset(result.neighborsArray.data(), 0, result.totalNumElements * sizeof(UVector));
|
||||
|
||||
result.minimalDepth = std::min(find_msb_64(edges.size()), 63u) + 1;
|
||||
const uint64 baseHeapID = 1ull << (result.minimalDepth - 1);
|
||||
|
||||
result.basePoints.resize(edges.size() * 3);
|
||||
|
||||
UVector neighbours;
|
||||
for (uint32 halfedgeIdx = 0; halfedgeIdx < (uint32)edges.size(); ++halfedgeIdx) {
|
||||
uint32 elementID = cbtNumElements + halfedgeIdx;
|
||||
|
||||
result.heapIDArray[elementID] = baseHeapID + halfedgeIdx;
|
||||
|
||||
Halfedge& halfedge = edges[halfedgeIdx];
|
||||
neighbours.x = halfedge.prevID != -1 ? cbtNumElements + halfedge.prevID : UINT32_MAX;
|
||||
neighbours.y = halfedge.nextID != -1 ? cbtNumElements + halfedge.nextID : UINT32_MAX;
|
||||
neighbours.z = halfedge.twinID != -1 ? cbtNumElements + halfedge.twinID : UINT32_MAX;
|
||||
result.neighborsArray[elementID] = UVector4(neighbours, 1);
|
||||
|
||||
result.basePoints[3 * halfedgeIdx + 2] = basePoints[halfedge.vertexID];
|
||||
|
||||
Halfedge& nextHalfedge = edges[halfedge.nextID];
|
||||
result.basePoints[3 * halfedgeIdx + 0] = basePoints[nextHalfedge.vertexID];
|
||||
|
||||
Vector thirdVertex = result.basePoints[3 * halfedgeIdx + 2];
|
||||
float sumWeight = 1.0f;
|
||||
uint32 currentIdx = halfedge.nextID;
|
||||
while (currentIdx != halfedgeIdx) {
|
||||
Halfedge currentHalfedge = edges[currentIdx];
|
||||
Vector vp = basePoints[currentHalfedge.vertexID];
|
||||
thirdVertex += vp;
|
||||
sumWeight += 1.0f;
|
||||
currentIdx = currentHalfedge.nextID;
|
||||
}
|
||||
result.basePoints[3 * halfedgeIdx + 1] = Vector4(thirdVertex / sumWeight, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
Matrix3 splittingMatrix(uint32 bitValue) {
|
||||
float b = float(bitValue);
|
||||
float c = 1.0f - b;
|
||||
|
||||
return glm::transpose(Matrix3({
|
||||
0.0f,
|
||||
b,
|
||||
c,
|
||||
0.5f,
|
||||
0.0f,
|
||||
0.5f,
|
||||
b,
|
||||
c,
|
||||
0.0f,
|
||||
}));
|
||||
}
|
||||
|
||||
Matrix3 decodeSubdivisionMatrix(uint64 heapID) {
|
||||
Matrix3 m = Matrix3({1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f});
|
||||
int32 depth = find_msb_64(heapID) - 1;
|
||||
for (int32 bitID = depth - 1; bitID >= 0; --bitID) {
|
||||
m = splittingMatrix((heapID >> bitID) & 1u) * m;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
void LebMatrixCache::init(Gfx::PGraphics graphics, uint32 depth) {
|
||||
cacheDepth = depth;
|
||||
uint32 matrixCount = 2ULL << cacheDepth;
|
||||
struct PaddedMatrix
|
||||
{
|
||||
Matrix3 m;
|
||||
uint8 pad[12];
|
||||
};
|
||||
std::vector<PaddedMatrix> table(matrixCount);
|
||||
table[0].m = Matrix3({1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f});
|
||||
for (uint64 heapID = 1ULL; heapID < (2ULL << cacheDepth); ++heapID) {
|
||||
table[heapID].m = decodeSubdivisionMatrix(heapID);
|
||||
}
|
||||
lebMatrixBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(PaddedMatrix) * matrixCount,
|
||||
.data = (uint8*)table.data(),
|
||||
},
|
||||
.name = "LebMatrixCache",
|
||||
});
|
||||
lebMatrixBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
void LebMatrixCache::release() {}
|
||||
|
||||
void MeshUpdater::init(Gfx::PGraphics gfx, Gfx::PDescriptorLayout viewParamsLayout) {
|
||||
graphics = gfx;
|
||||
layout = graphics->createDescriptorLayout("pParams");
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{1, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{2, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{3, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{4, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{5, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{6, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{7, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{8, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{9, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{10, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{11, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{12, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{13, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{14, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{15, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{16, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{17, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{18, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{19, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{20, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{21, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{22, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER});
|
||||
layout->create();
|
||||
pipelineLayout = graphics->createPipelineLayout("ComputeLayout");
|
||||
pipelineLayout->addDescriptorLayout(viewParamsLayout);
|
||||
pipelineLayout->addDescriptorLayout(layout);
|
||||
indirectBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32) * 9,
|
||||
},
|
||||
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||
.name = "IndirectBuffer",
|
||||
});
|
||||
memoryBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(int32) * 2,
|
||||
},
|
||||
.name = "MemoryBuffer",
|
||||
});
|
||||
validationBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(int32) * 2,
|
||||
},
|
||||
.name = "ValidationBuffer",
|
||||
});
|
||||
validationBufferRB = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(int32) * 2,
|
||||
},
|
||||
.name = "ValidationBufferRB",
|
||||
});
|
||||
occupancyBufferRB = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32),
|
||||
},
|
||||
.name = "OccupancyBuffer",
|
||||
});
|
||||
|
||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||
.name = "CBTCompute",
|
||||
.modules = {"CBTCompute"},
|
||||
.entryPoints =
|
||||
{
|
||||
{"reset", "CBTCompute"},
|
||||
{"classify", "CBTCompute"},
|
||||
{"split", "CBTCompute"},
|
||||
{"prepareIndirect", "CBTCompute"},
|
||||
{"allocate", "CBTCompute"},
|
||||
{"bisect", "CBTCompute"},
|
||||
{"propagateBisect", "CBTCompute"},
|
||||
{"prepareSimplify", "CBTCompute"},
|
||||
{"simplify", "CBTCompute"},
|
||||
{"propagateSimplify", "CBTCompute"},
|
||||
{"reducePrePass", "CBTCompute"},
|
||||
{"reduceFirstPass", "CBTCompute"},
|
||||
{"reduceSecondPass", "CBTCompute"},
|
||||
{"bisectorIndexation", "CBTCompute"},
|
||||
{"prepareBisectorIndirect", "CBTCompute"},
|
||||
{"validate", "CBTCompute"},
|
||||
{"clearLeb", "CBTCompute"},
|
||||
{"evaluateLeb", "CBTCompute"},
|
||||
},
|
||||
.rootSignature = pipelineLayout,
|
||||
});
|
||||
pipelineLayout->create();
|
||||
resetCS = graphics->createComputeShader({0});
|
||||
reset = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = resetCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
classifyCS = graphics->createComputeShader({1});
|
||||
classify = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = classifyCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
splitCS = graphics->createComputeShader({2});
|
||||
split = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = splitCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
prepareIndirectCS = graphics->createComputeShader({3});
|
||||
prepareIndirect = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = prepareIndirectCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
allocateCS = graphics->createComputeShader({4});
|
||||
allocate = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = allocateCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
bisectCS = graphics->createComputeShader({5});
|
||||
bisect = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = bisectCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
propagateBisectCS = graphics->createComputeShader({6});
|
||||
propagateBisect = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = propagateBisectCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
prepareSimplifyCS = graphics->createComputeShader({7});
|
||||
prepareSimplify = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = prepareSimplifyCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
simplifyCS = graphics->createComputeShader({8});
|
||||
simplify = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = simplifyCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
propagateSimplifyCS = graphics->createComputeShader({9});
|
||||
propagateSimplify = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = propagateSimplifyCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
reducePrePassCS = graphics->createComputeShader({10});
|
||||
reducePrePass = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = reducePrePassCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
reduceFirstPassCS = graphics->createComputeShader({11});
|
||||
reduceFirstPass = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = reduceFirstPassCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
reduceSecondPassCS = graphics->createComputeShader({12});
|
||||
reduceSecondPass = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = reduceSecondPassCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
bisectorIndexationCS = graphics->createComputeShader({13});
|
||||
bisectorIndexation = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = bisectorIndexationCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
prepareBisectorIndirectCS = graphics->createComputeShader({14});
|
||||
prepareBisectorIndirect = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = prepareBisectorIndirectCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
validateCS = graphics->createComputeShader({15});
|
||||
validate = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = validateCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
lebClearCS = graphics->createComputeShader({16});
|
||||
lebClear = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = lebClearCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
lebEvaluateCS = graphics->createComputeShader({17});
|
||||
lebEvaluate = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = lebEvaluateCS,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
});
|
||||
}
|
||||
|
||||
void MeshUpdater::release() {}
|
||||
|
||||
void MeshUpdater::evaluateLeb(const BaseMesh& baseMesh, CBTMesh& mesh, Gfx::PDescriptorSet viewParamsSet,
|
||||
Gfx::PUniformBuffer geometryBuffer, Gfx::PUniformBuffer updateBuffer, Gfx::PShaderBuffer lebMatrixCache,
|
||||
bool clear, bool complete) {
|
||||
if (clear) {
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryBuffer);
|
||||
set->updateBuffer(LEB_POSITION_BUFFER, 0, mesh.currentVertexBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand clearCmd = graphics->createComputeCommand("Clear");
|
||||
clearCmd->bindPipeline(lebClear);
|
||||
clearCmd->bindDescriptor(set);
|
||||
clearCmd->dispatch((mesh.totalNumElements * 3 + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE, 1, 1);
|
||||
mesh.currentVertexBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryBuffer);
|
||||
set->updateBuffer(UPDATE_CB, 0, updateBuffer);
|
||||
set->updateBuffer(CURRENT_VERTEX_BUFFER, 0, baseMesh.vertexBuffer);
|
||||
set->updateBuffer(HEAP_ID_BUFFER, 0, mesh.heapIDBuffer);
|
||||
set->updateBuffer(INDEXED_BISECTOR_BUFFER, 0, complete ? mesh.indexedBisectorBuffer : mesh.modifiedIndexedBisectorBuffer);
|
||||
set->updateBuffer(INDIRECT_DRAW_BUFFER, 0, mesh.indirectDrawBuffer);
|
||||
set->updateBuffer(LEB_MATRIX_CACHE, 0, lebMatrixCache);
|
||||
set->updateBuffer(LEB_POSITION_BUFFER, 0, mesh.lebVertexBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand evalCmd = graphics->createComputeCommand("EvalLEB");
|
||||
evalCmd->bindPipeline(lebEvaluate);
|
||||
evalCmd->bindDescriptor({set, viewParamsSet});
|
||||
evalCmd->dispatchIndirect(mesh.indirectDispatchBuffer, complete ? 0 : sizeof(uint32) * 6);
|
||||
graphics->executeCommands(std::move(evalCmd));
|
||||
mesh.currentVertexBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
void MeshUpdater::update(CBTMesh& mesh, Gfx::PDescriptorSet viewParamsSet, Gfx::PUniformBuffer geometryCB, Gfx::PUniformBuffer updateCB) {
|
||||
uint32 nextNeighborsBufferIdx = (mesh.currentNeighborsBufferIdx + 1) % 2;
|
||||
Gfx::PShaderBuffer currentNeighborsBuffer = mesh.neighborsBuffers[mesh.currentNeighborsBufferIdx];
|
||||
Gfx::PShaderBuffer nextNeighborsBuffer = mesh.neighborsBuffers[nextNeighborsBufferIdx];
|
||||
|
||||
resetBuffers(mesh);
|
||||
|
||||
// classify
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryCB);
|
||||
set->updateBuffer(UPDATE_CB, 0, updateCB);
|
||||
|
||||
set->updateBuffer(CURRENT_VERTEX_BUFFER, 0, mesh.currentVertexBuffer);
|
||||
set->updateBuffer(INDEXED_BISECTOR_BUFFER, 0, mesh.indexedBisectorBuffer);
|
||||
|
||||
set->updateBuffer(INDIRECT_DRAW_BUFFER, 0, mesh.indirectDrawBuffer);
|
||||
set->updateBuffer(HEAP_ID_BUFFER, 0, mesh.heapIDBuffer);
|
||||
set->updateBuffer(BISECTOR_DATA_BUFFER, 0, mesh.updateBuffer);
|
||||
set->updateBuffer(CLASSIFICATION_BUFFER, 0, mesh.classificationBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand classifyCmd = graphics->createComputeCommand("Classify");
|
||||
classifyCmd->bindPipeline(classify);
|
||||
classifyCmd->bindDescriptor({viewParamsSet, set});
|
||||
classifyCmd->dispatchIndirect(mesh.indirectDispatchBuffer, 0);
|
||||
graphics->executeCommands(std::move(classifyCmd));
|
||||
mesh.updateBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// prepare indirect pass
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(ALLOCATE_BUFFER, 0, mesh.classificationBuffer);
|
||||
set->updateBuffer(INDIRECT_DISPATCH_BUFFER, 0, indirectBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand prepareIndirectCmd = graphics->createComputeCommand("PrepareIndirect");
|
||||
prepareIndirectCmd->bindPipeline(prepareIndirect);
|
||||
prepareIndirectCmd->bindDescriptor(set);
|
||||
prepareIndirectCmd->dispatch(2, 1, 1);
|
||||
graphics->executeCommands(std::move(prepareIndirectCmd));
|
||||
indirectBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// split pass
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryCB);
|
||||
set->updateBuffer(UPDATE_CB, 0, updateCB);
|
||||
|
||||
set->updateBuffer(CLASSIFICATION_BUFFER, 0, mesh.classificationBuffer);
|
||||
set->updateBuffer(HEAP_ID_BUFFER, 0, mesh.heapIDBuffer);
|
||||
set->updateBuffer(BISECTOR_DATA_BUFFER, 0, mesh.updateBuffer);
|
||||
set->updateBuffer(NEIGHBOURS_BUFFER, 0, currentNeighborsBuffer);
|
||||
set->updateBuffer(MEMORY_BUFFER, 0, memoryBuffer);
|
||||
set->updateBuffer(ALLOCATE_BUFFER, 0, mesh.allocateBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand splitCmd = graphics->createComputeCommand("Split");
|
||||
splitCmd->bindPipeline(split);
|
||||
splitCmd->bindDescriptor({viewParamsSet, set});
|
||||
splitCmd->dispatchIndirect(indirectBuffer, 0);
|
||||
graphics->executeCommands(std::move(splitCmd));
|
||||
mesh.updateBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// prepare indirect pass
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(ALLOCATE_BUFFER, 0, mesh.allocateBuffer);
|
||||
set->updateBuffer(INDIRECT_DISPATCH_BUFFER, 0, indirectBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand prepareIndirectCmd = graphics->createComputeCommand("PrepareIndirect");
|
||||
prepareIndirectCmd->bindPipeline(prepareIndirect);
|
||||
prepareIndirectCmd->bindDescriptor(set);
|
||||
prepareIndirectCmd->dispatch(1, 1, 1);
|
||||
graphics->executeCommands(std::move(prepareIndirectCmd));
|
||||
indirectBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// Allocate Pass
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryCB);
|
||||
set->updateBuffer(UPDATE_CB, 0, updateCB);
|
||||
|
||||
set->updateBuffer(CBT_BUFFER0, 0, mesh.gpuCBT.bufferArray[0]);
|
||||
set->updateBuffer(CBT_BUFFER1, 0, mesh.gpuCBT.bufferArray[1]);
|
||||
set->updateBuffer(ALLOCATE_BUFFER, 0, mesh.allocateBuffer);
|
||||
set->updateBuffer(BISECTOR_DATA_BUFFER, 0, mesh.updateBuffer);
|
||||
set->updateBuffer(MEMORY_BUFFER, 0, memoryBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand allocateCmd = graphics->createComputeCommand("Allocate");
|
||||
allocateCmd->bindPipeline(allocate);
|
||||
allocateCmd->bindDescriptor({viewParamsSet, set});
|
||||
allocateCmd->dispatchIndirect(indirectBuffer, 0);
|
||||
graphics->executeCommands(std::move(allocateCmd));
|
||||
mesh.updateBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// copy
|
||||
currentNeighborsBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_TRANSFER_READ_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
graphics->copyBuffer(currentNeighborsBuffer, nextNeighborsBuffer);
|
||||
nextNeighborsBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
|
||||
// bisect
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryCB);
|
||||
set->updateBuffer(UPDATE_CB, 0, updateCB);
|
||||
|
||||
set->updateBuffer(CBT_BUFFER0, 0, mesh.gpuCBT.bufferArray[0]);
|
||||
set->updateBuffer(CBT_BUFFER1, 0, mesh.gpuCBT.bufferArray[1]);
|
||||
set->updateBuffer(ALLOCATE_BUFFER, 0, mesh.allocateBuffer);
|
||||
set->updateBuffer(HEAP_ID_BUFFER, 0, mesh.heapIDBuffer);
|
||||
set->updateBuffer(BISECTOR_DATA_BUFFER, 0, mesh.updateBuffer);
|
||||
set->updateBuffer(NEIGHBOURS_BUFFER, 0, currentNeighborsBuffer);
|
||||
set->updateBuffer(NEIGHBOURS_OUTPUT_BUFFER, 0, nextNeighborsBuffer);
|
||||
set->updateBuffer(PROPAGATE_BUFFER, 0, mesh.propagateBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand bisectCmd = graphics->createComputeCommand("Bisect");
|
||||
bisectCmd->bindPipeline(bisect);
|
||||
bisectCmd->bindDescriptor({viewParamsSet, set});
|
||||
bisectCmd->dispatchIndirect(indirectBuffer, 0);
|
||||
graphics->executeCommands(std::move(bisectCmd));
|
||||
nextNeighborsBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// Prepare indirect pass
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(ALLOCATE_BUFFER, 0, mesh.propagateBuffer);
|
||||
set->updateBuffer(INDIRECT_DISPATCH_BUFFER, 0, indirectBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand prepareIndirectCmd = graphics->createComputeCommand("PrepareIndirectPropagateBisect");
|
||||
prepareIndirectCmd->bindPipeline(prepareIndirect);
|
||||
prepareIndirectCmd->bindDescriptor(set);
|
||||
prepareIndirectCmd->dispatch(1, 1, 1);
|
||||
graphics->executeCommands(std::move(prepareIndirectCmd));
|
||||
indirectBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// propagate split pass
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryCB);
|
||||
set->updateBuffer(UPDATE_CB, 0, updateCB);
|
||||
|
||||
set->updateBuffer(PROPAGATE_BUFFER, 0, mesh.propagateBuffer);
|
||||
set->updateBuffer(BISECTOR_DATA_BUFFER, 0, mesh.updateBuffer);
|
||||
set->updateBuffer(NEIGHBOURS_BUFFER, 0, nextNeighborsBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand propagateBisectCmd = graphics->createComputeCommand("PropagateBisect");
|
||||
propagateBisectCmd->bindPipeline(propagateBisect);
|
||||
propagateBisectCmd->bindDescriptor({viewParamsSet, set});
|
||||
propagateBisectCmd->dispatchIndirect(indirectBuffer, 0);
|
||||
graphics->executeCommands(std::move(propagateBisectCmd));
|
||||
mesh.updateBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// prepare simplify
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryCB);
|
||||
set->updateBuffer(UPDATE_CB, 0, updateCB);
|
||||
|
||||
set->updateBuffer(CLASSIFICATION_BUFFER, 0, mesh.classificationBuffer);
|
||||
set->updateBuffer(HEAP_ID_BUFFER, 0, mesh.heapIDBuffer);
|
||||
set->updateBuffer(BISECTOR_DATA_BUFFER, 0, mesh.updateBuffer);
|
||||
set->updateBuffer(NEIGHBOURS_BUFFER, 0, nextNeighborsBuffer);
|
||||
set->updateBuffer(SIMPLIFICATION_BUFFER, 0, mesh.simplificationBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand prepareSimplifyCmd = graphics->createComputeCommand("PrepareSimplify");
|
||||
prepareSimplifyCmd->bindPipeline(prepareSimplify);
|
||||
prepareSimplifyCmd->bindDescriptor({viewParamsSet, set});
|
||||
prepareSimplifyCmd->dispatchIndirect(indirectBuffer, 0);
|
||||
graphics->executeCommands(std::move(prepareSimplifyCmd));
|
||||
mesh.simplificationBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// Prepare Indirect Simplify
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(ALLOCATE_BUFFER, 0, mesh.simplificationBuffer);
|
||||
set->updateBuffer(INDIRECT_DISPATCH_BUFFER, 0, indirectBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand prepareIndirectCmd = graphics->createComputeCommand("PrepareIndirectSimplify");
|
||||
prepareIndirectCmd->bindPipeline(prepareIndirect);
|
||||
prepareIndirectCmd->bindDescriptor(set);
|
||||
prepareIndirectCmd->dispatch(1, 1, 1);
|
||||
graphics->executeCommands(std::move(prepareIndirectCmd));
|
||||
indirectBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// Simplify Pass
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryCB);
|
||||
set->updateBuffer(UPDATE_CB, 0, updateCB);
|
||||
|
||||
set->updateBuffer(SIMPLIFICATION_BUFFER, 0, mesh.simplificationBuffer);
|
||||
set->updateBuffer(BISECTOR_DATA_BUFFER, 0, mesh.updateBuffer);
|
||||
set->updateBuffer(NEIGHBOURS_BUFFER, 0, nextNeighborsBuffer);
|
||||
set->updateBuffer(HEAP_ID_BUFFER, 0, mesh.heapIDBuffer);
|
||||
set->updateBuffer(CBT_BUFFER0, 0, mesh.gpuCBT.bufferArray[0]);
|
||||
set->updateBuffer(CBT_BUFFER1, 0, mesh.gpuCBT.bufferArray[1]);
|
||||
set->updateBuffer(PROPAGATE_BUFFER, 0, mesh.propagateBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand simplifyCmd = graphics->createComputeCommand("simplify");
|
||||
simplifyCmd->bindPipeline(simplify);
|
||||
simplifyCmd->bindDescriptor({viewParamsSet, set});
|
||||
simplifyCmd->dispatchIndirect(indirectBuffer, 0);
|
||||
graphics->executeCommands(std::move(simplifyCmd));
|
||||
nextNeighborsBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// Prepare Indirect Propagate Simplify
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(ALLOCATE_BUFFER, 0, mesh.propagateBuffer);
|
||||
set->updateBuffer(INDIRECT_DISPATCH_BUFFER, 0, indirectBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand prepareIndirectCmd = graphics->createComputeCommand("PrepareIndirectPropagateSimplify");
|
||||
prepareIndirectCmd->bindPipeline(prepareIndirect);
|
||||
prepareIndirectCmd->bindDescriptor({viewParamsSet, set});
|
||||
prepareIndirectCmd->dispatch(2, 1, 1);
|
||||
graphics->executeCommands(std::move(prepareIndirectCmd));
|
||||
indirectBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// Propagate Simplify Pass
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryCB);
|
||||
set->updateBuffer(UPDATE_CB, 0, updateCB);
|
||||
|
||||
set->updateBuffer(SIMPLIFICATION_BUFFER, 0, mesh.simplificationBuffer);
|
||||
set->updateBuffer(BISECTOR_DATA_BUFFER, 0, mesh.updateBuffer);
|
||||
set->updateBuffer(NEIGHBOURS_BUFFER, 0, nextNeighborsBuffer);
|
||||
set->updateBuffer(HEAP_ID_BUFFER, 0, mesh.heapIDBuffer);
|
||||
set->updateBuffer(CBT_BUFFER0, 0, mesh.gpuCBT.bufferArray[0]);
|
||||
set->updateBuffer(CBT_BUFFER1, 0, mesh.gpuCBT.bufferArray[1]);
|
||||
set->updateBuffer(PROPAGATE_BUFFER, 0, mesh.propagateBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand simplifyCmd = graphics->createComputeCommand("simplify");
|
||||
simplifyCmd->bindPipeline(simplify);
|
||||
simplifyCmd->bindDescriptor({viewParamsSet, set});
|
||||
simplifyCmd->dispatchIndirect(indirectBuffer, 0);
|
||||
graphics->executeCommands(std::move(simplifyCmd));
|
||||
nextNeighborsBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
// Update Tree
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(CBT_BUFFER0, 0, mesh.gpuCBT.bufferArray[0]);
|
||||
set->updateBuffer(CBT_BUFFER1, 0, mesh.gpuCBT.bufferArray[1]);
|
||||
set->writeChanges();
|
||||
|
||||
Gfx::OComputeCommand reducePrePassCmd = graphics->createComputeCommand("ReducePrepass");
|
||||
reducePrePassCmd->bindPipeline(reducePrePass);
|
||||
reducePrePassCmd->bindDescriptor(set);
|
||||
reducePrePassCmd->dispatch(mesh.gpuCBT.lastLevelSize / (4 * WORKGROUP_SIZE), 1, 1);
|
||||
graphics->executeCommands(std::move(reducePrePassCmd));
|
||||
mesh.gpuCBT.bufferArray[0]->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
|
||||
Gfx::OComputeCommand reduceFirstPassCmd = graphics->createComputeCommand("ReduceFirstPass");
|
||||
reduceFirstPassCmd->bindPipeline(reduceFirstPass);
|
||||
reduceFirstPassCmd->bindDescriptor(set);
|
||||
reduceFirstPassCmd->dispatch(8, 1, 1);
|
||||
graphics->executeCommands(std::move(reduceFirstPassCmd));
|
||||
mesh.gpuCBT.bufferArray[0]->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
|
||||
Gfx::OComputeCommand reduceSecondPassCmd = graphics->createComputeCommand("ReduceSecondPass");
|
||||
reduceSecondPassCmd->bindPipeline(reduceSecondPass);
|
||||
reduceSecondPassCmd->bindDescriptor(set);
|
||||
reduceSecondPassCmd->dispatch(1, 1, 1);
|
||||
graphics->executeCommands(std::move(reduceSecondPassCmd));
|
||||
mesh.gpuCBT.bufferArray[0]->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
mesh.currentNeighborsBufferIdx = nextNeighborsBufferIdx;
|
||||
|
||||
prepareIndirection(mesh, geometryCB);
|
||||
}
|
||||
|
||||
void MeshUpdater::validation(const CBTMesh& mesh, Gfx::PUniformBuffer geometryCB) {
|
||||
uint32 numGroups = (mesh.totalNumElements + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE;
|
||||
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryCB);
|
||||
|
||||
set->updateBuffer(HEAP_ID_BUFFER, 0, mesh.heapIDBuffer);
|
||||
set->updateBuffer(BISECTOR_DATA_BUFFER, 0, mesh.updateBuffer);
|
||||
set->updateBuffer(NEIGHBOURS_BUFFER, 0, mesh.neighborsBuffers[mesh.currentNeighborsBufferIdx]);
|
||||
set->updateBuffer(VALIDATION_BUFFER, 0, validationBuffer);
|
||||
set->writeChanges();
|
||||
|
||||
Gfx::OComputeCommand validateCmd = graphics->createComputeCommand("Validate");
|
||||
validateCmd->bindPipeline(validate);
|
||||
validateCmd->bindDescriptor(set);
|
||||
validateCmd->dispatch(numGroups, 1, 1);
|
||||
graphics->executeCommands(std::move(validateCmd));
|
||||
validationBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_TRANSFER_READ_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT);
|
||||
graphics->copyBuffer(validationBuffer, validationBufferRB);
|
||||
}
|
||||
|
||||
void MeshUpdater::resetBuffers(const CBTMesh& mesh) {
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(CBT_BUFFER0, 0, mesh.gpuCBT.bufferArray[0]);
|
||||
set->updateBuffer(CBT_BUFFER1, 0, mesh.gpuCBT.bufferArray[1]);
|
||||
set->updateBuffer(MEMORY_BUFFER, 0, memoryBuffer);
|
||||
set->updateBuffer(CLASSIFICATION_BUFFER, 0, mesh.classificationBuffer);
|
||||
set->updateBuffer(ALLOCATE_BUFFER, 0, mesh.allocateBuffer);
|
||||
set->updateBuffer(INDIRECT_DRAW_BUFFER, 0, mesh.indirectDrawBuffer);
|
||||
set->updateBuffer(SIMPLIFICATION_BUFFER, 0, mesh.simplificationBuffer);
|
||||
set->updateBuffer(PROPAGATE_BUFFER, 0, mesh.propagateBuffer);
|
||||
set->writeChanges();
|
||||
|
||||
Gfx::OComputeCommand resetCmd = graphics->createComputeCommand("Reset");
|
||||
resetCmd->bindPipeline(reset);
|
||||
resetCmd->bindDescriptor(set);
|
||||
resetCmd->dispatch(1, 1, 1);
|
||||
graphics->executeCommands(std::move(resetCmd));
|
||||
memoryBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
|
||||
void MeshUpdater::prepareIndirection(CBTMesh& mesh, Gfx::PUniformBuffer geometryCB) {
|
||||
uint32 numGroups = (mesh.totalNumElements + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE;
|
||||
|
||||
// Bitsector indexation
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryCB);
|
||||
set->updateBuffer(HEAP_ID_BUFFER, 0, mesh.heapIDBuffer);
|
||||
set->updateBuffer(INDIRECT_DRAW_BUFFER, 0, mesh.indirectDrawBuffer);
|
||||
set->updateBuffer(BISECTOR_INDICES, 0, mesh.indexedBisectorBuffer);
|
||||
set->updateBuffer(BISECTOR_DATA_BUFFER, 0, mesh.updateBuffer);
|
||||
set->updateBuffer(NEIGHBOURS_BUFFER, 0, mesh.neighborsBuffers[mesh.currentNeighborsBufferIdx]);
|
||||
set->updateBuffer(VISIBLE_BISECTOR_INDICES, 0, mesh.visibleIndexedBisectorBuffer);
|
||||
set->updateBuffer(MODIFIED_BISECTOR_INDICES, 0, mesh.modifiedIndexedBisectorBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand bisectorIndexationCmd = graphics->createComputeCommand("BisectorIndexation");
|
||||
bisectorIndexationCmd->bindPipeline(bisectorIndexation);
|
||||
bisectorIndexationCmd->bindDescriptor(set);
|
||||
bisectorIndexationCmd->dispatch(numGroups, 1, 1);
|
||||
graphics->executeCommands(std::move(bisectorIndexationCmd));
|
||||
}
|
||||
mesh.indirectDrawBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
// Prepare bisector indirect dispatch
|
||||
{
|
||||
Gfx::PDescriptorSet set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(INDIRECT_DRAW_BUFFER, 0, mesh.indirectDrawBuffer);
|
||||
set->updateBuffer(INDIRECT_DISPATCH_BUFFER, 0, mesh.indirectDispatchBuffer);
|
||||
set->writeChanges();
|
||||
|
||||
Gfx::OComputeCommand prepareBisectorIndirectCmd = graphics->createComputeCommand("PrepareBisectorIndirect");
|
||||
prepareBisectorIndirectCmd->bindPipeline(prepareBisectorIndirect);
|
||||
prepareBisectorIndirectCmd->bindDescriptor(set);
|
||||
prepareBisectorIndirectCmd->dispatch(1, 1, 1);
|
||||
graphics->executeCommands(std::move(prepareBisectorIndirectCmd));
|
||||
mesh.indirectDispatchBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
bool MeshUpdater::checkIfValid() { return true; }
|
||||
|
||||
void MeshUpdater::queryOccupancy(const CBTMesh& mesh) {}
|
||||
|
||||
uint32 MeshUpdater::getOccupancy() { return 0; }
|
||||
@@ -0,0 +1,505 @@
|
||||
#pragma once
|
||||
#include "Containers/Array.h"
|
||||
#include "Graphics/RenderPass/RenderPass.h"
|
||||
#include "MinimalEngine.h"
|
||||
#include <bit>
|
||||
|
||||
namespace Seele {
|
||||
constexpr auto GEOMETRY_CB = 0;
|
||||
constexpr auto UPDATE_CB = 1;
|
||||
constexpr auto CURRENT_VERTEX_BUFFER = 2;
|
||||
constexpr auto INDEXED_BISECTOR_BUFFER = 3;
|
||||
constexpr auto INDIRECT_DRAW_BUFFER = 4;
|
||||
constexpr auto HEAP_ID_BUFFER = 5;
|
||||
constexpr auto BISECTOR_DATA_BUFFER = 6;
|
||||
constexpr auto CLASSIFICATION_BUFFER = 7;
|
||||
constexpr auto ALLOCATE_BUFFER = 8;
|
||||
constexpr auto INDIRECT_DISPATCH_BUFFER = 9;
|
||||
constexpr auto NEIGHBOURS_BUFFER = 10;
|
||||
constexpr auto NEIGHBOURS_OUTPUT_BUFFER = 11;
|
||||
constexpr auto MEMORY_BUFFER = 12;
|
||||
constexpr auto CBT_BUFFER0 = 13;
|
||||
constexpr auto CBT_BUFFER1 = 14;
|
||||
constexpr auto PROPAGATE_BUFFER = 15;
|
||||
constexpr auto SIMPLIFICATION_BUFFER = 16;
|
||||
constexpr auto VALIDATION_BUFFER = 17;
|
||||
constexpr auto BISECTOR_INDICES = 18;
|
||||
constexpr auto VISIBLE_BISECTOR_INDICES = 19;
|
||||
constexpr auto MODIFIED_BISECTOR_INDICES = 20;
|
||||
constexpr auto LEB_POSITION_BUFFER = 21;
|
||||
constexpr auto LEB_MATRIX_CACHE = 22;
|
||||
|
||||
constexpr uint64 WORKGROUP_SIZE = 64;
|
||||
template <size_t Power> class CBT {
|
||||
private:
|
||||
struct OCBTTree {
|
||||
uint64 numElements = 0;
|
||||
uint64 treeSizeBits = 0;
|
||||
uint64 numSlots = 0;
|
||||
uint64 bitFieldNumSlots = 0;
|
||||
uint64 lastLevelSize = 0;
|
||||
uint64 lastLevel = 0;
|
||||
uint64 firstVirtualLevel = 0;
|
||||
uint64 leafLevel = 0;
|
||||
StaticArray<uint32, Power> depthOffset;
|
||||
StaticArray<uint64, Power> bitMask;
|
||||
StaticArray<uint32, Power> bitCount;
|
||||
};
|
||||
OCBTTree tree;
|
||||
constexpr static OCBTTree generateVirtualLevel(OCBTTree tree, uint64 index, uint64 bits) {
|
||||
tree.depthOffset[index] = 0;
|
||||
tree.bitCount[index] = bits;
|
||||
uint64 bitmask = 0;
|
||||
for (uint32 i = 0; i < bits; ++i) {
|
||||
bitmask |= 1ull << i;
|
||||
}
|
||||
tree.bitMask[index] = bitmask;
|
||||
if (bits == 1) {
|
||||
tree.numSlots = tree.treeSizeBits / 32;
|
||||
tree.bitFieldNumSlots = tree.numElements / 64;
|
||||
return tree;
|
||||
}
|
||||
return generateVirtualLevel(tree, index++, bits / 2);
|
||||
}
|
||||
constexpr static OCBTTree generateLevel(OCBTTree tree, uint64 remaining, uint64 index, uint64 levelElements, uint64 levelDimensions) {
|
||||
if (remaining == 7) {
|
||||
tree.depthOffset[index] = tree.treeSizeBits;
|
||||
tree.bitMask[index] = (1ull << 8) - 1;
|
||||
tree.bitCount[index] = 8;
|
||||
tree.treeSizeBits += levelDimensions * 8;
|
||||
tree.lastLevelSize = levelDimensions;
|
||||
tree.firstVirtualLevel = std::bit_width(levelDimensions);
|
||||
tree.lastLevel = tree.firstVirtualLevel - 1;
|
||||
return generateVirtualLevel(tree, index++, 64);
|
||||
}
|
||||
uint32 levelBits;
|
||||
if (levelDimensions < 128) {
|
||||
levelBits = 32;
|
||||
} else {
|
||||
levelBits = 16;
|
||||
}
|
||||
tree.depthOffset[index] = tree.treeSizeBits;
|
||||
tree.bitMask[index] = (1ull << levelBits) - 1;
|
||||
tree.bitCount[index] = levelBits;
|
||||
tree.treeSizeBits += levelDimensions * levelBits;
|
||||
return generateLevel(tree, --remaining, index++, levelElements / 2, levelDimensions * 2);
|
||||
}
|
||||
constexpr static OCBTTree createTree(uint64 power) {
|
||||
uint64 numElements = (1ull << (power - 1));
|
||||
return generateLevel(
|
||||
CBT::OCBTTree{
|
||||
.numElements = numElements,
|
||||
.leafLevel = power - 1,
|
||||
},
|
||||
power - 1, 0, numElements, 1);
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr CBT() : tree(createTree(Power)) {
|
||||
rawMemory = new uint32[tree.numSlots + tree.numElements / 32];
|
||||
packedHeap = rawMemory;
|
||||
bitfield = (uint64*)(rawMemory + tree.numSlots);
|
||||
clear();
|
||||
}
|
||||
~CBT() {}
|
||||
|
||||
uint32 numElements() { return tree.numElements; }
|
||||
|
||||
uint32 lastLevelSize() { return tree.lastLevelSize; }
|
||||
|
||||
uint32 maxDepth() { return Power; }
|
||||
|
||||
uint32 numInternalBuffers() { return 2; }
|
||||
|
||||
char* rawBuffer(uint32 bufferIdx = 0) { return bufferIdx == 0 ? (char*)packedHeap : (char*)bitfield; }
|
||||
const char* rawBuffer(uint32 bufferIdx = 0) const { return bufferIdx == 0 ? (const char*)packedHeap : (const char*)bitfield; }
|
||||
|
||||
uint32 bufferSize(uint32 bufferIdx = 0) const { return bufferIdx == 0 ? treeMemoryFootprint() : bitFieldMemoryFootprint(); }
|
||||
uint32 elementSize(uint32 bufferIdx) const { return bufferIdx == 0 ? sizeof(uint32) : sizeof(uint64); }
|
||||
|
||||
uint32 memoryFootPrint() const { return treeMemoryFootprint() + bitFieldMemoryFootprint(); }
|
||||
uint32 treeMemoryFootprint() const { return tree.numSlots * sizeof(uint32); }
|
||||
uint32 bitFieldMemoryFootprint() const { return (tree.numElements / 64) * sizeof(uint64); }
|
||||
|
||||
void setBit(uint32 bitID, bool state) {
|
||||
// Coordinates of the bit
|
||||
uint32_t slot = bitID / 64;
|
||||
uint32_t local_id = bitID % 64;
|
||||
|
||||
if (state)
|
||||
bitfield[slot] |= 1ull << local_id;
|
||||
else
|
||||
bitfield[slot] &= ~(1ull << local_id);
|
||||
}
|
||||
uint32 getBit(uint32 bitID) const {
|
||||
uint32_t slot = bitID / 64;
|
||||
uint32_t local_id = bitID % 64;
|
||||
return (bitfield[slot] & (1ull << local_id)) >> local_id;
|
||||
}
|
||||
|
||||
uint32 bitcount() const { return packedHeap[0]; }
|
||||
uint32 bitCount(uint32 depth, uint32 element) { return getHeapElement((1 << depth) + element); }
|
||||
|
||||
uint32 decodeBit(uint32 handle) const {
|
||||
uint32_t currentDepth = 0;
|
||||
uint32_t heapElementID = 1u;
|
||||
for (currentDepth = 0; currentDepth < tree.firstVirtualLevel; ++currentDepth) {
|
||||
// Read the left element
|
||||
uint32_t heapValue = getHeapElement(2u * heapElementID);
|
||||
|
||||
// Does it fall in the right or left subtree?
|
||||
uint32_t b = handle < heapValue ? 0u : 1u;
|
||||
|
||||
// Pick a subtree
|
||||
heapElementID = 2u * heapElementID + b;
|
||||
|
||||
// Move the iterator to exclude the right subtree if required
|
||||
handle -= heapValue * b;
|
||||
}
|
||||
|
||||
// Align with the internal depth
|
||||
currentDepth++;
|
||||
|
||||
// Ok we have our subtree, now we need to pick the right bit
|
||||
uint64_t heapValue = bitfield[heapElementID - tree.lastLevel * 2];
|
||||
|
||||
for (; currentDepth < (tree.leafLevel + 1); ++currentDepth) {
|
||||
// Figure out the location of the first bit of this element
|
||||
uint32_t real_heap_id = 2 * heapElementID - 1;
|
||||
uint32_t level_first_element = (1 << currentDepth) - 1;
|
||||
uint32_t id_in_level = real_heap_id - level_first_element;
|
||||
uint32_t first_bit = tree.depthOffset[currentDepth] + tree.bitCount[currentDepth] * id_in_level;
|
||||
uint32_t local_id = first_bit % 64;
|
||||
uint64_t target_bits = (heapValue >> local_id) & tree.bitMask[currentDepth];
|
||||
uint32_t heapValue = std::popcount(target_bits);
|
||||
|
||||
// Does it fall in the right or left subtree?
|
||||
uint32_t b = handle < heapValue ? 0u : 1u;
|
||||
|
||||
// Pick a subtree
|
||||
heapElementID = 2u * heapElementID + b;
|
||||
|
||||
// Move the iterator to exclude the right subtree if required
|
||||
handle -= heapValue * b;
|
||||
}
|
||||
return (heapElementID ^ tree.numElements);
|
||||
}
|
||||
uint32 decodeBitComplement(uint32 handle) const {
|
||||
uint32_t heapElementID = 1u;
|
||||
uint32_t c = tree.numElements / 2u;
|
||||
uint32_t currentDepth = 0;
|
||||
|
||||
for (currentDepth = 0; currentDepth < tree.firstVirtualLevel; ++currentDepth) {
|
||||
uint32_t heapValue = c - getHeapElement(2u * heapElementID);
|
||||
uint32_t b = handle < heapValue ? 0u : 1u;
|
||||
|
||||
heapElementID = 2u * heapElementID + b;
|
||||
handle -= heapValue * b;
|
||||
c /= 2u;
|
||||
}
|
||||
|
||||
// Align with the internal depth
|
||||
currentDepth++;
|
||||
|
||||
// Ok we have our subtree, now we need to pick the right bit
|
||||
uint64_t heapValue = bitfield[heapElementID - tree.lastLevelSize * 2];
|
||||
|
||||
for (; currentDepth < (tree.leafLevel + 1); ++currentDepth) {
|
||||
// Figure out the location of the first bit of this element
|
||||
uint32_t real_heap_id = 2 * heapElementID - 1;
|
||||
uint32_t level_first_element = (1 << currentDepth) - 1;
|
||||
uint32_t id_in_level = real_heap_id - level_first_element;
|
||||
uint32_t first_bit = tree.depthOffset[currentDepth] + tree.bitCount[currentDepth] * id_in_level;
|
||||
uint32_t local_id = first_bit % 64;
|
||||
uint64_t target_bits = (heapValue >> local_id) & tree.bitMask[currentDepth];
|
||||
uint32_t heapValue = c - countbits(target_bits);
|
||||
|
||||
uint32_t b = handle < heapValue ? 0u : 1u;
|
||||
|
||||
heapElementID = 2u * heapElementID + b;
|
||||
handle -= heapValue * b;
|
||||
c /= 2u;
|
||||
}
|
||||
|
||||
return (heapElementID ^ tree.numElements);
|
||||
}
|
||||
|
||||
uint32 getHeapElement(uint32 id) const {
|
||||
// Figure out the location of the first bit of this element
|
||||
uint32_t real_heap_id = id - 1;
|
||||
uint32_t depth = uint32_t(log2(real_heap_id + 1));
|
||||
uint32_t level_first_element = (1 << depth) - 1;
|
||||
uint32_t id_in_level = real_heap_id - level_first_element;
|
||||
uint32_t first_bit = tree.depthOffset[depth] + tree.bitCount[depth] * id_in_level;
|
||||
if (depth < tree.firstVirtualLevel) {
|
||||
uint32_t slot = first_bit / 32;
|
||||
uint32_t local_id = first_bit % 32;
|
||||
uint32_t target_bits = (packedHeap[slot] >> local_id) & tree.bitMask[depth];
|
||||
return (packedHeap[slot] >> local_id) & tree.bitMask[depth];
|
||||
} else {
|
||||
uint32_t slot = first_bit / 64;
|
||||
uint32_t local_id = first_bit % 64;
|
||||
uint64_t target_bits = (bitfield[slot] >> local_id) & tree.bitMask[depth];
|
||||
return std::popcount(target_bits);
|
||||
}
|
||||
}
|
||||
uint32 setHeapElement(uint32 id, uint32 value) {
|
||||
// Figure out the location of the first bit of this element
|
||||
uint32_t real_heap_id = id - 1;
|
||||
uint32_t depth = uint32_t(log2(real_heap_id + 1));
|
||||
uint32_t level_first_element = (1 << depth) - 1;
|
||||
uint32_t id_in_level = real_heap_id - level_first_element;
|
||||
|
||||
// If this is the tree representation
|
||||
if (depth < tree.firstVirtualLevel) {
|
||||
// Find the slot and the local first bit
|
||||
uint32_t first_bit = tree.depthOffset[depth] + tree.bitCount[depth] * id_in_level;
|
||||
uint32_t slot = first_bit / 32;
|
||||
uint32_t local_id = first_bit % 32;
|
||||
|
||||
// Extract the relevant bits
|
||||
uint32_t& target = packedHeap[slot];
|
||||
target &= ~(tree.bitMask[depth] << (local_id));
|
||||
target |= (tree.bitMask[depth] & value) << (local_id);
|
||||
}
|
||||
// Should be avoided, but is supported
|
||||
else if (depth == tree.leafLevel) {
|
||||
setBit(id_in_level, value);
|
||||
}
|
||||
// Doesn't make sense
|
||||
else {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void reduce() {
|
||||
// First reduce the last level using countbits
|
||||
for (uint32_t threadID = 0; threadID < (tree.lastLevelSize / 4); ++threadID) {
|
||||
// Initialize the packed sum
|
||||
uint32_t packedSum = 0;
|
||||
|
||||
// Loop through the 2 pairs to process
|
||||
for (uint32_t pairIdx = 0; pairIdx < 4; ++pairIdx) {
|
||||
// First element of the pair
|
||||
uint32_t elementC = std::popcount(bitfield[threadID * 8 + 2 * pairIdx]);
|
||||
|
||||
// Second element of the pair
|
||||
elementC += std::popcount(bitfield[threadID * 8 + 2 * pairIdx + 1]);
|
||||
|
||||
// Store in the right bits
|
||||
packedSum |= (elementC << pairIdx * 8);
|
||||
}
|
||||
|
||||
// Offset of the last level of the tree
|
||||
const uint32_t bufferOffset = tree.depthOffset[11] / 32;
|
||||
|
||||
// Store the result into the bitfield
|
||||
packedHeap[bufferOffset + threadID] = packedSum;
|
||||
}
|
||||
|
||||
// Then operate the reduction on the tree only (not the bitfield)
|
||||
for (uint32_t size = tree.numElements / 128u; size > 0u; size /= 2u) {
|
||||
uint32_t minHeapID = size;
|
||||
uint32_t maxHeapID = size * 2u;
|
||||
|
||||
for (uint32_t heapID = minHeapID; heapID < maxHeapID; ++heapID) {
|
||||
uint32_t value = getHeapElement(2u * heapID) + getHeapElement(2u * heapID + 1u);
|
||||
setHeapElement(heapID, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
void clear() {
|
||||
memset(packedHeap, 0, tree.numSlots * sizeof(uint32_t));
|
||||
memset(bitfield, 0, tree.bitFieldNumSlots * sizeof(uint64_t));
|
||||
}
|
||||
|
||||
private:
|
||||
uint32* rawMemory;
|
||||
uint32* packedHeap;
|
||||
uint64* bitfield;
|
||||
};
|
||||
|
||||
struct GeometryCB {
|
||||
uint32 totalNumElements;
|
||||
uint32 baseDepth;
|
||||
uint32 totalNumVertices;
|
||||
};
|
||||
struct UpdateCB {
|
||||
float triangleSize;
|
||||
uint32_t maxSubdivisionDepth;
|
||||
float fov;
|
||||
float farPlaneDistance;
|
||||
};
|
||||
struct CPUMesh {
|
||||
uint32 totalNumElements = 0;
|
||||
|
||||
uint32 minimalDepth = 0;
|
||||
|
||||
Array<uint64> heapIDArray;
|
||||
Array<UVector4> neighborsArray;
|
||||
|
||||
Array<Vector4> basePoints;
|
||||
};
|
||||
CPUMesh generateCPUMesh(uint32 cbtNumElements);
|
||||
// Pointer to an invalid neighbor or index
|
||||
constexpr uint64 INVALID_POINTER = UINT32_MAX;
|
||||
|
||||
// Possible culling state
|
||||
constexpr int64 BACK_FACE_CULLED = -3;
|
||||
constexpr int64 FRUSTUM_CULLED = -2;
|
||||
constexpr int64 TOO_SMALL = -1;
|
||||
constexpr int64 UNCHANGED_ELEMENT = 0;
|
||||
constexpr int64 BISECT_ELEMENT = 1;
|
||||
constexpr int64 SIMPLIFY_ELEMENT = 2;
|
||||
constexpr int64 MERGED_ELEMENT = 3;
|
||||
struct BisectorData {
|
||||
uint32 subdivisionPattern;
|
||||
|
||||
UVector indices;
|
||||
|
||||
uint32 problematicNeighbor;
|
||||
|
||||
uint32 bisectorState;
|
||||
|
||||
uint32 flags;
|
||||
|
||||
uint32 propagationID;
|
||||
};
|
||||
struct LebMatrixCache {
|
||||
void init(Gfx::PGraphics graphics, uint32 cacheDepth);
|
||||
void release();
|
||||
|
||||
Gfx::PShaderBuffer getLebMatrixBuffer() const { return lebMatrixBuffer; }
|
||||
|
||||
private:
|
||||
Gfx::OShaderBuffer lebMatrixBuffer;
|
||||
uint32 cacheDepth;
|
||||
};
|
||||
struct GPU_CBT {
|
||||
uint32 numElements;
|
||||
|
||||
uint32 lastLevelSize = 0;
|
||||
|
||||
uint32 bufferCount = 2;
|
||||
|
||||
Gfx::OShaderBuffer bufferArray[2];
|
||||
};
|
||||
struct BaseMesh {
|
||||
uint32 numVertices;
|
||||
|
||||
Gfx::OShaderBuffer vertexBuffer;
|
||||
|
||||
uint32 numElements;
|
||||
|
||||
Gfx::OIndexBuffer indexBuffer;
|
||||
};
|
||||
struct CBTMesh {
|
||||
uint32 totalNumElements;
|
||||
|
||||
uint32 numBaseVertices;
|
||||
|
||||
uint32 baseDepth;
|
||||
|
||||
Gfx::OShaderBuffer heapIDBuffer;
|
||||
uint32 currentNeighborsBufferIdx;
|
||||
|
||||
Gfx::OShaderBuffer neighborsBuffers[2];
|
||||
|
||||
Gfx::OShaderBuffer updateBuffer;
|
||||
Gfx::OShaderBuffer classificationBuffer;
|
||||
Gfx::OShaderBuffer simplificationBuffer;
|
||||
Gfx::OShaderBuffer allocateBuffer;
|
||||
Gfx::OShaderBuffer propagateBuffer;
|
||||
|
||||
Gfx::OShaderBuffer indirectDrawBuffer;
|
||||
Gfx::OShaderBuffer indirectDispatchBuffer;
|
||||
Gfx::OShaderBuffer indexedBisectorBuffer;
|
||||
Gfx::OShaderBuffer visibleIndexedBisectorBuffer;
|
||||
Gfx::OShaderBuffer modifiedIndexedBisectorBuffer;
|
||||
|
||||
Gfx::OShaderBuffer lebVertexBuffer;
|
||||
Gfx::OShaderBuffer currentVertexBuffer;
|
||||
Gfx::OShaderBuffer currentDisplacementBuffer;
|
||||
|
||||
GPU_CBT gpuCBT;
|
||||
};
|
||||
struct MeshUpdater {
|
||||
void init(Gfx::PGraphics gfx, Gfx::PDescriptorLayout viewParamsLayout);
|
||||
void release();
|
||||
|
||||
void evaluateLeb(const BaseMesh& baseMesh, CBTMesh& mesh, Gfx::PDescriptorSet viewParamsSet,
|
||||
Gfx::PUniformBuffer geometryBuffer, Gfx::PUniformBuffer updateBuffer, Gfx::PShaderBuffer lebMatrixCache, bool clear,
|
||||
bool complete);
|
||||
|
||||
void update(CBTMesh& mesh, Gfx::PDescriptorSet viewParamsSet, Gfx::PUniformBuffer geometryCB, Gfx::PUniformBuffer updateCB);
|
||||
|
||||
void validation(const CBTMesh& mesh, Gfx::PUniformBuffer geometryCB);
|
||||
|
||||
void resetBuffers(const CBTMesh& mesh);
|
||||
|
||||
void prepareIndirection(CBTMesh& mesh, Gfx::PUniformBuffer geometryCB);
|
||||
|
||||
bool checkIfValid();
|
||||
|
||||
void queryOccupancy(const CBTMesh& mesh);
|
||||
|
||||
uint32 getOccupancy();
|
||||
|
||||
Gfx::PGraphics graphics;
|
||||
|
||||
Gfx::ODescriptorLayout layout;
|
||||
Gfx::OPipelineLayout pipelineLayout;
|
||||
|
||||
Gfx::OShaderBuffer indirectBuffer;
|
||||
Gfx::OShaderBuffer memoryBuffer;
|
||||
Gfx::OShaderBuffer validationBuffer;
|
||||
Gfx::OShaderBuffer validationBufferRB;
|
||||
Gfx::OShaderBuffer occupancyBufferRB;
|
||||
|
||||
// Main update
|
||||
Gfx::OComputeShader resetCS;
|
||||
Gfx::PComputePipeline reset;
|
||||
Gfx::OComputeShader classifyCS;
|
||||
Gfx::PComputePipeline classify;
|
||||
Gfx::OComputeShader splitCS;
|
||||
Gfx::PComputePipeline split;
|
||||
Gfx::OComputeShader prepareIndirectCS;
|
||||
Gfx::PComputePipeline prepareIndirect;
|
||||
Gfx::OComputeShader allocateCS;
|
||||
Gfx::PComputePipeline allocate;
|
||||
Gfx::OComputeShader bisectCS;
|
||||
Gfx::PComputePipeline bisect;
|
||||
Gfx::OComputeShader propagateBisectCS;
|
||||
Gfx::PComputePipeline propagateBisect;
|
||||
Gfx::OComputeShader prepareSimplifyCS;
|
||||
Gfx::PComputePipeline prepareSimplify;
|
||||
Gfx::OComputeShader simplifyCS;
|
||||
Gfx::PComputePipeline simplify;
|
||||
Gfx::OComputeShader propagateSimplifyCS;
|
||||
Gfx::PComputePipeline propagateSimplify;
|
||||
|
||||
// Reduction
|
||||
Gfx::OComputeShader reducePrePassCS;
|
||||
Gfx::PComputePipeline reducePrePass;
|
||||
Gfx::OComputeShader reduceFirstPassCS;
|
||||
Gfx::PComputePipeline reduceFirstPass;
|
||||
Gfx::OComputeShader reduceSecondPassCS;
|
||||
Gfx::PComputePipeline reduceSecondPass;
|
||||
|
||||
// Indexation
|
||||
Gfx::OComputeShader bisectorIndexationCS;
|
||||
Gfx::PComputePipeline bisectorIndexation;
|
||||
Gfx::OComputeShader prepareBisectorIndirectCS;
|
||||
Gfx::PComputePipeline prepareBisectorIndirect;
|
||||
|
||||
// Debug
|
||||
Gfx::OComputeShader validateCS;
|
||||
Gfx::PComputePipeline validate;
|
||||
|
||||
// LEB
|
||||
Gfx::OComputeShader lebClearCS;
|
||||
Gfx::PComputePipeline lebClear;
|
||||
Gfx::OComputeShader lebEvaluateCS;
|
||||
Gfx::PComputePipeline lebEvaluate;
|
||||
};
|
||||
}; // namespace Seele
|
||||
@@ -0,0 +1,11 @@
|
||||
target_sources(Engine
|
||||
PRIVATE
|
||||
CBT.h
|
||||
CBT.cpp
|
||||
)
|
||||
|
||||
target_sources(Engine
|
||||
PUBLIC FILE_SET HEADERS
|
||||
FILES
|
||||
CBT.h
|
||||
)
|
||||
@@ -1,3 +1,5 @@
|
||||
add_subdirectory(CBT/)
|
||||
|
||||
target_sources(Engine
|
||||
PRIVATE
|
||||
Buffer.h
|
||||
|
||||
@@ -19,6 +19,7 @@ class RenderCommand {
|
||||
virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) = 0;
|
||||
virtual void pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) = 0;
|
||||
virtual void draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) = 0;
|
||||
virtual void drawIndirect(Gfx::PShaderBuffer buffer, uint64 offset, uint32 drawCount, uint32 stride) = 0;
|
||||
virtual void drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, uint32 firstInstance) = 0;
|
||||
virtual void drawMesh(uint32 groupX, uint32 groupY, uint32 groupZ) = 0;
|
||||
virtual void drawMeshIndirect(Gfx::PShaderBuffer buffer, uint64 offset, uint32 drawCount, uint32 stride) = 0;
|
||||
@@ -35,6 +36,7 @@ class ComputeCommand {
|
||||
virtual void bindDescriptor(const Array<Gfx::PDescriptorSet>& sets) = 0;
|
||||
virtual void pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) = 0;
|
||||
virtual void dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) = 0;
|
||||
virtual void dispatchIndirect(Gfx::PShaderBuffer buffer, uint32 offset) = 0;
|
||||
std::string name;
|
||||
};
|
||||
DEFINE_REF(ComputeCommand)
|
||||
|
||||
@@ -65,6 +65,7 @@ class DescriptorSet {
|
||||
virtual void writeChanges() = 0;
|
||||
virtual void updateBuffer(uint32 binding, uint32 index, Gfx::PUniformBuffer uniformBuffer) = 0;
|
||||
virtual void updateBuffer(uint32 binding, uint32 index, Gfx::PShaderBuffer shaderBuffer) = 0;
|
||||
virtual void updateBuffer(uint32 binding, uint32 index, Gfx::PVertexBuffer indexBuffer) = 0;
|
||||
virtual void updateBuffer(uint32 binding, uint32 index, Gfx::PIndexBuffer indexBuffer) = 0;
|
||||
virtual void updateSampler(uint32 binding, uint32 index, Gfx::PSampler samplerState) = 0;
|
||||
virtual void updateTexture(uint32 binding, uint32 index, Gfx::PTexture2D texture) = 0;
|
||||
|
||||
@@ -100,6 +100,8 @@ class Graphics {
|
||||
virtual void resolveTexture(PTexture source, PTexture destination) = 0;
|
||||
virtual void copyTexture(PTexture src, PTexture dst) = 0;
|
||||
|
||||
virtual void copyBuffer(Gfx::PShaderBuffer src, Gfx::PShaderBuffer dst) = 0;
|
||||
|
||||
bool supportMeshShading() const { return meshShadingEnabled; }
|
||||
|
||||
// Ray Tracing
|
||||
|
||||
@@ -98,7 +98,7 @@ struct ShaderBufferCreateInfo {
|
||||
uint64 numElements = 1;
|
||||
uint32 clearValue = 0;
|
||||
uint8 createCleared = 0;
|
||||
uint8 vertexBuffer = 0;
|
||||
Gfx::SeBufferUsageFlags usage = 0;
|
||||
std::string name = "Unnamed";
|
||||
};
|
||||
DECLARE_NAME_REF(Gfx, PipelineLayout)
|
||||
|
||||
@@ -27,7 +27,6 @@ void Seele::addDebugVertices(Array<DebugVertex> verts) { gDebugVertices.addAll(v
|
||||
|
||||
BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics, scene) {
|
||||
//waterRenderer = new WaterRenderer(graphics, scene, viewParamsLayout);
|
||||
//terrainRenderer = new TerrainRenderer(graphics, scene, viewParamsLayout);
|
||||
basePassLayout = graphics->createPipelineLayout("BasePassLayout");
|
||||
|
||||
basePassLayout->addDescriptorLayout(viewParamsLayout);
|
||||
@@ -100,7 +99,7 @@ void BasePass::beginFrame(const Component::Camera& cam) {
|
||||
transparentCulling = lightCullingLayout->allocateDescriptorSet();
|
||||
|
||||
//waterRenderer->beginFrame();
|
||||
//terrainRenderer->beginFrame();
|
||||
terrainRenderer->beginFrame(viewParamsSet);
|
||||
|
||||
// Debug vertices
|
||||
{
|
||||
@@ -249,8 +248,8 @@ void BasePass::render() {
|
||||
}
|
||||
}
|
||||
|
||||
// commands.add(waterRenderer->render(viewParamsSet));
|
||||
// commands.add(terrainRenderer->render(viewParamsSet));
|
||||
//commands.add(waterRenderer->render(viewParamsSet));
|
||||
commands.add(terrainRenderer->render(viewParamsSet));
|
||||
|
||||
// Skybox
|
||||
{
|
||||
@@ -432,6 +431,8 @@ void BasePass::publishOutputs() {
|
||||
}
|
||||
|
||||
void BasePass::createRenderPass() {
|
||||
RenderPass::beginFrame(Component::Camera());
|
||||
terrainRenderer = new TerrainRenderer(graphics, scene, viewParamsLayout, viewParamsSet);
|
||||
cullingBuffer = resources->requestBuffer("CULLINGBUFFER");
|
||||
timestamps = resources->requestTimestampQuery("TIMESTAMPS");
|
||||
|
||||
@@ -474,7 +475,7 @@ void BasePass::createRenderPass() {
|
||||
tLightGrid = resources->requestTexture("LIGHTCULLING_TLIGHTGRID");
|
||||
|
||||
//waterRenderer->setViewport(viewport, renderPass);
|
||||
//terrainRenderer->setViewport(viewport, renderPass);
|
||||
terrainRenderer->setViewport(viewport, renderPass);
|
||||
|
||||
// Debug rendering
|
||||
{
|
||||
|
||||
@@ -51,7 +51,7 @@ class BasePass : public RenderPass {
|
||||
Gfx::PShaderBuffer cullingBuffer;
|
||||
|
||||
//OWaterRenderer waterRenderer;
|
||||
//OTerrainRenderer terrainRenderer;
|
||||
OTerrainRenderer terrainRenderer;
|
||||
|
||||
// Debug rendering
|
||||
Gfx::OVertexInput debugVertexInput;
|
||||
|
||||
@@ -31,13 +31,6 @@ class LightCullingPass : public RenderPass {
|
||||
glm::uvec3 numThreads;
|
||||
uint32_t pad1;
|
||||
} dispatchParams;
|
||||
struct Plane {
|
||||
Vector n;
|
||||
float d;
|
||||
};
|
||||
struct Frustum {
|
||||
Plane planes[4];
|
||||
};
|
||||
|
||||
Gfx::OShaderBuffer frustumBuffer;
|
||||
Gfx::OUniformBuffer dispatchParamsBuffer;
|
||||
|
||||
@@ -23,13 +23,18 @@ RenderPass::RenderPass(Gfx::PGraphics graphics, PScene scene) : graphics(graphic
|
||||
RenderPass::~RenderPass() {}
|
||||
|
||||
void RenderPass::beginFrame(const Component::Camera& cam) {
|
||||
auto screenDim = Vector2(static_cast<float>(viewport->getWidth()), static_cast<float>(viewport->getHeight()));
|
||||
viewParams = {
|
||||
.viewMatrix = cam.getViewMatrix(),
|
||||
.inverseViewMatrix = glm::inverse(cam.getViewMatrix()),
|
||||
.projectionMatrix = viewport->getProjectionMatrix(),
|
||||
.inverseProjection = glm::inverse(viewport->getProjectionMatrix()),
|
||||
.cameraPosition = Vector4(cam.getCameraPosition(), 1),
|
||||
.screenDimensions = Vector2(static_cast<float>(viewport->getWidth()), static_cast<float>(viewport->getHeight())),
|
||||
.cameraPosition_WS = Vector4(cam.getCameraPosition(), 1),
|
||||
.cameraForward_WS = Vector4(cam.getCameraForward(), 1),
|
||||
.screenDimensions = screenDim,
|
||||
.invScreenDimensions = 1.0f / screenDim,
|
||||
.frameIndex = Gfx::getCurrentFrameIndex(),
|
||||
.time = static_cast<float>(Gfx::getCurrentFrameTime()),
|
||||
};
|
||||
viewParamsBuffer->rotateBuffer(sizeof(ViewParameter));
|
||||
viewParamsBuffer->updateContents(0, sizeof(ViewParameter), &viewParams);
|
||||
|
||||
@@ -27,13 +27,25 @@ class RenderPass {
|
||||
void setViewport(Gfx::PViewport _viewport);
|
||||
|
||||
protected:
|
||||
struct Plane {
|
||||
Vector n;
|
||||
float d;
|
||||
};
|
||||
struct Frustum {
|
||||
Plane planes[4];
|
||||
};
|
||||
struct ViewParameter {
|
||||
Frustum viewFrustum;
|
||||
Matrix4 viewMatrix;
|
||||
Matrix4 inverseViewMatrix;
|
||||
Matrix4 projectionMatrix;
|
||||
Matrix4 inverseProjection;
|
||||
Vector4 cameraPosition;
|
||||
Vector4 cameraPosition_WS;
|
||||
Vector4 cameraForward_WS;
|
||||
Vector2 screenDimensions;
|
||||
Vector2 invScreenDimensions;
|
||||
uint32 frameIndex;
|
||||
float time;
|
||||
} viewParams;
|
||||
PRenderGraphResources resources;
|
||||
Gfx::ODescriptorLayout viewParamsLayout;
|
||||
|
||||
@@ -2,111 +2,298 @@
|
||||
#include "Asset/AssetRegistry.h"
|
||||
#include "Component/TerrainTile.h"
|
||||
#include "Graphics/Graphics.h"
|
||||
#include "Graphics/Pipeline.h"
|
||||
#include "Graphics/Shader.h"
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
TerrainRenderer::TerrainRenderer(Gfx::PGraphics graphics, PScene scene, Gfx::PDescriptorLayout viewParamsLayout)
|
||||
TerrainRenderer::TerrainRenderer(Gfx::PGraphics graphics, PScene scene, Gfx::PDescriptorLayout viewParamsLayout,
|
||||
Gfx::PDescriptorSet viewParamsSet)
|
||||
: graphics(graphics), scene(scene) {
|
||||
struct TerrainTile {
|
||||
IVector2 offset;
|
||||
float extent;
|
||||
float height;
|
||||
};
|
||||
Array<TerrainTile> payloads;
|
||||
for (int32 y = -100; y < 100; ++y) {
|
||||
for (int32 x = -100; x < 100; ++x) {
|
||||
payloads.add(TerrainTile{
|
||||
.offset = IVector2(x, y),
|
||||
.extent = Component::TerrainTile::DIMENSIONS,
|
||||
.height = 0,
|
||||
});
|
||||
}
|
||||
meshUpdater.init(graphics, viewParamsLayout);
|
||||
lebCache.init(graphics, 5);
|
||||
CBT<21> cbt;
|
||||
CPUMesh cpuMesh = generateCPUMesh(cbt.numElements());
|
||||
plainMesh.gpuCBT.lastLevelSize = cbt.lastLevelSize();
|
||||
for (uint32 i = 0; i < 2; ++i) {
|
||||
uint32 bufferSize = cbt.bufferSize(i);
|
||||
uint32 elementSize = cbt.elementSize(i);
|
||||
plainMesh.gpuCBT.bufferArray[i] = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = bufferSize,
|
||||
.data = (uint8*)cbt.rawBuffer(i),
|
||||
},
|
||||
.name = "GPUCBT",
|
||||
});
|
||||
plainMesh.gpuCBT.bufferArray[i]->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
}
|
||||
tilesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
plainMesh.totalNumElements = cpuMesh.totalNumElements;
|
||||
plainMesh.numBaseVertices = (uint32)cpuMesh.basePoints.size();
|
||||
plainMesh.baseDepth = cpuMesh.minimalDepth;
|
||||
|
||||
plainMesh.heapIDBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(TerrainTile) * payloads.size(),
|
||||
.data = (uint8*)payloads.data(),
|
||||
.size = sizeof(uint64) * cpuMesh.totalNumElements,
|
||||
.data = (uint8*)cpuMesh.heapIDArray.data(),
|
||||
},
|
||||
.numElements = payloads.size(),
|
||||
.name = "TilesBuffer",
|
||||
.name = "HeapID",
|
||||
});
|
||||
tilesBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_TASK_SHADER_BIT_EXT);
|
||||
colorMap = AssetRegistry::findTexture("", "azeroth")->getTexture();
|
||||
displacementMap = AssetRegistry::findTexture("", "azeroth_height")->getTexture();
|
||||
plainMesh.heapIDBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
|
||||
sampler = graphics->createSampler(SamplerCreateInfo{});
|
||||
layout = graphics->createDescriptorLayout("pTerrainData");
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.binding = 0,
|
||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||
plainMesh.currentNeighborsBufferIdx = 0;
|
||||
plainMesh.neighborsBuffers[0] = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(UVector4) * cpuMesh.totalNumElements,
|
||||
.data = (uint8*)cpuMesh.neighborsArray.data(),
|
||||
},
|
||||
.name = "Neighbours0",
|
||||
});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.binding = 1,
|
||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
||||
plainMesh.neighborsBuffers[0]->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
plainMesh.neighborsBuffers[1] = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(UVector4) * cpuMesh.totalNumElements,
|
||||
},
|
||||
.name = "Neighbours1",
|
||||
});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.binding = 2,
|
||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
|
||||
plainMesh.neighborsBuffers[1]->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
|
||||
plainMesh.updateBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(BisectorData) * cpuMesh.totalNumElements,
|
||||
},
|
||||
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||
.name = "UpdateBuffer",
|
||||
});
|
||||
layout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
.binding = 3,
|
||||
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER,
|
||||
plainMesh.classificationBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32) * (2 + cpuMesh.totalNumElements * 2),
|
||||
},
|
||||
.name = "Classification",
|
||||
});
|
||||
layout->create();
|
||||
pipelineLayout = graphics->createPipelineLayout("TerrainLayout");
|
||||
pipelineLayout->addDescriptorLayout(viewParamsLayout);
|
||||
pipelineLayout->addDescriptorLayout(layout);
|
||||
ShaderCompilationInfo s{
|
||||
.name = "TerrainShaders",
|
||||
plainMesh.simplificationBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32) * (1 + cpuMesh.totalNumElements),
|
||||
},
|
||||
.name = "Simplification",
|
||||
});
|
||||
plainMesh.allocateBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32) * (1 + cpuMesh.totalNumElements),
|
||||
},
|
||||
.name = "Allocation",
|
||||
});
|
||||
plainMesh.propagateBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32) * (2 + cpuMesh.totalNumElements),
|
||||
},
|
||||
.name = "Propagate",
|
||||
});
|
||||
|
||||
plainMesh.indirectDrawBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32) * (4 * 2 + 2),
|
||||
},
|
||||
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||
.name = "IndirectDraw",
|
||||
});
|
||||
plainMesh.indirectDispatchBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32) * 3 * 3,
|
||||
},
|
||||
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||
.name = "IndirectDispatch",
|
||||
});
|
||||
plainMesh.indexedBisectorBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32) * cpuMesh.totalNumElements,
|
||||
},
|
||||
.name = "IndexedBisector",
|
||||
});
|
||||
plainMesh.visibleIndexedBisectorBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32) * cpuMesh.totalNumElements,
|
||||
},
|
||||
.name = "VisibleIndexedBisector",
|
||||
});
|
||||
plainMesh.modifiedIndexedBisectorBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32) * cpuMesh.totalNumElements,
|
||||
},
|
||||
.name = "ModifiedIndexedBisector",
|
||||
});
|
||||
|
||||
plainMesh.lebVertexBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(Vector4) * plainMesh.totalNumElements * 4,
|
||||
},
|
||||
.name = "LebVertexBuffer",
|
||||
});
|
||||
plainMesh.currentVertexBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(Vector4) * plainMesh.totalNumElements * 4,
|
||||
},
|
||||
.usage = Gfx::SE_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||
.name = "CurrentVertexBuffer",
|
||||
});
|
||||
plainMesh.currentDisplacementBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(Vector4) * plainMesh.totalNumElements * 3,
|
||||
},
|
||||
.name = "CurrentDisplacementBuffer",
|
||||
});
|
||||
uint32 numBaseVertex = (uint32)cpuMesh.basePoints.size();
|
||||
baseMesh.numVertices = numBaseVertex;
|
||||
baseMesh.numElements = numBaseVertex / 3;
|
||||
uint32 baseVertexBufferSize = sizeof(Vector4) * numBaseVertex;
|
||||
baseMesh.vertexBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = baseVertexBufferSize,
|
||||
.data = (uint8*)cpuMesh.basePoints.data(),
|
||||
},
|
||||
.name = "VertexBuffer",
|
||||
});
|
||||
baseMesh.vertexBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
uint32 indexBufferSize = cpuMesh.totalNumElements * sizeof(UVector);
|
||||
Array<uint32> indices;
|
||||
for (uint32 i = 0; i < cpuMesh.totalNumElements * 3; ++i)
|
||||
indices.add(i);
|
||||
baseMesh.indexBuffer = graphics->createIndexBuffer(IndexBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(uint32) * indices.size(),
|
||||
.data = (uint8*)indices.data(),
|
||||
},
|
||||
.indexType = Gfx::SE_INDEX_TYPE_UINT32,
|
||||
.name = "IndexBuffer",
|
||||
});
|
||||
baseMesh.indexBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
GeometryCB geometryCB = {
|
||||
.totalNumElements = plainMesh.totalNumElements,
|
||||
.baseDepth = plainMesh.baseDepth,
|
||||
.totalNumVertices = plainMesh.totalNumElements * 3,
|
||||
};
|
||||
geometryBuffer = graphics->createUniformBuffer(UniformBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(GeometryCB),
|
||||
.data = (uint8*)&geometryCB,
|
||||
},
|
||||
.name = "GeometryCB",
|
||||
});
|
||||
geometryBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_UNIFORM_READ_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
UpdateCB updateCB = {
|
||||
.triangleSize = 10.0f,
|
||||
.maxSubdivisionDepth = 63,
|
||||
.fov = 70.0f,
|
||||
.farPlaneDistance = 1000.0f,
|
||||
};
|
||||
updateBuffer = graphics->createUniformBuffer(UniformBufferCreateInfo{
|
||||
.sourceData =
|
||||
{
|
||||
.size = sizeof(UpdateCB),
|
||||
.data = (uint8*)&updateCB,
|
||||
},
|
||||
.name = "UpdateCB",
|
||||
});
|
||||
updateBuffer->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_UNIFORM_READ_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
meshUpdater.resetBuffers(plainMesh);
|
||||
meshUpdater.prepareIndirection(plainMesh, geometryBuffer);
|
||||
meshUpdater.evaluateLeb(baseMesh, plainMesh, viewParamsSet, geometryBuffer, updateBuffer, lebCache.getLebMatrixBuffer(), true, true);
|
||||
|
||||
graphics->beginShaderCompilation(ShaderCompilationInfo{
|
||||
.modules = {"TerrainPass"},
|
||||
.entryPoints =
|
||||
{
|
||||
{"taskMain", "TerrainPass"},
|
||||
{"meshMain", "TerrainPass"},
|
||||
{"fragmentMain", "TerrainPass"},
|
||||
{"vert", "TerrainPass"},
|
||||
{"frag", "TerrainPass"},
|
||||
{"deform", "TerrainPass"},
|
||||
},
|
||||
.rootSignature = pipelineLayout,
|
||||
.dumpIntermediate = false,
|
||||
};
|
||||
graphics->beginShaderCompilation(s);
|
||||
task = graphics->createTaskShader({0});
|
||||
mesh = graphics->createMeshShader({1});
|
||||
frag = graphics->createFragmentShader({2});
|
||||
pipelineLayout->create();
|
||||
.rootSignature = meshUpdater.pipelineLayout,
|
||||
});
|
||||
vert = graphics->createVertexShader({0});
|
||||
frag = graphics->createFragmentShader({1});
|
||||
deformCS = graphics->createComputeShader({2});
|
||||
deform = graphics->createComputePipeline(Gfx::ComputePipelineCreateInfo{
|
||||
.computeShader = deformCS,
|
||||
.pipelineLayout = meshUpdater.pipelineLayout,
|
||||
});
|
||||
}
|
||||
|
||||
TerrainRenderer::~TerrainRenderer() {}
|
||||
|
||||
void TerrainRenderer::beginFrame() {
|
||||
set = layout->allocateDescriptorSet();
|
||||
set->updateBuffer(0, 0, tilesBuffer);
|
||||
set->updateTexture(1, 0, displacementMap);
|
||||
set->updateTexture(2, 0, colorMap);
|
||||
set->updateSampler(3, 0, sampler);
|
||||
void TerrainRenderer::beginFrame(Gfx::PDescriptorSet viewParamsSet) {
|
||||
meshUpdater.update(plainMesh, viewParamsSet, geometryBuffer, updateBuffer);
|
||||
meshUpdater.evaluateLeb(baseMesh, plainMesh, viewParamsSet, geometryBuffer, updateBuffer, lebCache.getLebMatrixBuffer(), false, false);
|
||||
Gfx::PDescriptorSet set = meshUpdater.layout->allocateDescriptorSet();
|
||||
set->updateBuffer(GEOMETRY_CB, 0, geometryBuffer);
|
||||
set->updateBuffer(INDIRECT_DRAW_BUFFER, 0, plainMesh.indirectDrawBuffer);
|
||||
set->updateBuffer(INDEXED_BISECTOR_BUFFER, 0, plainMesh.indexedBisectorBuffer);
|
||||
set->updateBuffer(LEB_POSITION_BUFFER, 0, plainMesh.lebVertexBuffer);
|
||||
set->updateBuffer(CURRENT_VERTEX_BUFFER, 0, plainMesh.currentVertexBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::OComputeCommand command = graphics->createComputeCommand("Deform");
|
||||
command->bindPipeline(deform);
|
||||
command->bindDescriptor({viewParamsSet, set});
|
||||
command->dispatchIndirect(plainMesh.indirectDispatchBuffer, 3 * sizeof(uint32));
|
||||
graphics->executeCommands(std::move(command));
|
||||
plainMesh.currentVertexBuffer->pipelineBarrier(Gfx::SE_ACCESS_SHADER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
Gfx::SE_ACCESS_SHADER_READ_BIT, Gfx::SE_PIPELINE_STAGE_VERTEX_SHADER_BIT);
|
||||
}
|
||||
|
||||
Gfx::ORenderCommand TerrainRenderer::render(Gfx::PDescriptorSet viewParamsSet) {
|
||||
Gfx::PDescriptorSet set = meshUpdater.layout->allocateDescriptorSet();
|
||||
set->updateBuffer(CURRENT_VERTEX_BUFFER, 0, plainMesh.currentVertexBuffer);
|
||||
set->updateBuffer(INDEXED_BISECTOR_BUFFER, 0, plainMesh.indexedBisectorBuffer);
|
||||
set->writeChanges();
|
||||
Gfx::ORenderCommand command = graphics->createRenderCommand("TerrainRender");
|
||||
command->setViewport(viewport);
|
||||
command->bindPipeline(pipeline);
|
||||
command->bindDescriptor({viewParamsSet, set});
|
||||
command->drawMesh(tilesBuffer->getNumElements(), 4, 1);
|
||||
command->drawIndirect(plainMesh.indirectDrawBuffer, 0, 1, 0);
|
||||
return command;
|
||||
}
|
||||
|
||||
void TerrainRenderer::setViewport(Gfx::PViewport _viewport, Gfx::PRenderPass renderPass) {
|
||||
viewport = _viewport;
|
||||
|
||||
Gfx::MeshPipelineCreateInfo pipelineInfo = {
|
||||
.taskShader = task,
|
||||
.meshShader = mesh,
|
||||
inp = graphics->createVertexInput({});
|
||||
Gfx::LegacyPipelineCreateInfo pipelineInfo = {
|
||||
.vertexInput = inp,
|
||||
.vertexShader = vert,
|
||||
.fragmentShader = frag,
|
||||
.renderPass = renderPass,
|
||||
.pipelineLayout = pipelineLayout,
|
||||
.pipelineLayout = meshUpdater.pipelineLayout,
|
||||
.multisampleState =
|
||||
{
|
||||
.samples = viewport->getSamples(),
|
||||
@@ -128,4 +315,4 @@ void TerrainRenderer::setViewport(Gfx::PViewport _viewport, Gfx::PRenderPass ren
|
||||
},
|
||||
};
|
||||
pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
#include "RenderPass.h"
|
||||
#include "Graphics/Buffer.h"
|
||||
#include "Graphics/CBT/CBT.h"
|
||||
|
||||
namespace Seele {
|
||||
class TerrainRenderer {
|
||||
public:
|
||||
TerrainRenderer(Gfx::PGraphics graphics, PScene scene, Gfx::PDescriptorLayout viewParamsLayout);
|
||||
TerrainRenderer(Gfx::PGraphics graphics, PScene scene, Gfx::PDescriptorLayout viewParamsLayout, Gfx::PDescriptorSet viewParamsSet);
|
||||
~TerrainRenderer();
|
||||
void beginFrame();
|
||||
void beginFrame(Gfx::PDescriptorSet viewParamsSet);
|
||||
Gfx::ORenderCommand render(Gfx::PDescriptorSet viewParamsSet);
|
||||
void setViewport(Gfx::PViewport viewport, Gfx::PRenderPass renderPass);
|
||||
|
||||
@@ -18,13 +20,24 @@ class TerrainRenderer {
|
||||
Gfx::OPipelineLayout pipelineLayout;
|
||||
Gfx::OTaskShader task;
|
||||
Gfx::OMeshShader mesh;
|
||||
Gfx::OVertexInput inp;
|
||||
Gfx::OVertexShader vert;
|
||||
Gfx::OFragmentShader frag;
|
||||
Gfx::PGraphicsPipeline pipeline;
|
||||
Gfx::OComputeShader deformCS;
|
||||
Gfx::PComputePipeline deform;
|
||||
Gfx::PViewport viewport;
|
||||
Gfx::OShaderBuffer tilesBuffer;
|
||||
Gfx::PTexture2D displacementMap;
|
||||
Gfx::PTexture2D colorMap;
|
||||
Gfx::OSampler sampler;
|
||||
|
||||
Gfx::OUniformBuffer geometryBuffer;
|
||||
Gfx::OUniformBuffer updateBuffer;
|
||||
BaseMesh baseMesh;
|
||||
CBTMesh plainMesh;
|
||||
MeshUpdater meshUpdater;
|
||||
LebMatrixCache lebCache;
|
||||
};
|
||||
DEFINE_REF(TerrainRenderer);
|
||||
}
|
||||
} // namespace Seele
|
||||
@@ -149,7 +149,6 @@ void StaticMeshVertexData::updateBuffers() {
|
||||
.size = verticesAllocated * sizeof(Vector),
|
||||
.data = (uint8*)posData.data(),
|
||||
},
|
||||
.vertexBuffer = true,
|
||||
.name = "Positions",
|
||||
});
|
||||
normals = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
@@ -158,7 +157,6 @@ void StaticMeshVertexData::updateBuffers() {
|
||||
.size = verticesAllocated * sizeof(Quaternion),
|
||||
.data = (uint8*)norData.data(),
|
||||
},
|
||||
.vertexBuffer = false,
|
||||
.name = "Normals",
|
||||
});
|
||||
colors = graphics->createShaderBuffer(ShaderBufferCreateInfo{
|
||||
@@ -167,7 +165,6 @@ void StaticMeshVertexData::updateBuffers() {
|
||||
.size = verticesAllocated * sizeof(U16Vector),
|
||||
.data = (uint8*)colData.data(),
|
||||
},
|
||||
.vertexBuffer = false,
|
||||
.name = "Colors",
|
||||
});
|
||||
for (size_t i = 0; i < MAX_TEXCOORDS; ++i) {
|
||||
@@ -177,7 +174,6 @@ void StaticMeshVertexData::updateBuffers() {
|
||||
.size = verticesAllocated * sizeof(U16Vector2),
|
||||
.data = (uint8*)texData[i].data(),
|
||||
},
|
||||
.vertexBuffer = false,
|
||||
.name = "TexCoords",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
constexpr static uint64 NUM_DEFAULT_ELEMENTS = 100000;
|
||||
constexpr static uint64 NUM_DEFAULT_ELEMENTS = 36;
|
||||
uint64 VertexData::meshletCount = 0;
|
||||
|
||||
void VertexData::resetMeshData() {
|
||||
|
||||
@@ -389,8 +389,8 @@ void Buffer::pipelineBarrier(VkAccessFlags srcAccess, VkPipelineStageFlags srcSt
|
||||
|
||||
UniformBuffer::UniformBuffer(PGraphics graphics, const UniformBufferCreateInfo& createInfo)
|
||||
: Gfx::UniformBuffer(graphics->getFamilyMapping(), createInfo),
|
||||
Vulkan::Buffer(graphics, createInfo.sourceData.size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, createInfo.sourceData.owner,
|
||||
true, createInfo.name) {
|
||||
Vulkan::Buffer(graphics, createInfo.sourceData.size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, createInfo.sourceData.owner, true,
|
||||
createInfo.name) {
|
||||
if (createInfo.sourceData.size > 0 && createInfo.sourceData.data != nullptr) {
|
||||
getAlloc()->updateContents(createInfo.sourceData.offset, createInfo.sourceData.size, createInfo.sourceData.data);
|
||||
}
|
||||
@@ -416,11 +416,7 @@ void UniformBuffer::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineSt
|
||||
|
||||
ShaderBuffer::ShaderBuffer(PGraphics graphics, const ShaderBufferCreateInfo& createInfo)
|
||||
: Gfx::ShaderBuffer(graphics->getFamilyMapping(), createInfo),
|
||||
Vulkan::Buffer(graphics, createInfo.sourceData.size,
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||
(createInfo.vertexBuffer ? VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
|
||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT
|
||||
: 0),
|
||||
Vulkan::Buffer(graphics, createInfo.sourceData.size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | createInfo.usage,
|
||||
createInfo.sourceData.owner, true, createInfo.name, createInfo.createCleared, createInfo.clearValue) {
|
||||
if (createInfo.sourceData.size > 0 && createInfo.sourceData.data != nullptr) {
|
||||
getAlloc()->updateContents(createInfo.sourceData.offset, createInfo.sourceData.size, createInfo.sourceData.data);
|
||||
@@ -491,12 +487,12 @@ void VertexBuffer::executePipelineBarrier(VkAccessFlags srcAccess, VkPipelineSta
|
||||
IndexBuffer::IndexBuffer(PGraphics graphics, const IndexBufferCreateInfo& createInfo)
|
||||
: Gfx::IndexBuffer(graphics->getFamilyMapping(), createInfo),
|
||||
Vulkan::Buffer(graphics, createInfo.sourceData.size,
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR |
|
||||
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
||||
createInfo.sourceData.owner, false, createInfo.name) {
|
||||
getAlloc()->updateContents(createInfo.sourceData.offset, createInfo.sourceData.size, createInfo.sourceData.data);
|
||||
getAlloc()->pipelineBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_INDEX_READ_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | Gfx::SE_PIPELINE_STAGE_VERTEX_INPUT_BIT);
|
||||
//getAlloc()->pipelineBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_INDEX_READ_BIT,
|
||||
// Gfx::SE_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR | Gfx::SE_PIPELINE_STAGE_VERTEX_INPUT_BIT);
|
||||
}
|
||||
|
||||
IndexBuffer::~IndexBuffer() {}
|
||||
|
||||
@@ -331,6 +331,11 @@ void RenderCommand::draw(uint32 vertexCount, uint32 instanceCount, int32 firstVe
|
||||
vkCmdDraw(handle, vertexCount, instanceCount, firstVertex, firstInstance);
|
||||
}
|
||||
|
||||
void RenderCommand::drawIndirect(Gfx::PShaderBuffer buffer, uint64 offset, uint32 drawCount, uint32 stride) {
|
||||
assert(threadId == std::this_thread::get_id());
|
||||
vkCmdDrawIndirect(handle, buffer.cast<ShaderBuffer>()->getHandle(), offset, drawCount, stride);
|
||||
}
|
||||
|
||||
void RenderCommand::drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, uint32 firstInstance) {
|
||||
assert(threadId == std::this_thread::get_id());
|
||||
vkCmdDrawIndexed(handle, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance);
|
||||
@@ -470,6 +475,10 @@ void ComputeCommand::dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) {
|
||||
assert(threadId == std::this_thread::get_id());
|
||||
vkCmdDispatch(handle, threadX, threadY, threadZ);
|
||||
}
|
||||
void ComputeCommand::dispatchIndirect(Gfx::PShaderBuffer buffer, uint32 offset) {
|
||||
assert(threadId == std::this_thread::get_id());
|
||||
vkCmdDispatchIndirect(handle, buffer.cast<ShaderBuffer>()->getHandle(), offset);
|
||||
}
|
||||
|
||||
CommandPool::CommandPool(PGraphics graphics, PQueue queue) : graphics(graphics), queue(queue), queueFamilyIndex(queue->getFamilyIndex()) {
|
||||
VkCommandPoolCreateInfo info = {
|
||||
|
||||
@@ -84,6 +84,7 @@ class RenderCommand : public Gfx::RenderCommand {
|
||||
virtual void bindIndexBuffer(Gfx::PIndexBuffer indexBuffer) override;
|
||||
virtual void pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) override;
|
||||
virtual void draw(uint32 vertexCount, uint32 instanceCount, int32 firstVertex, uint32 firstInstance) override;
|
||||
virtual void drawIndirect(Gfx::PShaderBuffer buffer, uint64 offset, uint32 drawCount, uint32 stride) override;
|
||||
virtual void drawIndexed(uint32 indexCount, uint32 instanceCount, int32 firstIndex, uint32 vertexOffset, uint32 firstInstance) override;
|
||||
virtual void drawMesh(uint32 groupX, uint32 groupY, uint32 groupZ) override;
|
||||
virtual void drawMeshIndirect(Gfx::PShaderBuffer buffer, uint64 offset, uint32 drawCount, uint32 stride) override;
|
||||
@@ -118,6 +119,7 @@ class ComputeCommand : public Gfx::ComputeCommand {
|
||||
virtual void bindDescriptor(const Array<Gfx::PDescriptorSet>& sets) override;
|
||||
virtual void pushConstants(Gfx::SeShaderStageFlags stage, uint32 offset, uint32 size, const void* data) override;
|
||||
virtual void dispatch(uint32 threadX, uint32 threadY, uint32 threadZ) override;
|
||||
virtual void dispatchIndirect(Gfx::PShaderBuffer buffer, uint32 offset) override;
|
||||
|
||||
private:
|
||||
PComputePipeline pipeline;
|
||||
|
||||
@@ -220,6 +220,31 @@ void DescriptorSet::updateBuffer(uint32_t binding, uint32 index, Gfx::PShaderBuf
|
||||
boundResources[binding][index] = vulkanBuffer->getAlloc();
|
||||
}
|
||||
|
||||
void DescriptorSet::updateBuffer(uint32_t binding, uint32 index, Gfx::PVertexBuffer indexBuffer) {
|
||||
PVertexBuffer vulkanBuffer = indexBuffer.cast<VertexBuffer>();
|
||||
if (boundResources[binding][index] == vulkanBuffer->getAlloc()) {
|
||||
return;
|
||||
}
|
||||
|
||||
bufferInfos.add(VkDescriptorBufferInfo{
|
||||
.buffer = vulkanBuffer->getHandle(),
|
||||
.offset = 0,
|
||||
.range = vulkanBuffer->getSize(),
|
||||
});
|
||||
writeDescriptors.add(VkWriteDescriptorSet{
|
||||
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
||||
.pNext = nullptr,
|
||||
.dstSet = setHandle,
|
||||
.dstBinding = binding,
|
||||
.dstArrayElement = index,
|
||||
.descriptorCount = 1,
|
||||
.descriptorType = cast(layout->getBindings()[binding].descriptorType),
|
||||
.pBufferInfo = &bufferInfos.back(),
|
||||
});
|
||||
|
||||
boundResources[binding][index] = vulkanBuffer->getAlloc();
|
||||
}
|
||||
|
||||
void DescriptorSet::updateBuffer(uint32_t binding, uint32 index, Gfx::PIndexBuffer indexBuffer) {
|
||||
PIndexBuffer vulkanBuffer = indexBuffer.cast<IndexBuffer>();
|
||||
if (boundResources[binding][index] == vulkanBuffer->getAlloc()) {
|
||||
|
||||
@@ -50,6 +50,7 @@ class DescriptorSet : public Gfx::DescriptorSet, public CommandBoundResource {
|
||||
virtual void writeChanges() override;
|
||||
virtual void updateBuffer(uint32 binding, uint32 index, Gfx::PUniformBuffer uniformBuffer) override;
|
||||
virtual void updateBuffer(uint32 binding, uint32 index, Gfx::PShaderBuffer shaderBuffer) override;
|
||||
virtual void updateBuffer(uint32 binding, uint32 index, Gfx::PVertexBuffer indexBuffer) override;
|
||||
virtual void updateBuffer(uint32 binding, uint32 index, Gfx::PIndexBuffer indexBuffer) override;
|
||||
virtual void updateSampler(uint32 binding, uint32 index, Gfx::PSampler samplerState) override;
|
||||
virtual void updateTexture(uint32 binding, uint32 index, Gfx::PTexture2D texture) override;
|
||||
|
||||
@@ -377,6 +377,19 @@ void Graphics::copyTexture(Gfx::PTexture source, Gfx::PTexture destination) {
|
||||
Gfx::SE_ACCESS_MEMORY_READ_BIT | Gfx::SE_ACCESS_MEMORY_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
}
|
||||
|
||||
void Graphics::copyBuffer(Gfx::PShaderBuffer srcBuffer, Gfx::PShaderBuffer dstBuffer) {
|
||||
PShaderBuffer src = srcBuffer.cast<ShaderBuffer>();
|
||||
PShaderBuffer dst = dstBuffer.cast<ShaderBuffer>();
|
||||
|
||||
VkBufferCopy region = {
|
||||
.srcOffset = 0,
|
||||
.dstOffset = 0,
|
||||
.size = src->getSize(),
|
||||
};
|
||||
vkCmdCopyBuffer(getGraphicsCommands()->getCommands()->getHandle(), src->getHandle(), dst->getHandle(), 1, ®ion);
|
||||
}
|
||||
|
||||
|
||||
Gfx::OBottomLevelAS Graphics::createBottomLevelAccelerationStructure(const Gfx::BottomLevelASCreateInfo& createInfo) {
|
||||
return new BottomLevelAS(this, createInfo);
|
||||
}
|
||||
@@ -740,7 +753,7 @@ void Graphics::pickPhysicalDevice() {
|
||||
};
|
||||
meshShaderFeatures = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT,
|
||||
.pNext = &accelerationFeatures,
|
||||
.pNext = nullptr,
|
||||
.taskShader = true,
|
||||
.meshShader = true,
|
||||
.meshShaderQueries = true,
|
||||
@@ -872,9 +885,9 @@ void Graphics::createDevice(GraphicsInitializer initializer) {
|
||||
#ifdef __APPLE__
|
||||
initializer.deviceExtensions.add("VK_KHR_portability_subset");
|
||||
#endif
|
||||
initializer.deviceExtensions.add(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
|
||||
initializer.deviceExtensions.add(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
|
||||
initializer.deviceExtensions.add(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||
//initializer.deviceExtensions.add(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME);
|
||||
//initializer.deviceExtensions.add(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME);
|
||||
//initializer.deviceExtensions.add(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME);
|
||||
VkDeviceCreateInfo deviceInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = &features,
|
||||
|
||||
@@ -78,6 +78,8 @@ class Graphics : public Gfx::Graphics {
|
||||
|
||||
virtual void resolveTexture(Gfx::PTexture source, Gfx::PTexture destination) override;
|
||||
virtual void copyTexture(Gfx::PTexture src, Gfx::PTexture dst) override;
|
||||
|
||||
virtual void copyBuffer(Gfx::PShaderBuffer src, Gfx::PShaderBuffer dst) override;
|
||||
|
||||
// Ray Tracing
|
||||
virtual Gfx::OBottomLevelAS createBottomLevelAccelerationStructure(const Gfx::BottomLevelASCreateInfo& createInfo) override;
|
||||
|
||||
@@ -49,7 +49,7 @@ PGraphicsPipeline PipelineCache::createPipeline(Gfx::LegacyPipelineCreateInfo gf
|
||||
if (graphicsPipelines.contains(hash)) {
|
||||
return graphicsPipelines[hash];
|
||||
}
|
||||
PPipelineLayout layout = Gfx::PPipelineLayout(gfxInfo.pipelineLayout).cast<PipelineLayout>();
|
||||
PPipelineLayout layout = gfxInfo.pipelineLayout.cast<PipelineLayout>();
|
||||
Array<VkVertexInputBindingDescription> bindings;
|
||||
Array<VkVertexInputAttributeDescription> attributes;
|
||||
if (gfxInfo.vertexInput != nullptr) {
|
||||
@@ -429,7 +429,7 @@ PGraphicsPipeline PipelineCache::createPipeline(Gfx::MeshPipelineCreateInfo gfxI
|
||||
}
|
||||
|
||||
PComputePipeline PipelineCache::createPipeline(Gfx::ComputePipelineCreateInfo computeInfo) {
|
||||
PPipelineLayout layout = Gfx::PPipelineLayout(computeInfo.pipelineLayout).cast<PipelineLayout>();
|
||||
PPipelineLayout layout = computeInfo.pipelineLayout.cast<PipelineLayout>();
|
||||
auto computeStage = computeInfo.computeShader.cast<ComputeShader>();
|
||||
|
||||
uint32 hash = layout->getHash();
|
||||
|
||||
@@ -14,7 +14,7 @@ double Gfx::getCurrentFrameDelta() { return currentFrameDelta; }
|
||||
double currentFrameTime = 0;
|
||||
double Gfx::getCurrentFrameTime() { return currentFrameTime; }
|
||||
|
||||
uint32 currentFrameIndex = 0;
|
||||
uint32 currentFrameIndex = std::numeric_limits<uint32>::max();
|
||||
uint32 Gfx::getCurrentFrameIndex() { return currentFrameIndex; }
|
||||
|
||||
void glfwKeyCallback(GLFWwindow* handle, int key, int, int action, int modifier) {
|
||||
|
||||
@@ -33,22 +33,48 @@ void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarg
|
||||
}
|
||||
slang::SessionDesc sessionDesc;
|
||||
sessionDesc.flags = 0;
|
||||
StaticArray<slang::CompilerOptionEntry, 5> option;
|
||||
option[0].name = slang::CompilerOptionName::IgnoreCapabilities;
|
||||
option[0].value.kind = slang::CompilerOptionValueKind::Int;
|
||||
option[0].value.intValue0 = 1;
|
||||
option[1].name = slang::CompilerOptionName::EmitSpirvViaGLSL;
|
||||
option[1].value.kind = slang::CompilerOptionValueKind::Int;
|
||||
option[1].value.intValue0 = 1;
|
||||
option[2].name = slang::CompilerOptionName::DebugInformation;
|
||||
option[2].value.kind = slang::CompilerOptionValueKind::Int;
|
||||
option[2].value.intValue0 = SLANG_DEBUG_INFO_LEVEL_STANDARD;
|
||||
option[3].name = slang::CompilerOptionName::DebugInformationFormat;
|
||||
option[3].value.kind = slang::CompilerOptionValueKind::Int;
|
||||
option[3].value.intValue0 = SLANG_DEBUG_INFO_FORMAT_PDB;
|
||||
option[4].name = slang::CompilerOptionName::DumpIntermediates;
|
||||
option[4].value.kind = slang::CompilerOptionValueKind::Int;
|
||||
option[4].value.intValue0 = info.dumpIntermediate;
|
||||
Array<slang::CompilerOptionEntry> option = {
|
||||
{
|
||||
.name = slang::CompilerOptionName::IgnoreCapabilities,
|
||||
.value =
|
||||
{
|
||||
.kind = slang::CompilerOptionValueKind::Int,
|
||||
.intValue0 = 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = slang::CompilerOptionName::EmitSpirvViaGLSL,
|
||||
.value =
|
||||
{
|
||||
.kind = slang::CompilerOptionValueKind::Int,
|
||||
.intValue0 = 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = slang::CompilerOptionName::DebugInformation,
|
||||
.value =
|
||||
{
|
||||
.kind = slang::CompilerOptionValueKind::Int,
|
||||
.intValue0 = SLANG_DEBUG_INFO_LEVEL_STANDARD,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = slang::CompilerOptionName::DebugInformationFormat,
|
||||
.value =
|
||||
{
|
||||
.kind = slang::CompilerOptionValueKind::Int,
|
||||
.intValue0 = SLANG_DEBUG_INFO_FORMAT_PDB,
|
||||
},
|
||||
},
|
||||
{
|
||||
.name = slang::CompilerOptionName::DumpIntermediates,
|
||||
.value =
|
||||
{
|
||||
.kind = slang::CompilerOptionValueKind::Int,
|
||||
.intValue0 = info.dumpIntermediate,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
sessionDesc.compilerOptionEntries = option.data();
|
||||
sessionDesc.compilerOptionEntryCount = option.size();
|
||||
@@ -63,11 +89,11 @@ void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarg
|
||||
sessionDesc.preprocessorMacroCount = macros.size();
|
||||
sessionDesc.preprocessorMacros = macros.data();
|
||||
slang::TargetDesc targetDesc;
|
||||
targetDesc.profile = globalSession->findProfile("spirv_1_5");
|
||||
targetDesc.profile = globalSession->findProfile("GLSL_450");
|
||||
targetDesc.format = target;
|
||||
sessionDesc.targetCount = 1;
|
||||
sessionDesc.targets = &targetDesc;
|
||||
StaticArray<const char*, 4> searchPaths = {"shaders/", "shaders/lib/", "shaders/raytracing/", "shaders/generated/"};
|
||||
StaticArray<const char*, 5> searchPaths = {"shaders/", "shaders/lib/", "shaders/raytracing/", "shaders/terrain", "shaders/generated/"};
|
||||
sessionDesc.searchPaths = searchPaths.data();
|
||||
sessionDesc.searchPathCount = searchPaths.size();
|
||||
|
||||
@@ -113,20 +139,20 @@ void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarg
|
||||
|
||||
slang::ProgramLayout* signature = specializedComponent->getLayout(0, diagnostics.writeRef());
|
||||
CHECK_DIAGNOSTICS();
|
||||
//std::cout << info.name << std::endl;
|
||||
// std::cout << info.name << std::endl;
|
||||
for (size_t i = 0; i < signature->getParameterCount(); ++i) {
|
||||
auto param = signature->getParameterByIndex(i);
|
||||
layout->addMapping(param->getName(), param->getBindingIndex());
|
||||
//std::cout << param->getName() << ": " << param->getBindingIndex() << std::endl;
|
||||
// std::cout << param->getName() << ": " << param->getBindingIndex() << std::endl;
|
||||
}
|
||||
|
||||
// workaround
|
||||
//layout->addMapping("pVertexData", 1);
|
||||
//layout->addMapping("pMaterial", 4);
|
||||
//layout->addMapping("pLightEnv", 3);
|
||||
//layout->addMapping("pRayTracingParams", 5);
|
||||
//layout->addMapping("pScene", 2);
|
||||
//layout->addMapping("pWaterMaterial", 1);
|
||||
// layout->addMapping("pVertexData", 1);
|
||||
// layout->addMapping("pMaterial", 4);
|
||||
// layout->addMapping("pLightEnv", 3);
|
||||
// layout->addMapping("pRayTracingParams", 5);
|
||||
// layout->addMapping("pScene", 2);
|
||||
// layout->addMapping("pWaterMaterial", 1);
|
||||
}
|
||||
|
||||
Pair<Slang::ComPtr<slang::IBlob>, std::string> Seele::generateShader(const ShaderCreateInfo& createInfo) {
|
||||
|
||||
Reference in New Issue
Block a user