Adding basic CBT Terrain implementation

This commit is contained in:
Dynamitos
2024-10-10 20:36:59 +02:00
parent c89fd405b8
commit 98a7e16756
38 changed files with 3779 additions and 373 deletions
+63 -184
View File
@@ -1,198 +1,77 @@
import Common;
import Bounding;
import Scene;
import MaterialParameter;
import Parameters;
struct TerrainPayload
// Vertex input
struct VertexInput
{
float3 offset;
float extent;
uint numMeshes;
uint instanceID : SV_InstanceID;
uint vertexID : SV_VertexID;
};
struct TerrainTile
// Vertex output
struct VertexOutput
{
int2 location;
float extent;
float height;
float4 positionCS : SV_POSITION;
uint triangleID : TRIANGLE_ID;
};
struct TerrainVertex
[shader("vertex")]
VertexOutput vert(VertexInput input)
{
float4 position_CS : SV_Position;
float3 position_WS : POSITION0;
float2 texCoord : TEXCOORD0;
float depth : DEPTH;
uint lod : BONEINDEX;
// Initialize the output structure
VertexOutput output;
output = (VertexOutput)0;
// Evaluate the properties of this triangle
uint triangle_id = input.vertexID / 3;
uint local_vert_id = input.vertexID % 3;
// Operate the indirection
output.triangleID = pParams.indexedBisectorBuffer[triangle_id];
// Which vertex should be read?
local_vert_id = local_vert_id == 0 ? 2 : (local_vert_id == 2 ? 0 : 1);
float3 positionRWS = pParams.currentVertexBuffer[output.triangleID * 3 + local_vert_id];
// Apply the view projection
output.positionCS = mul(pViewParams.projectionMatrix, mul(pViewParams.viewMatrix, float4(positionRWS, 1.0)));
return output;
}
// Pixel input
struct PixelInput
{
float4 positionCS : SV_POSITION;
uint triangleID : TRIANGLE_ID;
};
struct TerrainData
{
StructuredBuffer<TerrainTile> tiles;
Texture2D<float> displacement;
Texture2D<float3> colorMap;
SamplerState sampler;
};
ParameterBlock<TerrainData> pTerrainData;
[numthreads(1, 1, 1)]
[shader("amplification")]
void taskMain(
uint threadID: SV_GroupThreadID,
uint3 groupID: SV_GroupID
) {
TerrainTile tile = pTerrainData.tiles[groupID.x];
GroupMemoryBarrierWithGroupSync();
AABB bounding;
bounding.minCorner = float3(tile.location.x, tile.height, tile.location.y) * tile.extent;
bounding.maxCorner = float3(tile.location.x + tile.extent, tile.height, tile.location.y + tile.extent) * tile.extent;
float3 origin = viewToWorld(float4(0, 0, 0, 1)).xyz;
const float offset = 0.0f;
float3 corners[4] = {
screenToWorld(float4(offset, offset, -1.0f, 1.0f)).xyz,
screenToWorld(float4(pViewParams.screenDimensions.x - offset, offset, -1.0f, 1.0f)).xyz,
screenToWorld(float4(offset, pViewParams.screenDimensions.y - offset, -1.0f, 1.0f)).xyz,
screenToWorld(float4(pViewParams.screenDimensions - float2(offset, offset), -1.0f, 1.0f)).xyz
};
Frustum viewFrustum;
viewFrustum.sides[0] = computePlane(origin, corners[2], corners[0]);
viewFrustum.sides[1] = computePlane(origin, corners[1], corners[3]);
viewFrustum.sides[2] = computePlane(origin, corners[0], corners[1]);
viewFrustum.sides[3] = computePlane(origin, corners[3], corners[2]);
if(!bounding.insideFrustum(viewFrustum))
{
return;
}
float3 median = (bounding.minCorner + bounding.maxCorner) / 2;
float distance = distance(median, pViewParams.cameraPos_WS.xyz);
float tileDistance = distance / tile.extent;
uint numMeshes = groupID.y + 1;
if(numMeshes == 4 && tileDistance > 2)
{
return;
}
if(numMeshes == 3 && (tileDistance > 4 || tileDistance < 1))
{
return;
}
if(numMeshes == 2 && (tileDistance > 8 || tileDistance < 3))
{
return;
}
if(numMeshes == 1 && tileDistance < 7)
{
return;
}
TerrainPayload payload;
payload.offset = bounding.minCorner;
payload.extent = tile.extent / numMeshes;
payload.numMeshes = numMeshes;
DispatchMesh(numMeshes, numMeshes, 1, payload);
}
const static uint64_t TILE_VERTS = 144;
const static uint64_t TILE_PRIMS = 242;
const static float2 VERT[TILE_VERTS] = {float2(0.0f / 11, 0.0f / 11), float2(0.0f / 11, 1.0f / 11), float2(0.0f / 11, 2.0f / 11), float2(0.0f / 11, 3.0f / 11), float2(0.0f / 11, 4.0f / 11), float2(0.0f / 11, 5.0f / 11), float2(0.0f / 11,
6.0f / 11), float2(0.0f / 11, 7.0f / 11), float2(0.0f / 11, 8.0f / 11), float2(0.0f / 11, 9.0f / 11), float2(0.0f / 11, 10.0f / 11), float2(0.0f / 11, 11.0f / 11), float2(1.0f / 11, 0.0f / 11), float2(1.0f / 11, 1.0f / 11), float2(1.0f / 11, 2.0f / 11), float2(1.0f / 11, 3.0f / 11), float2(1.0f /
11, 4.0f / 11), float2(1.0f / 11, 5.0f / 11), float2(1.0f / 11, 6.0f / 11), float2(1.0f / 11, 7.0f / 11), float2(1.0f / 11, 8.0f / 11), float2(1.0f / 11, 9.0f / 11), float2(1.0f / 11, 10.0f / 11), float2(1.0f / 11, 11.0f / 11), float2(2.0f / 11, 0.0f / 11), float2(2.0f / 11, 1.0f / 11), float2(2.0f / 11, 2.0f / 11), float2(2.0f / 11, 3.0f / 11), float2(2.0f / 11, 4.0f / 11), float2(2.0f / 11, 5.0f / 11), float2(2.0f / 11, 6.0f / 11), float2(2.0f / 11, 7.0f / 11), float2(2.0f / 11, 8.0f / 11), float2(2.0f / 11, 9.0f / 11), float2(2.0f / 11, 10.0f / 11), float2(2.0f / 11, 11.0f / 11), float2(3.0f / 11, 0.0f / 11), float2(3.0f / 11, 1.0f / 11), float2(3.0f / 11, 2.0f / 11), float2(3.0f / 11, 3.0f / 11), float2(3.0f / 11, 4.0f / 11), float2(3.0f / 11, 5.0f / 11), float2(3.0f / 11, 6.0f / 11), float2(3.0f / 11, 7.0f / 11), float2(3.0f / 11, 8.0f / 11), float2(3.0f / 11, 9.0f / 11), float2(3.0f / 11, 10.0f / 11), float2(3.0f / 11, 11.0f / 11), float2(4.0f / 11, 0.0f / 11), float2(4.0f
/ 11, 1.0f / 11), float2(4.0f / 11, 2.0f / 11), float2(4.0f / 11, 3.0f / 11), float2(4.0f / 11, 4.0f / 11), float2(4.0f / 11, 5.0f / 11), float2(4.0f / 11, 6.0f / 11), float2(4.0f / 11, 7.0f / 11), float2(4.0f / 11, 8.0f / 11), float2(4.0f / 11, 9.0f / 11), float2(4.0f / 11, 10.0f / 11), float2(4.0f / 11, 11.0f / 11), float2(5.0f / 11, 0.0f / 11), float2(5.0f / 11, 1.0f / 11), float2(5.0f / 11,
2.0f / 11), float2(5.0f / 11, 3.0f / 11), float2(5.0f / 11, 4.0f / 11), float2(5.0f / 11, 5.0f / 11), float2(5.0f / 11, 6.0f / 11), float2(5.0f / 11, 7.0f / 11), float2(5.0f / 11, 8.0f / 11), float2(5.0f / 11, 9.0f / 11), float2(5.0f / 11, 10.0f / 11), float2(5.0f / 11, 11.0f / 11), float2(6.0f /
11, 0.0f / 11), float2(6.0f / 11, 1.0f / 11), float2(6.0f / 11, 2.0f / 11), float2(6.0f / 11, 3.0f / 11), float2(6.0f / 11, 4.0f / 11), float2(6.0f / 11, 5.0f / 11), float2(6.0f / 11, 6.0f / 11), float2(6.0f / 11, 7.0f / 11), float2(6.0f / 11, 8.0f / 11), float2(6.0f / 11, 9.0f / 11), float2(6.0f
/ 11, 10.0f / 11), float2(6.0f / 11, 11.0f / 11), float2(7.0f / 11, 0.0f / 11), float2(7.0f / 11, 1.0f / 11), float2(7.0f / 11, 2.0f / 11), float2(7.0f / 11, 3.0f / 11), float2(7.0f / 11, 4.0f / 11), float2(7.0f / 11, 5.0f / 11), float2(7.0f / 11, 6.0f / 11), float2(7.0f / 11, 7.0f / 11), float2(7.0f / 11, 8.0f / 11), float2(7.0f / 11, 9.0f / 11), float2(7.0f / 11, 10.0f / 11), float2(7.0f / 11, 11.0f / 11), float2(8.0f / 11, 0.0f / 11), float2(8.0f / 11, 1.0f / 11), float2(8.0f / 11, 2.0f / 11), float2(8.0f / 11, 3.0f / 11), float2(8.0f / 11, 4.0f / 11), float2(8.0f / 11, 5.0f / 11), float2(8.0f / 11, 6.0f / 11), float2(8.0f / 11, 7.0f / 11), float2(8.0f / 11, 8.0f / 11), float2(8.0f /
11, 9.0f / 11), float2(8.0f / 11, 10.0f / 11), float2(8.0f / 11, 11.0f / 11), float2(9.0f / 11, 0.0f / 11), float2(9.0f / 11, 1.0f / 11), float2(9.0f / 11, 2.0f / 11), float2(9.0f / 11, 3.0f / 11), float2(9.0f / 11, 4.0f / 11), float2(9.0f / 11, 5.0f / 11), float2(9.0f / 11, 6.0f / 11), float2(9.0f / 11, 7.0f / 11), float2(9.0f / 11, 8.0f / 11), float2(9.0f / 11, 9.0f / 11), float2(9.0f / 11, 10.0f / 11), float2(9.0f / 11, 11.0f / 11), float2(10.0f / 11, 0.0f / 11), float2(10.0f / 11, 1.0f / 11), float2(10.0f / 11, 2.0f / 11), float2(10.0f / 11, 3.0f / 11), float2(10.0f / 11, 4.0f / 11), float2(10.0f / 11, 5.0f / 11), float2(10.0f / 11, 6.0f / 11), float2(10.0f / 11, 7.0f / 11), float2(10.0f / 11, 8.0f / 11), float2(10.0f / 11, 9.0f / 11), float2(10.0f / 11, 10.0f / 11), float2(10.0f / 11, 11.0f / 11), float2(11.0f / 11, 0.0f / 11), float2(11.0f / 11, 1.0f / 11), float2(11.0f / 11, 2.0f / 11), float2(11.0f / 11, 3.0f / 11), float2(11.0f / 11, 4.0f / 11), float2(11.0f / 11, 5.0f / 11), float2(11.0f / 11, 6.0f / 11), float2(11.0f / 11, 7.0f / 11), float2(11.0f / 11, 8.0f / 11), float2(11.0f / 11, 9.0f / 11), float2(11.0f / 11, 10.0f / 11), float2(11.0f / 11, 11.0f / 11)};
const static uint3 IND[TILE_PRIMS] = {uint3(0, 1, 12), uint3(12, 1, 13), uint3(1, 2, 13), uint3(13, 2, 14), uint3(2, 3, 14), uint3(14, 3, 15), uint3(3, 4, 15), uint3(15, 4, 16), uint3(4, 5, 16), uint3(16, 5, 17), uint3(5, 6, 17), uint3(17, 6, 18), uint3(6, 7, 18), uint3(18, 7, 19), uint3(7, 8, 19), uint3(19, 8, 20), uint3(8, 9, 20), uint3(20, 9, 21), uint3(9, 10, 21), uint3(21, 10, 22), uint3(10, 11, 22), uint3(22, 11, 23), uint3(12, 13, 24), uint3(24, 13, 25), uint3(13, 14, 25), uint3(25, 14, 26), uint3(14,
15, 26), uint3(26, 15, 27), uint3(15, 16, 27), uint3(27, 16, 28), uint3(16, 17, 28), uint3(28, 17, 29), uint3(17, 18, 29), uint3(29, 18, 30), uint3(18, 19, 30), uint3(30, 19, 31), uint3(19, 20, 31), uint3(31, 20, 32), uint3(20, 21, 32), uint3(32, 21, 33), uint3(21, 22, 33), uint3(33, 22, 34), uint3(22, 23, 34), uint3(34, 23, 35), uint3(24, 25, 36), uint3(36, 25, 37), uint3(25, 26,
37), uint3(37, 26, 38), uint3(26, 27, 38), uint3(38, 27, 39), uint3(27, 28, 39), uint3(39, 28, 40), uint3(28, 29, 40), uint3(40, 29, 41), uint3(29, 30, 41), uint3(41, 30, 42), uint3(30, 31, 42), uint3(42, 31, 43), uint3(31, 32, 43), uint3(43, 32, 44), uint3(32, 33, 44), uint3(44, 33, 45), uint3(33, 34, 45), uint3(45, 34, 46), uint3(34, 35, 46), uint3(46, 35, 47), uint3(36, 37, 48), uint3(48, 37, 49), uint3(37, 38, 49), uint3(49, 38, 50), uint3(38, 39, 50), uint3(50, 39, 51), uint3(39, 40, 51), uint3(51, 40, 52), uint3(40, 41, 52), uint3(52, 41, 53), uint3(41, 42, 53),
uint3(53, 42, 54), uint3(42, 43, 54), uint3(54, 43, 55), uint3(43, 44, 55), uint3(55, 44, 56), uint3(44, 45, 56), uint3(56, 45, 57), uint3(45, 46, 57), uint3(57, 46, 58), uint3(46, 47, 58), uint3(58, 47, 59), uint3(48, 49, 60), uint3(60, 49, 61), uint3(49, 50, 61), uint3(61, 50, 62), uint3(50, 51, 62), uint3(62, 51, 63), uint3(51, 52, 63), uint3(63, 52, 64), uint3(52, 53, 64), uint3(64, 53, 65), uint3(53, 54, 65), uint3(65, 54, 66), uint3(54, 55, 66), uint3(66, 55, 67), uint3(55, 56, 67), uint3(67, 56, 68), uint3(56, 57, 68), uint3(68, 57, 69), uint3(57, 58, 69), uint3(69, 58, 70), uint3(58, 59, 70), uint3(70, 59, 71), uint3(60, 61, 72), uint3(72, 61, 73), uint3(61, 62, 73), uint3(73, 62, 74), uint3(62, 63, 74), uint3(74, 63, 75), uint3(63, 64, 75), uint3(75, 64, 76), uint3(64, 65, 76), uint3(76, 65, 77), uint3(65, 66, 77), uint3(77, 66, 78), uint3(66, 67, 78), uint3(78, 67, 79), uint3(67, 68, 79), uint3(79, 68, 80), uint3(68, 69, 80), uint3(80, 69, 81), uint3(69, 70, 81), uint3(81, 70, 82), uint3(70, 71, 82), uint3(82, 71, 83), uint3(72,
73, 84), uint3(84, 73, 85), uint3(73, 74, 85), uint3(85, 74, 86), uint3(74, 75, 86), uint3(86, 75, 87), uint3(75, 76, 87), uint3(87, 76, 88), uint3(76, 77, 88), uint3(88, 77, 89), uint3(77, 78, 89), uint3(89, 78, 90), uint3(78, 79, 90), uint3(90, 79, 91), uint3(79, 80, 91), uint3(91, 80, 92), uint3(80, 81, 92), uint3(92, 81, 93), uint3(81, 82, 93), uint3(93, 82, 94), uint3(82, 83,
94), uint3(94, 83, 95), uint3(84, 85, 96), uint3(96, 85, 97), uint3(85, 86, 97), uint3(97, 86, 98), uint3(86, 87, 98), uint3(98, 87, 99), uint3(87, 88, 99), uint3(99, 88, 100), uint3(88, 89, 100), uint3(100, 89, 101), uint3(89, 90, 101), uint3(101, 90, 102), uint3(90, 91, 102), uint3(102, 91, 103), uint3(91, 92, 103), uint3(103, 92, 104), uint3(92, 93, 104), uint3(104, 93, 105), uint3(93, 94, 105), uint3(105, 94, 106), uint3(94, 95, 106), uint3(106, 95, 107), uint3(96, 97, 108), uint3(108, 97, 109), uint3(97, 98, 109), uint3(109, 98, 110), uint3(98, 99, 110), uint3(110, 99, 111), uint3(99, 100, 111), uint3(111, 100, 112), uint3(100, 101, 112), uint3(112, 101, 113), uint3(101, 102, 113), uint3(113, 102, 114), uint3(102, 103, 114), uint3(114, 103, 115), uint3(103, 104, 115), uint3(115, 104, 116), uint3(104, 105, 116), uint3(116, 105, 117), uint3(105, 106, 117), uint3(117, 106, 118), uint3(106, 107, 118), uint3(118, 107, 119), uint3(108, 109, 120), uint3(120, 109, 121), uint3(109, 110, 121), uint3(121, 110, 122), uint3(110, 111, 122), uint3(122, 111,
123), uint3(111, 112, 123), uint3(123, 112, 124), uint3(112, 113, 124), uint3(124, 113, 125), uint3(113, 114, 125), uint3(125, 114, 126), uint3(114, 115, 126), uint3(126, 115, 127), uint3(115, 116, 127), uint3(127, 116, 128), uint3(116, 117, 128), uint3(128, 117, 129), uint3(117, 118, 129), uint3(129, 118, 130), uint3(118, 119, 130), uint3(130, 119, 131), uint3(120, 121, 132), uint3(132, 121, 133), uint3(121, 122, 133), uint3(133, 122, 134), uint3(122, 123, 134), uint3(134, 123, 135), uint3(123, 124, 135), uint3(135, 124, 136), uint3(124, 125, 136), uint3(136, 125, 137), uint3(125, 126, 137), uint3(137, 126, 138), uint3(126, 127, 138), uint3(138, 127, 139), uint3(127, 128, 139), uint3(139, 128, 140), uint3(128, 129, 140), uint3(140, 129, 141), uint3(129, 130, 141), uint3(141, 130, 142), uint3(130, 131, 142), uint3(142, 131, 143)};
[numthreads(MESH_GROUP_SIZE, 1, 1)]
[outputtopology("triangle")]
[shader("mesh")]
void meshMain(
in uint threadID: SV_GroupThreadID,
in uint3 groupID: SV_GroupID,
in payload TerrainPayload params,
out vertices TerrainVertex vertices[TILE_VERTS],
out indices uint3 indices[TILE_PRIMS],
) {
float4x4 vp = mul(pViewParams.projectionMatrix, pViewParams.viewMatrix);
SetMeshOutputCounts(TILE_VERTS, TILE_PRIMS);
for(uint i = threadID; i < TILE_PRIMS; i += MESH_GROUP_SIZE)
{
indices[i] = IND[i];
}
for(uint i = threadID; i < TILE_VERTS; i += MESH_GROUP_SIZE)
{
float2 base = VERT[i];
float3 objectPos = float3(base.x, 0, base.y);
float3 worldPos = params.offset + objectPos * params.extent + float3(groupID.x * params.extent, 0, groupID.y * params.extent);
float lodDisplacement = 0;
float3 camPos = pViewParams.cameraPos_WS.xyz;
float cameraDistance = distance(worldPos, camPos);
float threshold = 0;
if(params.numMeshes == 3)
{
threshold = 10;
}
if(params.numMeshes == 2)
{
threshold = 30;
}
if(params.numMeshes == 1)
{
threshold = 70;
}
if(params.numMeshes < 4)
{
if(cameraDistance > threshold)
{
lodDisplacement = clamp(exp(-(1 / (cameraDistance + threshold))), 0, 1) - 1;
}
else
{
lodDisplacement = -1;
}
}
// float3 displacement1 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile1, 0)).xyz * pWaterMaterial.contributeDisplacement1;
// float3 displacement2 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile2, 1)).xyz * pWaterMaterial.contributeDisplacement2;
// float3 displacement3 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile3, 2)).xyz * pWaterMaterial.contributeDisplacement3;
// float3 displacement4 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile4, 3)).xyz * pWaterMaterial.contributeDisplacement4;
float displacement = pTerrainData.displacement.SampleLevel(pTerrainData.sampler, worldPos.xz / 1000, 0) * 10;
float4 clipPos = mul(vp, float4(worldPos, 1));
float ndcDepth = clipPos.z / clipPos.w;
float depth = 1 - (-ndcDepth + 1.0f) / 2.0f;
// displacement = lerp(0.0f, displacement, pow(saturate(depth), pTerrainData.displacementDepthAttenuation));
worldPos.y += displacement;
worldPos.y += lodDisplacement;
TerrainVertex v;
v.position_WS = worldPos;
v.position_CS = mul(vp, float4(worldPos, 1));
v.texCoord = worldPos.xz;
v.depth = depth;
v.lod = params.numMeshes;
vertices[i] = v;
}
}
[shader("pixel")]
float4 fragmentMain(TerrainVertex vertex)
float4 frag(PixelInput input) : SV_Target
{
return float4(pTerrainData.colorMap.Sample(pTerrainData.sampler, vertex.position_WS.xz / 1000), 1);
return float4(0, 1, 0, 1);
}
[shader("compute")]
[numthreads(64, 1, 1)]
void deform(uint currentID: SV_DispatchThreadID)
{
if(currentID > pParams.indirectDrawBuffer[9] * 4)
return;
uint bisectorID = currentID / 4;
uint localVertexID = currentID % 4;
bisectorID = pParams.indexedBisectorBuffer[bisectorID];
currentID = localVertexID < 3 ? bisectorID * 3 + localVertexID : 3 * pParams.geometry.totalNumElements + bisectorID;
float3 positionWS = pParams.lebPositionBuffer[currentID];
float3 positionPS = positionWS;
float3 normalPS = float3(0, 1, 0);
float2 sampleUV = float2(0, 0);
pParams.currentVertexBuffer[currentID] = positionWS;
}
+4 -4
View File
@@ -87,7 +87,7 @@ void taskMain(
bounding.minCorner = float3(tile.location.x, tile.height, tile.location.y) * tile.extent;
bounding.maxCorner = float3(tile.location.x + 1, tile.height, tile.location.y + 1) * tile.extent;
float3 median = (bounding.minCorner + bounding.maxCorner) / 2;
float distance = distance(median, pViewParams.cameraPos_WS.xyz);
float distance = distance(median, pViewParams.cameraPosition_WS.xyz);
float tileDistance = distance / tile.extent;
uint numMeshes = groupID.y + 1;
@@ -179,7 +179,7 @@ void meshMain(
float3 worldPos = params.offset + objectPos * params.extent + float3(groupID.x * params.extent, 0, groupID.y * params.extent);
float lodDisplacement = 0;
float3 camPos = pViewParams.ameraPos_WS.xyz;
float3 camPos = pViewParams.cameraPosition_WS.xyz;
float cameraDistance = distance(worldPos, camPos);
float threshold = 0;
if(params.numMeshes == 3)
@@ -207,7 +207,7 @@ void meshMain(
}
}
// TODO: LOD load
float3 displacement1 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile1, 0)).xyz * pWaterMaterial.contributeDisplacement1;
float3 displacement2 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile2, 1)).xyz * pWaterMaterial.contributeDisplacement2;
float3 displacement3 = pWaterMaterial.displacementTextures.Sample(pWaterMaterial.sampler, float3(worldPos.xz * pWaterMaterial.tile3, 2)).xyz * pWaterMaterial.contributeDisplacement3;
@@ -237,7 +237,7 @@ void meshMain(
[shader("pixel")]
float4 fragmentMain(WaterVertex vert) : SV_TARGET {
float3 lightDir = -normalize(pWaterMaterial.sunDirection);
float3 viewDir = normalize(pViewParams.cameraPos_WS.xyz - vert.position_WS);
float3 viewDir = normalize(pViewParams.cameraPosition_WS.xyz - vert.position_WS);
float3 halfwayDir = normalize(lightDir + viewDir);
float depth = vert.depth;
float LdotH = clamp(dot(lightDir, halfwayDir), 0, 1);
+6 -1
View File
@@ -6,12 +6,17 @@ static const uint32_t MESH_GROUP_SIZE = 32;
struct ViewParameter
{
Frustum viewFrustum;
float4x4 viewMatrix;
float4x4 inverseViewMatrix;
float4x4 projectionMatrix;
float4x4 inverseProjection;
float4 cameraPos_WS;
float4 cameraPosition_WS;
float4 cameraForward_WS;
float2 screenDimensions;
float2 invScreenDimensions;
uint frameIndex;
float time;
};
layout(set = 0)
ParameterBlock<ViewParameter> pViewParams;
+1 -1
View File
@@ -51,7 +51,7 @@ struct FragmentParameter
float3x3 tbn = float3x3(normalize(tangent_WS), normalize(biTangent_WS), normalize(normal_WS));
result.tbn = tbn;
result.position_TS = mul(tbn, position_WS);
result.viewDir_TS = mul(tbn, normalize(pViewParams.cameraPos_WS.xyz - position_WS));
result.viewDir_TS = mul(tbn, normalize(pViewParams.cameraPosition_WS.xyz - position_WS));
result.normal_TS = mul(tbn, normal_WS);
return result;
}
+46
View File
@@ -0,0 +1,46 @@
// Pointer to an invalid neighbor or index
const static int INVALID_POINTER = 4294967295;
// Possible culling state
const static int BACK_FACE_CULLED =-3;
const static int FRUSTUM_CULLED =-2;
const static int TOO_SMALL =-1;
const static int UNCHANGED_ELEMENT= 0;
const static int BISECT_ELEMENT= 1;
const static int SIMPLIFY_ELEMENT= 2;
const static int MERGED_ELEMENT= 3;
// Bisector flags
const static int VISIBLE_BISECTOR = 0x1;
const static int MODIFIED_BISECTOR = 0x2;
struct BisectorData
{
// Subvision that should be applied to this bisector
uint32_t subdivisionPattern;
// Allocated indices for this bisector
uint32_t indices[3];
// Neighbor that should be processed
uint32_t problematicNeighbor;
// State of this bisector (split, merge, etc)
uint32_t bisectorState;
// Visibility and modification flags of a bisector
uint32_t flags;
// ID used for the propagation
uint32_t propagationID;
};
uint heapIDDepth(uint64_t x)
{
uint depth = 0;
while (x > 0u) {
++depth;
x >>= 1u;
}
return depth;
}
+617
View File
@@ -0,0 +1,617 @@
import Parameters;
#ifndef WORKGROUP_SIZE
#define WORKGROUP_SIZE 64
#endif
// Num elements
#define OCBT_NUM_ELEMENTS 1048576
// Tree sizes
#define OCBT_TREE_SIZE_BITS (32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512 + 16 * 1024 + 16* 2048 + 16 * 4096 + 8 * 8192)
#define OCBT_TREE_NUM_SLOTS (OCBT_TREE_SIZE_BITS / 32)
#define OCBT_BITFIELD_NUM_SLOTS (OCBT_NUM_ELEMENTS / 64)
#define OCBT_LAST_LEVEL_SIZE 8192
// Tree last level
#define TREE_LAST_LEVEL 13
// First virtual level
#define FIRST_VIRTUAL_LEVEL 14
// Leaf level
#define LEAF_LEVEL 20
// per level offset
static const uint32_t OCBT_depth_offset[21] = { 0, // Level 0
32 * 1, // level 1
32 * 1 + 32 * 2, // level 2
32 * 1 + 32 * 2 + 32 * 4, // level 3
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8, // Level 4
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16, // Level 5
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32, // Level 6
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64, // Level 7
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128, // Level 8
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256, // Level 9
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512, // Level 10
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512 + 16 * 1024, // Level 11
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512 + 16 * 1024 + 16 * 2048, // Level 12
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512 + 16 * 1024 + 16 * 2048 + 16 * 4096, // Level 13
0, // Level 14
0, // Level 15
0, // Level 16
0, // Level 17
0, // Level 18
0, // Level 19
0, // Level 20
};
static const uint64_t OCBT_bit_mask[21] = { 0xffffffff, // Root 17
0xffffffff, // Level 16
0xffffffff, // level 15
0xffffffff, // level 14
0xffffffff, // level 13
0xffffffff, // level 12
0xffffffff, // level 11
0xffff, // level 10
0xffff, // level 9
0xffff, // level 8
0xffff, // level 8
0xffff, // level 8
0xffff, // level 8
0xff, // level 8
0xffffffffffffffff, // level 7
0xffffffff, // Level 6
0xffff, // level 5
0xff, // level 4
0xf, // level 3
0x3, // level 2
0x1, // level 1
};
static const uint32_t OCBT_bit_count[21] = { 32, // Root 17
32, // Level 16
32, // level 15
32, // level 14
32, // level 13
32, // level 12
32, // level 11
16, // level 10
16, // level 9
16, // level 8
16, // level 8
16, // level 8
16, // level 8
8, // level 8
64, // Level 5
32, // Level 5
16, // Level 4
8, // level 3
4, // level 2
2, // level 1
1, // level 0
};
// Define the remaining values
#define BUFFER_ELEMENT_PER_LANE ((OCBT_TREE_NUM_SLOTS + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE)
#define BUFFER_ELEMENT_PER_LANE_NO_BITFIELD ((OCBT_TREE_NUM_SLOTS + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE)
#define BITFIELD_ELEMENT_PER_LANE ((OCBT_BITFIELD_NUM_SLOTS + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE)
#define WAVE_TREE_DEPTH uint(log2(OCBT_NUM_ELEMENTS))
uint32_t cbt_size()
{
return OCBT_NUM_ELEMENTS;
}
uint32_t last_level_offset()
{
return OCBT_depth_offset[TREE_LAST_LEVEL] / 32;
}
groupshared uint gs_cbtTree[OCBT_TREE_NUM_SLOTS];
// Function that sets a given bit
void set_bit(uint bitID, bool state)
{
// Coordinates of the bit
uint32_t slot = bitID / 64;
uint32_t local_id = bitID % 64;
if (state)
pParams.bitFieldBuffer[slot] |= 1uLL << local_id;
else
pParams.bitFieldBuffer[slot] &= ~(1uLL << local_id);
}
void set_bit_atomic(uint bitID, bool state)
{
// Coordinates of the bit
uint32_t slot = bitID / 64;
uint32_t local_id = bitID % 64;
if (state)
InterlockedOr(pParams.bitFieldBuffer[slot], 1uLL << local_id);
else
InterlockedAnd(pParams.bitFieldBuffer[slot], ~(1uLL << local_id));
}
uint get_bit(uint bitID)
{
uint32_t slot = bitID / 64;
uint32_t local_id = bitID % 64;
return uint((pParams.bitFieldBuffer[slot] & (1uLL << local_id)) >> local_id);
}
uint get_heap_element(uint id)
{
// 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 = (1u << depth) - 1;
uint32_t id_in_level = real_heap_id - level_first_element;
uint32_t first_bit = OCBT_depth_offset[depth] + OCBT_bit_count[depth] * id_in_level;
if (depth < FIRST_VIRTUAL_LEVEL)
{
uint32_t slot = first_bit / 32;
uint32_t local_id = first_bit % 32;
uint32_t target_bits = (gs_cbtTree[slot] >> local_id) & uint32_t(OCBT_bit_mask[depth]);
return (gs_cbtTree[slot] >> local_id) & uint32_t(OCBT_bit_mask[depth]);
}
else
{
uint32_t slot = first_bit / 64;
uint32_t local_id = first_bit % 64;
uint64_t target_bits = (pParams.bitFieldBuffer[slot] >> local_id) & OCBT_bit_mask[depth];
uint32_t high = uint(target_bits >> 32);
uint32_t low = uint(target_bits);
return countbits(high) + countbits(low);
}
}
// Should not be called if depth > TREE_LAST_LEVEL
void set_heap_element(uint id, uint value)
{
// Figure out the location of the first bit of this element
uint real_heap_id = id - 1;
uint depth = uint(log2(real_heap_id + 1));
uint level_first_element = (1u << depth) - 1;
uint first_bit = OCBT_depth_offset[depth] + OCBT_bit_count[depth] * (real_heap_id - level_first_element);
// Find the slot and the local first bit
uint slot = first_bit / 32;
uint local_id = first_bit % 32;
// Extract the relevant bits
gs_cbtTree[slot] &= ~(uint32_t(OCBT_bit_mask[depth]) << local_id);
gs_cbtTree[slot] |= ((uint32_t(OCBT_bit_mask[depth]) & value) << local_id);
}
// Should not be called if depth > TREE_LAST_LEVEL
void set_heap_element_atomic(uint id, uint value)
{
// Figure out the location of the first bit of this element
uint real_heap_id = id - 1;
uint depth = uint(log2(real_heap_id + 1));
uint level_first_element = (1u << depth) - 1;
uint first_bit = OCBT_depth_offset[depth] + OCBT_bit_count[depth] * (real_heap_id - level_first_element);
// Find the slot and the local first bit
uint slot = first_bit / 32;
uint local_id = first_bit % 32;
// Extract the relevant bits
InterlockedAnd(gs_cbtTree[slot], ~(uint32_t(OCBT_bit_mask[depth]) << local_id));
InterlockedOr(gs_cbtTree[slot], ((uint32_t(OCBT_bit_mask[depth]) & value) << local_id));
}
// Function that returns the number of active bits
uint bit_count()
{
return gs_cbtTree[0];
}
uint bit_count(uint depth, uint element)
{
return get_heap_element((1u << depth) + element);
}
// decodes the position of the i-th one in the bitfield
uint decode_bit(uint handle)
{
#if defined(NAIVE_DECODE)
uint bitID = 1;
for (uint currentDepth = 0; currentDepth < WAVE_TREE_DEPTH; ++currentDepth)
{
uint heapValue = get_heap_element(2 * bitID);
uint b = handle < heapValue ? 0 : 1;
bitID = 2 * bitID + b;
handle -= heapValue * b;
}
return (bitID ^ OCBT_NUM_ELEMENTS);
#else
uint currentDepth = 0;
uint heapElementID = 1u;
for (currentDepth = 0; currentDepth < FIRST_VIRTUAL_LEVEL; ++currentDepth)
{
// Read the left element
uint heapValue = get_heap_element(2u * heapElementID);
// Does it fall in the right or left subtree?
uint 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 = pParams.bitFieldBuffer[heapElementID - OCBT_LAST_LEVEL_SIZE * 2];
uint64_t mask = 0xffffffff;
uint32_t bitCount = 32;
for (; currentDepth < (WAVE_TREE_DEPTH + 1); ++currentDepth)
{
// Figure out the location of the first bit of this element
uint real_heap_id = 2 * heapElementID - 1;
uint level_first_element = (1u << currentDepth) - 1;
uint id_in_level = real_heap_id - level_first_element;
uint first_bit = bitCount * id_in_level;
uint local_id = first_bit % 64;
uint64_t target_bits = (heapValue >> local_id) & mask;
uint32_t high = uint(target_bits >> 32);
uint32_t low = uint(target_bits);
uint heapValue = countbits(high) + countbits(low);
// Does it fall in the right or left subtree?
uint 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;
// Adjust the mask and bitcount
bitCount /= 2;
mask = mask >> bitCount;
}
return (heapElementID ^ OCBT_NUM_ELEMENTS);
#endif
}
// decodes the position of the i-th zero in the bitfield
uint decode_bit_complement(uint handle)
{
#if defined(NAIVE_DECODE)
uint bitID = 1u;
uint c = OCBT_NUM_ELEMENTS / 2u;
while (bitID < OCBT_NUM_ELEMENTS) {
uint heapValue = c - get_heap_element(2u * bitID);
uint b = handle < heapValue ? 0u : 1u;
bitID = 2u * bitID + b;
handle -= heapValue * b;
c /= 2u;
}
return (bitID ^ OCBT_NUM_ELEMENTS);
#else
uint heapElementID = 1u;
uint c = OCBT_NUM_ELEMENTS / 2u;
uint currentDepth = 0;
for (currentDepth = 0; currentDepth < FIRST_VIRTUAL_LEVEL; ++currentDepth)
{
uint heapValue = c - get_heap_element(2u * heapElementID);
uint 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 = pParams.bitFieldBuffer[heapElementID - OCBT_LAST_LEVEL_SIZE * 2];
uint64_t mask = 0xffffffff;
uint32_t bitCount = 32;
for (; currentDepth < (WAVE_TREE_DEPTH + 1); ++currentDepth)
{
// Figure out the location of the first bit of this element
uint real_heap_id = 2 * heapElementID - 1;
uint level_first_element = (1u << currentDepth) - 1;
uint id_in_level = real_heap_id - level_first_element;
uint first_bit = bitCount * id_in_level;
uint local_id = first_bit % 64;
uint64_t target_bits = (heapValue >> local_id) & mask;
uint32_t high = uint(target_bits >> 32);
uint32_t low = uint(target_bits);
uint heapValue = c - (countbits(high) + countbits(low));
uint b = handle < heapValue ? 0u : 1u;
heapElementID = 2u * heapElementID + b;
handle -= heapValue * b;
c /= 2u;
// Adjust the mask and bitcount
bitCount /= 2;
mask = mask >> bitCount;
}
return (heapElementID ^ OCBT_NUM_ELEMENTS);
#endif
}
void reduce(uint groupIndex)
{
// First we do a reduction until each lane has exactly one element to process
uint initial_pass_size = OCBT_NUM_ELEMENTS / WORKGROUP_SIZE;
for (uint it = initial_pass_size / 64, offset = OCBT_NUM_ELEMENTS / 64; it > 0 ; it >>=1, offset >>=1)
{
uint minHeapID = offset + (groupIndex * it);
uint maxHeapID = offset + ((groupIndex + 1) * it);
for (uint heapID = minHeapID; heapID < maxHeapID; ++heapID)
{
set_heap_element(heapID, get_heap_element(heapID * 2) + get_heap_element(heapID * 2 + 1));
}
}
GroupMemoryBarrierWithGroupSync();
for(uint s = WORKGROUP_SIZE / 2; s > 0u; s >>= 1)
{
if (groupIndex < s)
{
uint v = s + groupIndex;
set_heap_element(v, get_heap_element(v * 2) + get_heap_element(v * 2 + 1));
}
GroupMemoryBarrierWithGroupSync();
}
}
void reduce_prepass(uint dispatchThreadID)
{
// Initialize the packed sum
uint packedSum = 0;
// Loop through the 4 pairs to process
for (uint pairIdx = 0; pairIdx < 4; ++pairIdx)
{
// First element of the pair
uint64_t target_bits = pParams.bitFieldBuffer[dispatchThreadID * 8 + 2 * pairIdx];
uint32_t high = uint(target_bits >> 32);
uint32_t low = uint(target_bits);
uint elementC = countbits(high) + countbits(low);
// Second element of the pair
target_bits = pParams.bitFieldBuffer[dispatchThreadID * 8 + 2 * pairIdx + 1];
high = uint(target_bits >> 32);
low = uint(target_bits);
elementC += countbits(high) + countbits(low);
// Store in the right bits
packedSum |= (elementC << pairIdx * 8);
}
// Offset of the last level of the tree
const uint bufferOffset = last_level_offset();
// Store the result into the bitfield
pParams.cbtBuffer[bufferOffset + dispatchThreadID] = packedSum;
}
void reduce_first_pass(uint dispatchThreadID, uint groupIndex)
{
// Load the lowest level (and only the last level)
const uint level0Offset = OCBT_depth_offset[TREE_LAST_LEVEL] / 32;
for (uint e = 0; e < 4; ++e)
{
uint target_element = 4 * dispatchThreadID + e;
gs_cbtTree[level0Offset + target_element] = pParams.cbtBuffer[level0Offset + target_element];
}
GroupMemoryBarrierWithGroupSync();
// First we do a reduction until each lane has exactly one element to process
uint initial_pass_size = OCBT_LAST_LEVEL_SIZE / 2;
uint it, offset;
for (it = initial_pass_size / 512, offset = initial_pass_size; it > 1; it >>=1, offset >>=1)
{
uint minHeapID = offset + (dispatchThreadID * it);
uint maxHeapID = offset + ((dispatchThreadID + 1) * it);
for (uint heapID = minHeapID; heapID < maxHeapID; ++heapID)
{
set_heap_element(heapID, get_heap_element(heapID * 2) + get_heap_element(heapID * 2 + 1));
}
}
// Last pass needs to be atomic
uint heapID = offset + (dispatchThreadID * it);
set_heap_element_atomic(heapID, get_heap_element(heapID * 2) + get_heap_element(heapID * 2 + 1));
GroupMemoryBarrierWithGroupSync();
// Load the first reduced level
const uint level2Offset = OCBT_depth_offset[TREE_LAST_LEVEL - 1] / 32;
for (uint e = 0; e < 4; ++e)
{
uint target_element = 4 * dispatchThreadID + e;
pParams.cbtBuffer[level2Offset + target_element] = gs_cbtTree[level2Offset + target_element];
}
// Load the first reduced level
const uint level3Offset = OCBT_depth_offset[TREE_LAST_LEVEL - 2] / 32;
for (uint e = 0; e < 2; ++e)
{
uint target_element = 2 * dispatchThreadID + e;
pParams.cbtBuffer[level3Offset + target_element] = gs_cbtTree[level3Offset + target_element];
}
const uint level4Offset = OCBT_depth_offset[TREE_LAST_LEVEL - 3] / 32;
pParams.cbtBuffer[level4Offset + dispatchThreadID] = gs_cbtTree[level4Offset + dispatchThreadID];
const uint level5Offset = OCBT_depth_offset[TREE_LAST_LEVEL - 4] / 32;
if (groupIndex % 2 == 0)
pParams.cbtBuffer[level5Offset + dispatchThreadID / 2] = gs_cbtTree[level5Offset + dispatchThreadID / 2];
}
void reduce_second_pass(uint groupIndex)
{
// Load the lowest level (and only the last level)
const uint level0Offset = OCBT_depth_offset[9] / 32;
for (uint e = 0; e < 4; ++e)
{
uint target_element = 4 * groupIndex + e;
gs_cbtTree[level0Offset + target_element] = pParams.cbtBuffer[level0Offset + target_element];
}
GroupMemoryBarrierWithGroupSync();
// First we do a reduction until each lane has exactly one element to process
uint initial_pass_size = 256;
for (uint it = initial_pass_size / 64, offset = initial_pass_size; it > 0 ; it >>=1, offset >>=1)
{
uint minHeapID = offset + (groupIndex * it);
uint maxHeapID = offset + ((groupIndex + 1) * it);
for (uint heapID = minHeapID; heapID < maxHeapID; ++heapID)
{
set_heap_element(heapID, get_heap_element(heapID * 2) + get_heap_element(heapID * 2 + 1));
}
}
GroupMemoryBarrierWithGroupSync();
for(uint s = WORKGROUP_SIZE / 2; s > 0u; s >>= 1)
{
if (groupIndex < s)
{
uint v = s + groupIndex;
set_heap_element(v, get_heap_element(v * 2) + get_heap_element(v * 2 + 1));
}
GroupMemoryBarrierWithGroupSync();
}
// Make sure all the previous operations are done
GroupMemoryBarrierWithGroupSync();
// Load the bitfield to the LDS
for (uint e = 0; e < 5; ++e)
{
uint target_element = 5 * groupIndex + e;
if (target_element < 319)
pParams.cbtBuffer[target_element] = gs_cbtTree[target_element];
}
}
void reduce_no_bitfield(uint groupIndex)
{
// First we do a reduction until each lane has exactly one element to process
uint initial_pass_size = OCBT_NUM_ELEMENTS / WORKGROUP_SIZE;
for (uint it = initial_pass_size / 128, offset = OCBT_NUM_ELEMENTS / 128; it > 0 ; it >>=1, offset >>=1)
{
uint minHeapID = offset + (groupIndex * it);
uint maxHeapID = offset + ((groupIndex + 1) * it);
for (uint heapID = minHeapID; heapID < maxHeapID; ++heapID)
{
set_heap_element(heapID, get_heap_element(heapID * 2) + get_heap_element(heapID * 2 + 1));
}
}
GroupMemoryBarrierWithGroupSync();
for(uint s = WORKGROUP_SIZE / 2; s > 0u; s >>= 1)
{
if (groupIndex < s)
{
uint v = s + groupIndex;
set_heap_element(v, get_heap_element(v * 2) + get_heap_element(v * 2 + 1));
}
GroupMemoryBarrierWithGroupSync();
}
}
void clear_cbt(uint groupIndex)
{
for (uint v = 0; v < BUFFER_ELEMENT_PER_LANE; ++v)
{
uint target_element = BUFFER_ELEMENT_PER_LANE * groupIndex + v;
if (target_element < OCBT_TREE_NUM_SLOTS)
gs_cbtTree[target_element] = 0;
}
for (uint b = 0; b < BITFIELD_ELEMENT_PER_LANE; ++b)
{
uint target_element = BITFIELD_ELEMENT_PER_LANE * groupIndex + b;
if (target_element < OCBT_BITFIELD_NUM_SLOTS)
pParams.bitFieldBuffer[target_element] = 0;
}
GroupMemoryBarrierWithGroupSync();
}
// Importante note
// Depending on your target GPU architecture, the pattern used to load has a different performance behavior
// here is the best performant based on our tests:
// NVIDIA uint target_element = groupIndex + WORKGROUP_SIZE * e;
// AMD uint target_element = BUFFER_ELEMENT_PER_LANE * groupIndex + e;
void load_buffer_to_shared_memory(uint groupIndex)
{
// Load the bitfield to the LDS
for (uint e = 0; e < BUFFER_ELEMENT_PER_LANE; ++e)
{
#ifdef AMD
uint target_element = BUFFER_ELEMENT_PER_LANE * groupIndex + e;
#else
uint target_element = groupIndex + WORKGROUP_SIZE * e;
#endif
if (target_element < OCBT_TREE_NUM_SLOTS)
gs_cbtTree[target_element] = pParams.cbtBuffer[target_element];
}
GroupMemoryBarrierWithGroupSync();
}
void load_shared_memory_to_buffer(uint groupIndex)
{
// Make sure all the previous operations are done
GroupMemoryBarrierWithGroupSync();
// Load the bitfield to the LDS
for (uint e = 0; e < BUFFER_ELEMENT_PER_LANE; ++e)
{
#ifdef AMD
uint target_element = BUFFER_ELEMENT_PER_LANE * groupIndex + e;
#else
uint target_element = groupIndex + WORKGROUP_SIZE * e;
#endif
if (target_element < OCBT_TREE_NUM_SLOTS)
pParams.cbtBuffer[target_element] = gs_cbtTree[target_element];
}
}
void set_bit_atomic_buffer(uint bitID, bool state)
{
// Coordinates of the bit
uint32_t slot = bitID / 64;
uint32_t local_id = bitID % 64;
if (state)
InterlockedOr(pParams.bitFieldBuffer[slot], 1uLL << local_id);
else
InterlockedAnd(pParams.bitFieldBuffer[slot], ~(1uLL << local_id));
}
uint32_t bit_count_buffer()
{
return pParams.cbtBuffer[0];
}
File diff suppressed because it is too large Load Diff
+56
View File
@@ -0,0 +1,56 @@
import Common;
import Bisector;
struct GeometryCB
{
uint32_t totalNumElements;
uint32_t baseDepth;
uint32_t totalNumVertices;
};
struct DeformationCB
{
float4 patchSize;
float4 patchRoughness;
float choppiness;
int attenuation;
float amplification;
uint32_t patchFlags;
};
struct UpdateCB
{
float triangleSize;
uint32_t maxSubdivisionDepth;
float fov;
float farPlaneDistance;
}
struct ComputeParams
{
ConstantBuffer<GeometryCB> geometry;
ConstantBuffer<UpdateCB> update;
RWStructuredBuffer<float3> currentVertexBuffer;
StructuredBuffer<uint> indexedBisectorBuffer;
RWStructuredBuffer<uint> indirectDrawBuffer;
RWStructuredBuffer<uint64_t> heapIDBuffer;
RWStructuredBuffer<BisectorData> bisectorDataBuffer;
RWStructuredBuffer<uint> classificationBuffer;
RWStructuredBuffer<int> allocateBuffer;
RWStructuredBuffer<uint> indirectDispatchBuffer;
RWStructuredBuffer<uint3> neighboursBuffer;
RWStructuredBuffer<uint3> neighboursOutputBuffer;
RWStructuredBuffer<int> memoryBuffer;
RWStructuredBuffer<uint> cbtBuffer;
RWStructuredBuffer<uint64_t> bitFieldBuffer;
RWStructuredBuffer<int> propagateBuffer;
RWStructuredBuffer<uint> simplifyBuffer;
RWStructuredBuffer<uint> validationBuffer;
RWStructuredBuffer<uint> bisectorIndicesBuffer;
RWStructuredBuffer<uint> visibleBisectorIndices;
RWStructuredBuffer<uint> modifiedBisectorIndices;
RWStructuredBuffer<float3> lebPositionBuffer;
StructuredBuffer<float3x3> lebMatrixCache;
};
ParameterBlock<ComputeParams> pParams;
+44 -10
View File
@@ -22,6 +22,37 @@ using namespace Seele::Editor;
// make it global so it gets deleted last and automatically
static Gfx::OGraphics graphics;
struct Halfedge {
uint32 vertexID;
uint32 nextID;
uint32 prevID;
uint32 twinID;
};
Array<Halfedge> generateEdges() {
Array<UVector> indices = {UVector(0, 1, 4), UVector(4, 1, 5), UVector(1, 2, 5), UVector(5, 2, 6), UVector(2, 3, 6),
UVector(6, 3, 7), UVector(4, 5, 8), UVector(8, 5, 9), UVector(5, 6, 9), UVector(9, 6, 10),
UVector(6, 7, 10), UVector(10, 7, 11), UVector(8, 9, 12), UVector(12, 9, 13), UVector(9, 10, 13),
UVector(13, 10, 14), UVector(10, 11, 14), UVector(14, 11, 15)};
Array<Halfedge> edges;
for (auto ind : indices) {
uint32 baseIndex = edges.size();
edges.add(Halfedge{ind.x, baseIndex+1, baseIndex+2, UINT32_MAX});
edges.add(Halfedge{ind.y, baseIndex+2, baseIndex, UINT32_MAX});
edges.add(Halfedge{ind.z, baseIndex, baseIndex+1, UINT32_MAX});
}
for (uint32 i = 0; i < edges.size(); ++i) {
if (edges[i].twinID == UINT32_MAX) {
for (uint32 j = 0; j < edges.size(); ++j) {
if (edges[i].vertexID == edges[edges[j].nextID].vertexID && edges[edges[i].nextID].vertexID == edges[j].vertexID) {
edges[i].twinID = j;
edges[j].twinID = i;
}
}
}
}
return edges;
}
int main() {
std::string gameName = "MeshShadingDemo";
#ifdef WIN32
@@ -69,12 +100,15 @@ int main() {
// .filePath = sourcePath / "import/models/ship.fbx",
// .importPath = "ship",
// });
AssetImporter::importTexture(TextureImportArgs{
.filePath = sourcePath / "import/textures/azeroth.png",
});
AssetImporter::importTexture(TextureImportArgs{
.filePath = sourcePath / "import/textures/azeroth_height.png",
});
//AssetImporter::importTexture(TextureImportArgs{
// .filePath = sourcePath / "import/textures/azeroth.png",
//});
//AssetImporter::importTexture(TextureImportArgs{
// .filePath = sourcePath / "import/textures/azeroth_height.png",
//});
//AssetImporter::importTexture(TextureImportArgs{
// .filePath = sourcePath / "import/textures/wgen.png",
//});
// AssetImporter::importMesh(MeshImportArgs{
// .filePath = sourcePath / "import/models/after-the-rain-vr-sound/source/Whitechapel.glb",
// .importPath = "Whitechapel",
@@ -87,10 +121,10 @@ int main() {
// .filePath = sourcePath / "import/models/minecraft-medieval-city.fbx",
// .importPath = "minecraft",
// });
AssetImporter::importMesh(MeshImportArgs{
.filePath = sourcePath / "import/models/Volvo/Volvo.fbx",
.importPath = "Volvo",
});
// AssetImporter::importMesh(MeshImportArgs{
// .filePath = sourcePath / "import/models/Volvo/Volvo.fbx",
// .importPath = "Volvo",
// });
getThreadPool().waitIdle();
vd->commitMeshes();
WindowCreateInfo mainWindowInfo = {
+21 -21
View File
@@ -466,25 +466,25 @@ template <typename T, size_t N> struct StaticArray {
using reference = X&;
using pointer = X*;
IteratorBase(X* x = nullptr) : p(x) {}
reference operator*() const { return *p; }
pointer operator->() const { return p; }
inline bool operator!=(const IteratorBase& other) { return p != other.p; }
inline bool operator==(const IteratorBase& other) { return p == other.p; }
IteratorBase& operator++() {
constexpr IteratorBase(X* x = nullptr) : p(x) {}
constexpr reference operator*() const { return *p; }
constexpr pointer operator->() const { return p; }
constexpr bool operator!=(const IteratorBase& other) { return p != other.p; }
constexpr bool operator==(const IteratorBase& other) { return p == other.p; }
constexpr IteratorBase& operator++() {
p++;
return *this;
}
IteratorBase operator++(int) {
constexpr IteratorBase operator++(int) {
IteratorBase tmp(*this);
++*this;
return tmp;
}
IteratorBase& operator--() {
constexpr IteratorBase& operator--() {
p--;
return *this;
}
IteratorBase operator--(int) {
constexpr IteratorBase operator--(int) {
IteratorBase tmp(*this);
--*this;
return tmp;
@@ -507,18 +507,18 @@ template <typename T, size_t N> struct StaticArray {
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
StaticArray() {
constexpr StaticArray() {
beginIt = iterator(_data);
endIt = iterator(_data + N);
}
StaticArray(T value) {
constexpr StaticArray(T value) {
for (size_t i = 0; i < N; ++i) {
_data[i] = value;
}
beginIt = iterator(_data);
endIt = iterator(_data + N);
}
StaticArray(std::initializer_list<T> init) {
constexpr StaticArray(std::initializer_list<T> init) {
auto beg = init.begin();
for (size_t i = 0; i < N; ++i) {
_data[i] = *beg;
@@ -527,11 +527,11 @@ template <typename T, size_t N> struct StaticArray {
}
}
}
~StaticArray() {}
constexpr ~StaticArray() {}
inline size_type size() const { return N; }
inline pointer data() { return _data; }
inline const_pointer data() const { return _data; }
constexpr size_type size() const { return N; }
constexpr pointer data() { return _data; }
constexpr const_pointer data() const { return _data; }
template <typename I> constexpr reference operator[](I index) noexcept { return operator[](static_cast<size_t>(index)); }
template <typename I> constexpr const_reference operator[](I index) const noexcept { return operator[](static_cast<size_t>(index)); }
constexpr reference operator[](size_type index) noexcept {
@@ -542,13 +542,13 @@ template <typename T, size_t N> struct StaticArray {
assert(index < N);
return _data[index];
}
iterator begin() { return beginIt; }
iterator end() { return endIt; }
const_iterator begin() const { return beginIt; }
const_iterator end() const { return beginIt; }
constexpr iterator begin() { return beginIt; }
constexpr iterator end() { return endIt; }
constexpr const_iterator begin() const { return beginIt; }
constexpr const_iterator end() const { return beginIt; }
private:
T _data[N];
T _data[N] = {T()};
iterator beginIt;
iterator endIt;
};
+797
View File
@@ -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; }
+505
View File
@@ -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
+11
View File
@@ -0,0 +1,11 @@
target_sources(Engine
PRIVATE
CBT.h
CBT.cpp
)
target_sources(Engine
PUBLIC FILE_SET HEADERS
FILES
CBT.h
)
+2
View File
@@ -1,3 +1,5 @@
add_subdirectory(CBT/)
target_sources(Engine
PRIVATE
Buffer.h
+2
View File
@@ -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)
+1
View File
@@ -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;
+2
View File
@@ -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
+1 -1
View File
@@ -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)
+5 -4
View File
@@ -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
{
@@ -250,7 +249,7 @@ void BasePass::render() {
}
//commands.add(waterRenderer->render(viewParamsSet));
// commands.add(terrainRenderer->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
{
+1 -1
View File
@@ -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);
+13 -1
View File
@@ -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,
});
}
}
tilesBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
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 = sizeof(TerrainTile) * payloads.size(),
.data = (uint8*)payloads.data(),
.size = bufferSize,
.data = (uint8*)cbt.rawBuffer(i),
},
.numElements = payloads.size(),
.name = "TilesBuffer",
.name = "GPUCBT",
});
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.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);
}
plainMesh.totalNumElements = cpuMesh.totalNumElements;
plainMesh.numBaseVertices = (uint32)cpuMesh.basePoints.size();
plainMesh.baseDepth = cpuMesh.minimalDepth;
sampler = graphics->createSampler(SamplerCreateInfo{});
layout = graphics->createDescriptorLayout("pTerrainData");
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = 0,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER,
plainMesh.heapIDBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint64) * cpuMesh.totalNumElements,
.data = (uint8*)cpuMesh.heapIDArray.data(),
},
.name = "HeapID",
});
layout->addDescriptorBinding(Gfx::DescriptorBinding{
.binding = 1,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
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);
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 = 2,
.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 = 3,
.descriptorType = Gfx::SE_DESCRIPTOR_TYPE_SAMPLER,
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->create();
pipelineLayout = graphics->createPipelineLayout("TerrainLayout");
pipelineLayout->addDescriptorLayout(viewParamsLayout);
pipelineLayout->addDescriptorLayout(layout);
ShaderCompilationInfo s{
.name = "TerrainShaders",
plainMesh.classificationBuffer = graphics->createShaderBuffer(ShaderBufferCreateInfo{
.sourceData =
{
.size = sizeof(uint32) * (2 + cpuMesh.totalNumElements * 2),
},
.name = "Classification",
});
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(),
@@ -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",
});
}
+1 -1
View File
@@ -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() {
+7 -11
View File
@@ -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() {}
+9
View File
@@ -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 = {
+2
View File
@@ -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;
+25
View File
@@ -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()) {
+1
View File
@@ -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;
+17 -4
View File
@@ -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, &region);
}
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,
+2
View File
@@ -79,6 +79,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;
virtual Gfx::OTopLevelAS createTopLevelAccelerationStructure(const Gfx::TopLevelASCreateInfo& createInfo) override;
+2 -2
View File
@@ -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();
+1 -1
View File
@@ -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) {
+44 -18
View File
@@ -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();
+4 -4
View File
@@ -1,14 +1,14 @@
i = 12
i = 4
positions = []
for x in range(i):
for y in range(i):
positions.append(f"float2({x}.0f / 11, {y}.0f / 11)")
positions.append(f"Vector({x}.0f / {i-1}, 0, {y}.0f / {i-1})")
indices = []
for y in range(i - 1):
for x in range(i - 1):
indices.append(f'uint3({(x) + i * (y)}, {(x + 1) + i * (y)}, {(x) + i * (y + 1)})')
indices.append(f'uint3({(x) + i * (y + 1)}, {(x + 1) + i * (y)}, {(x + 1) + i * (y + 1)})')
indices.append(f'UVector3({(x) + i * (y)}, {(x + 1) + i * (y)}, {(x) + i * (y + 1)})')
indices.append(f'UVector3({(x) + i * (y + 1)}, {(x + 1) + i * (y)}, {(x + 1) + i * (y + 1)})')
print(f"Dim {i}")
print(len(positions))
print(len(indices))