resurrected global ray sorting + refactor
This commit is contained in:
@@ -8,7 +8,11 @@ static const uint RAYTRACING_TRACE_GROUPSIZE = 64;
|
||||
static const uint RAYTRACING_SORT_GROUPSIZE = 1024;
|
||||
|
||||
static const uint RAYTRACE_INDIRECT_OFFSET_TRACE = 0;
|
||||
static const uint RAYTRACE_INDIRECT_OFFSET_SORT = 4 * 3;
|
||||
static const uint RAYTRACE_INDIRECT_OFFSET_TILESORT = 4 * 3;
|
||||
|
||||
// Whether to sort global ray buffer or only smaller bundles (tiles).
|
||||
// The global sorting is slower, but on some GPUs, it is still worth to to this because the raytracing will be faster (more coherent)
|
||||
#define RAYTRACING_SORT_GLOBAL
|
||||
|
||||
|
||||
CBUFFER(RaytracingCB, CBSLOT_RENDERER_TRACED)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "globals.hlsli"
|
||||
#include "ShaderInterop_BVH.h"
|
||||
#include "ShaderInterop_Raytracing.h"
|
||||
|
||||
// This shader builds scene triangle data and performs BVH classification:
|
||||
// - This shader is run per object.
|
||||
|
||||
@@ -9,9 +9,13 @@ STRUCTUREDBUFFER(rayBuffer_READ, RaytracingStoredRay, TEXSLOT_ONDEMAND9);
|
||||
|
||||
RWRAWBUFFER(counterBuffer_WRITE, 0);
|
||||
RWSTRUCTUREDBUFFER(rayBuffer_WRITE, RaytracingStoredRay, 1);
|
||||
#ifdef RAYTRACING_SORT_GLOBAL
|
||||
RWSTRUCTUREDBUFFER(rayIndexBuffer_WRITE, uint, 2);
|
||||
RWSTRUCTUREDBUFFER(raySortBuffer_WRITE, float, 3);
|
||||
#endif // RAYTRACING_SORT_GLOBAL
|
||||
|
||||
// This enables reduced atomics into global memory.
|
||||
//#define ADVANCED_ALLOCATION
|
||||
#define ADVANCED_ALLOCATION
|
||||
|
||||
#ifdef ADVANCED_ALLOCATION
|
||||
static const uint GroupActiveRayMaskBucketCount = RAYTRACING_TRACE_GROUPSIZE / 32;
|
||||
@@ -83,6 +87,10 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex )
|
||||
uint dest;
|
||||
counterBuffer_WRITE.InterlockedAdd(0, 1, dest);
|
||||
rayBuffer_WRITE[dest] = CreateStoredRay(ray);
|
||||
#ifdef RAYTRACING_SORT_GLOBAL
|
||||
rayIndexBuffer_WRITE[dest] = dest;
|
||||
raySortBuffer_WRITE[dest] = CreateRaySortCode(ray);
|
||||
#endif // RAYTRACING_SORT_GLOBAL
|
||||
#endif // ADVANCED_ALLOCATION
|
||||
}
|
||||
}
|
||||
@@ -136,6 +144,10 @@ void main( uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex )
|
||||
|
||||
const uint dest = GroupRayWriteOffset + activePrefixSum - 1; // -1 because activePrefixSum includes current thread, but arrays start from 0!
|
||||
rayBuffer_WRITE[dest] = CreateStoredRay(ray);
|
||||
#ifdef RAYTRACING_SORT_GLOBAL
|
||||
rayIndexBuffer_WRITE[dest] = dest;
|
||||
raySortBuffer_WRITE[dest] = CreateRaySortCode(ray);
|
||||
#endif // RAYTRACING_SORT_GLOBAL
|
||||
}
|
||||
#endif // ADVANCED_ALLOCATION
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ void main( uint3 DTid : SV_DispatchThreadID )
|
||||
|
||||
// write the indirect dispatch arguments:
|
||||
indirectBuffer.Store3(RAYTRACE_INDIRECT_OFFSET_TRACE, uint3((rayCount + RAYTRACING_TRACE_GROUPSIZE - 1) / RAYTRACING_TRACE_GROUPSIZE, 1, 1));
|
||||
indirectBuffer.Store3(RAYTRACE_INDIRECT_OFFSET_SORT, uint3((rayCount + RAYTRACING_SORT_GROUPSIZE - 1) / RAYTRACING_SORT_GROUPSIZE, 1, 1));
|
||||
indirectBuffer.Store3(RAYTRACE_INDIRECT_OFFSET_TILESORT, uint3((rayCount + RAYTRACING_SORT_GROUPSIZE - 1) / RAYTRACING_SORT_GROUPSIZE, 1, 1));
|
||||
|
||||
// Reset counter buffer for this step:
|
||||
counterBuffer_WRITE.Store(0, 0);
|
||||
|
||||
@@ -14,10 +14,11 @@ void main( uint3 DTid : SV_DispatchThreadID )
|
||||
|
||||
// Create starting ray:
|
||||
Ray ray = CreateCameraRay(uv);
|
||||
ray.pixelID = flatten2D(DTid.xy, xTraceResolution.xy);
|
||||
ray.pixelID = (DTid.x & 0xFFFF) | ((DTid.y & 0xFFFF) << 16);
|
||||
|
||||
// The launch writes each ray to the pixel location:
|
||||
rayIndexBuffer[ray.pixelID] = ray.pixelID;
|
||||
rayBuffer[ray.pixelID] = CreateStoredRay(ray);
|
||||
const uint rayIndex = flatten2D(DTid.xy, xTraceResolution.xy);
|
||||
rayIndexBuffer[rayIndex] = rayIndex;
|
||||
rayBuffer[rayIndex] = CreateStoredRay(ray);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,14 +18,12 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
const uint rayIndex = rayIndexBuffer_READ[DTid.x];
|
||||
//const uint rayIndex = DTid.x;
|
||||
Ray ray = LoadRay(rayBuffer[rayIndex]);
|
||||
|
||||
// Compute real pixel coords from flattened:
|
||||
uint2 coords2D = unflatten2D(ray.pixelID, xTraceResolution.xy);
|
||||
uint2 pixel = uint2(ray.pixelID & 0xFFFF, (ray.pixelID >> 16) & 0xFFFF);
|
||||
|
||||
if (any(ray.energy))
|
||||
{
|
||||
float3 bounceResult = 0;
|
||||
float2 uv = float2((coords2D + xTracePixelOffset) * xTraceResolution_rcp.xy * 2.0f - 1.0f) * float2(1, -1);
|
||||
float2 uv = float2((pixel + xTracePixelOffset) * xTraceResolution_rcp.xy * 2.0f - 1.0f) * float2(1, -1);
|
||||
float seed = xTraceRandomSeed;
|
||||
|
||||
TriangleData tri = TriangleData_Unpack(primitiveBuffer[ray.primitiveID], primitiveDataBuffer[ray.primitiveID]);
|
||||
@@ -282,12 +280,12 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
// Pre-clear result texture for first bounce and first accumulation sample:
|
||||
if (xTraceUserData.x == 1)
|
||||
{
|
||||
resultTexture[coords2D] = 0;
|
||||
resultTexture[pixel] = 0;
|
||||
}
|
||||
if (!any(ray.energy) || xTraceUserData.y == 1)
|
||||
{
|
||||
// If the ray is killed or last bounce, we write to accumulation texture:
|
||||
resultTexture[coords2D] = lerp(resultTexture[coords2D], float4(ray.color, 1), xTraceAccumulationFactor);
|
||||
resultTexture[pixel] = lerp(resultTexture[pixel], float4(ray.color, 1), xTraceAccumulationFactor);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -45,7 +45,7 @@ void main(uint3 DTid : SV_DispatchThreadID, uint groupIndex : SV_GroupIndex)
|
||||
[branch]
|
||||
if (DTid.x < counterBuffer_READ.Load(0))
|
||||
{
|
||||
sortcode = rayBuffer_READ[DTid.x].primitiveID;
|
||||
sortcode = CreateRaySortCode(LoadRay(rayBuffer_READ[DTid.x]));
|
||||
}
|
||||
|
||||
Array[groupIndex] = uint2(sortcode, DTid.x);
|
||||
|
||||
@@ -36,6 +36,28 @@ struct Ray
|
||||
}
|
||||
};
|
||||
|
||||
inline uint CreateRaySortCode(in Ray ray)
|
||||
{
|
||||
// Sorting purely based on morton code works best so far:
|
||||
return morton3D((ray.origin - g_xFrame_WorldBoundsMin) * g_xFrame_WorldBoundsExtents_rcp);
|
||||
|
||||
//return ray.primitiveID;
|
||||
|
||||
//uint hash = 0;
|
||||
|
||||
//// quantize direction [-1; 1] on 8x4x8 grid (3 + 2 + 3 = 8 bits):
|
||||
//hash |= (uint)clamp(ray.direction.x * 4 + 4, 0, 7) << 0;
|
||||
//hash |= (uint)clamp(ray.direction.y * 2 + 2, 0, 3) << 3;
|
||||
//hash |= (uint)clamp(ray.direction.z * 4 + 4, 0, 7) << 5;
|
||||
|
||||
//// quantize origin [0, 1] on 256x256x256 grid (8 bits per component):
|
||||
//const float3 origin = (ray.origin - g_xFrame_WorldBoundsMin) * g_xFrame_WorldBoundsExtents_rcp;
|
||||
//hash |= ((uint)abs(origin.x * 255) % 256) << 8;
|
||||
//hash |= ((uint)abs(origin.x * 255) % 256) << 16;
|
||||
//hash |= ((uint)abs(origin.x * 255) % 256) << 24;
|
||||
|
||||
//return (float)hash;
|
||||
}
|
||||
inline RaytracingStoredRay CreateStoredRay(in Ray ray)
|
||||
{
|
||||
RaytracingStoredRay storedray;
|
||||
|
||||
@@ -7334,6 +7334,13 @@ void RayBuffers::Create(GraphicsDevice* device, uint32_t newRayCapacity)
|
||||
device->CreateBuffer(&desc, nullptr, &rayIndexBuffer[1]);
|
||||
device->SetName(&rayIndexBuffer[1], "rayIndexBuffer[1]");
|
||||
|
||||
#ifdef RAYTRACING_SORT_GLOBAL
|
||||
desc.StructureByteStride = sizeof(float); // sorting needs float now
|
||||
desc.ByteWidth = desc.StructureByteStride * rayCapacity;
|
||||
device->CreateBuffer(&desc, nullptr, &raySortBuffer);
|
||||
device->SetName(&raySortBuffer, "raySortBuffer");
|
||||
#endif // RAYTRACING_SORT_GLOBAL
|
||||
|
||||
desc.StructureByteStride = sizeof(RaytracingStoredRay);
|
||||
desc.ByteWidth = desc.StructureByteStride * rayCapacity;
|
||||
device->CreateBuffer(&desc, nullptr, &rayBuffer[0]);
|
||||
@@ -7496,6 +7503,10 @@ void RayTraceScene(
|
||||
// Sort rays to achieve more coherency:
|
||||
{
|
||||
device->EventBegin("Ray Sorting", cmd);
|
||||
|
||||
#ifdef RAYTRACING_SORT_GLOBAL
|
||||
wiGPUSortLib::Sort(rayBuffers->rayCapacity, rayBuffers->raySortBuffer, rayBuffers->rayCountBuffer[__readBufferID], 0, rayBuffers->rayIndexBuffer[__readBufferID], cmd);
|
||||
#else
|
||||
device->BindComputeShader(&computeShaders[CSTYPE_RAYTRACE_TILESORT], cmd);
|
||||
|
||||
const GPUResource* res[] = {
|
||||
@@ -7508,10 +7519,11 @@ void RayTraceScene(
|
||||
};
|
||||
device->BindUAVs(CS, uavs, 0, arraysize(uavs), cmd);
|
||||
|
||||
device->DispatchIndirect(&indirectBuffer, RAYTRACE_INDIRECT_OFFSET_SORT, cmd);
|
||||
device->DispatchIndirect(&indirectBuffer, RAYTRACE_INDIRECT_OFFSET_TILESORT, cmd);
|
||||
|
||||
device->Barrier(&GPUBarrier::Memory(), 1, cmd);
|
||||
device->UnbindUAVs(0, arraysize(uavs), cmd);
|
||||
#endif // RAYTRACING_SORT_GLOBAL
|
||||
|
||||
device->EventEnd(cmd);
|
||||
}
|
||||
@@ -7578,6 +7590,10 @@ void RayTraceScene(
|
||||
const GPUResource* uavs[] = {
|
||||
&rayBuffers->rayCountBuffer[__writeBufferID],
|
||||
&rayBuffers->rayBuffer[__writeBufferID],
|
||||
#ifdef RAYTRACING_SORT_GLOBAL
|
||||
&rayBuffers->rayIndexBuffer[__writeBufferID],
|
||||
&rayBuffers->raySortBuffer,
|
||||
#endif // RAYTRACING_SORT_GLOBAL
|
||||
};
|
||||
device->BindUAVs(CS, uavs, 0, arraysize(uavs), cmd);
|
||||
|
||||
|
||||
@@ -316,6 +316,7 @@ namespace wiRenderer
|
||||
wiGraphics::GPUBuffer rayBuffer[2];
|
||||
wiGraphics::GPUBuffer rayIndexBuffer[2];
|
||||
wiGraphics::GPUBuffer rayCountBuffer[2];
|
||||
wiGraphics::GPUBuffer raySortBuffer;
|
||||
void Create(wiGraphics::GraphicsDevice* device, uint32_t newRayCapacity);
|
||||
};
|
||||
// Generate rays for every pixel of the internal resolution
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace wiVersion
|
||||
// minor features, major updates
|
||||
const int minor = 36;
|
||||
// minor bug fixes, alterations, refactors, updates
|
||||
const int revision = 46;
|
||||
const int revision = 47;
|
||||
|
||||
|
||||
long GetVersion()
|
||||
|
||||
Reference in New Issue
Block a user