#pragma only_renderers d3d11 vulkan metal glcore
#define UNIFIED_RT_BACKEND_COMPUTE
#define UNIFIED_RT_GROUP_SIZE_X 16
#define UNIFIED_RT_GROUP_SIZE_Y 8
#include "ExpansionHelpers.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/UnifiedRayTracing/CommonStructs.hlsl"
// Compact an instance GBuffer to a buffer of non-empty texel indices.
// The output buffer has non-empty texels indices written into it. The number of texels written is stored in g_CompactedBufferLength.
// g_CompactedBufferLength must be initialized to 0 before calling this kernel.
#pragma kernel CompactGBuffer
[numthreads(64,1,1)]
void CompactGBuffer(uint3 id : SV_DispatchThreadID)
{
    CompactGBufferInternal(id.x);
}

uint DivUp(uint x, uint y)
{
    return uint((x + (int)y - 1) / (int)y);
}

// Populate the indirect dispatch buffer for the accumulation shader. Dimensions are in threads.
int g_ExpandedTexelSampleWidth;
int g_ThreadGroupSizeX;
RWStructuredBuffer<uint> g_AccumulationDispatchBuffer;
#pragma kernel PopulateAccumulationDispatch
[numthreads(8,1,1)]
void PopulateAccumulationDispatch(uint3 id : SV_DispatchThreadID)
{
    if (id.x >= 1)
        return;
    const uint dimX = uint(g_ExpandedTexelSampleWidth) * g_CompactedGBufferLength[0];
    g_AccumulationDispatchBuffer[0] = dimX;
    g_AccumulationDispatchBuffer[1] = 1;
    g_AccumulationDispatchBuffer[2] = 1;
}

// Populate the indirect dispatch buffer for the clear shader.
RWStructuredBuffer<uint> g_ClearDispatchBuffer;
#pragma kernel PopulateClearDispatch
[numthreads(8,1,1)]
void PopulateClearDispatch(uint3 id : SV_DispatchThreadID)
{
    if (id.x >= 1)
        return;
    const uint dimX = uint(g_ExpandedTexelSampleWidth) * g_CompactedGBufferLength[0];
    g_ClearDispatchBuffer[0] = DivUp(dimX, uint(g_ThreadGroupSizeX));
    g_ClearDispatchBuffer[1] = 1;
    g_ClearDispatchBuffer[2] = 1;
}

// Populate the indirect dispatch buffer for the copy shader.
RWStructuredBuffer<uint> g_CopyDispatchBuffer;
#pragma kernel PopulateCopyDispatch
[numthreads(8,1,1)]
void PopulateCopyDispatch(uint3 id : SV_DispatchThreadID)
{
    if (id.x >= 1)
        return;
    const uint dimX = g_CompactedGBufferLength[0];
    g_CopyDispatchBuffer[0] = DivUp(dimX, uint(g_ThreadGroupSizeX));
    g_CopyDispatchBuffer[1] = 1;
    g_CopyDispatchBuffer[2] = 1;
}

// Populate the indirect dispatch buffer for the reduce shader.
RWStructuredBuffer<uint> g_ReduceDispatchBuffer;
#pragma kernel PopulateReduceDispatch
[numthreads(8,1,1)]
void PopulateReduceDispatch(uint3 id : SV_DispatchThreadID)
{
    if (id.x >= 1)
        return;
    const uint dimX = uint(g_ExpandedTexelSampleWidth) * g_CompactedGBufferLength[0];
    g_ReduceDispatchBuffer[0] = DivUp(dimX, uint(g_ThreadGroupSizeX));
    g_ReduceDispatchBuffer[1] = 1;
    g_ReduceDispatchBuffer[2] = 1;
}

StructuredBuffer<float4> g_SourceBuffer;
RWTexture2D<float4> g_DestinationTexture;
int g_SourceStride;
int g_DestinationX;
int g_DestinationY;
#pragma kernel AdditivelyCopyCompactedTo2D
[numthreads(64,1,1)]
void AdditivelyCopyCompactedTo2D(uint3 id : SV_DispatchThreadID)
{
    if (id.x >= uint(g_CompactedGBufferLength[0]))
        return;
    uint linearChunkOffset = g_ChunkOffsetX + g_ChunkOffsetY * uint(g_InstanceWidth);
    uint linearTexelIndex = g_CompactedGBuffer[id.x] + linearChunkOffset;
    uint2 texelIndex = uint2(linearTexelIndex % uint(g_InstanceWidth), linearTexelIndex / uint(g_InstanceWidth)) + uint2(uint(g_DestinationX), uint(g_DestinationY));
    g_DestinationTexture[texelIndex] += g_SourceBuffer[id.x*uint(g_SourceStride)];
}

// Sums the leftmost value of each group to the left
// The input buffer must be a multiple of g_BinaryGroupSize
RWStructuredBuffer<float4> g_Float4Buffer;
#pragma kernel BinaryGroupSumLeft
int g_BinaryBufferSize;
int g_BinaryGroupSize;
[numthreads(64,1,1)]
void BinaryGroupSumLeft(uint3 id : SV_DispatchThreadID)
{
    if (id.x % (2 * uint(g_BinaryGroupSize)) != 0 || id.x + uint(g_BinaryGroupSize) >= uint(g_BinaryBufferSize))
        return;
    g_Float4Buffer[id.x] += g_Float4Buffer[id.x + g_BinaryGroupSize];
}

int g_Float4BufferLength;
#pragma kernel ClearFloat4Buffer
[numthreads(64,1,1)]
void ClearFloat4Buffer(uint3 id : SV_DispatchThreadID)
{
    if (id.x >= uint(g_Float4BufferLength))
        return;
    g_Float4Buffer[id.x] = 0.0f;
}