diff --git a/WickedEngine/ShaderInterop_Raytracing.h b/WickedEngine/ShaderInterop_Raytracing.h index 9288a1736..46be0f3c9 100644 --- a/WickedEngine/ShaderInterop_Raytracing.h +++ b/WickedEngine/ShaderInterop_Raytracing.h @@ -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) diff --git a/WickedEngine/bvh_primitivesCS.hlsl b/WickedEngine/bvh_primitivesCS.hlsl index d17fddf26..d1ca5ef49 100644 --- a/WickedEngine/bvh_primitivesCS.hlsl +++ b/WickedEngine/bvh_primitivesCS.hlsl @@ -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. diff --git a/WickedEngine/raytrace_closesthitCS.hlsl b/WickedEngine/raytrace_closesthitCS.hlsl index 04891d02d..d33b62b0c 100644 --- a/WickedEngine/raytrace_closesthitCS.hlsl +++ b/WickedEngine/raytrace_closesthitCS.hlsl @@ -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 } diff --git a/WickedEngine/raytrace_kickjobsCS.hlsl b/WickedEngine/raytrace_kickjobsCS.hlsl index 1f768e1a1..dc6ca71d9 100644 --- a/WickedEngine/raytrace_kickjobsCS.hlsl +++ b/WickedEngine/raytrace_kickjobsCS.hlsl @@ -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); diff --git a/WickedEngine/raytrace_launchCS.hlsl b/WickedEngine/raytrace_launchCS.hlsl index c5e4b841b..5cc9d0908 100644 --- a/WickedEngine/raytrace_launchCS.hlsl +++ b/WickedEngine/raytrace_launchCS.hlsl @@ -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); } } diff --git a/WickedEngine/raytrace_shadeCS.hlsl b/WickedEngine/raytrace_shadeCS.hlsl index e97de24cc..d796fd97b 100644 --- a/WickedEngine/raytrace_shadeCS.hlsl +++ b/WickedEngine/raytrace_shadeCS.hlsl @@ -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 { diff --git a/WickedEngine/raytrace_tilesortCS.hlsl b/WickedEngine/raytrace_tilesortCS.hlsl index 92781c567..149b835a9 100644 --- a/WickedEngine/raytrace_tilesortCS.hlsl +++ b/WickedEngine/raytrace_tilesortCS.hlsl @@ -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); diff --git a/WickedEngine/raytracingHF.hlsli b/WickedEngine/raytracingHF.hlsli index 1a26e45c4..d2d0c68a6 100644 --- a/WickedEngine/raytracingHF.hlsli +++ b/WickedEngine/raytracingHF.hlsli @@ -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; diff --git a/WickedEngine/wiRenderer.cpp b/WickedEngine/wiRenderer.cpp index 4734db71f..fe20a0459 100644 --- a/WickedEngine/wiRenderer.cpp +++ b/WickedEngine/wiRenderer.cpp @@ -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); diff --git a/WickedEngine/wiRenderer.h b/WickedEngine/wiRenderer.h index 158048366..de790ddf1 100644 --- a/WickedEngine/wiRenderer.h +++ b/WickedEngine/wiRenderer.h @@ -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 diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 7b130cd77..f34ee2d6a 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -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()