/*
===========================================================================
Copyright (C) 2024 Gian 'myT' Schellenbaum
This file is part of Challenge Quake 3 (CNQ3).
Challenge Quake 3 is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
Challenge Quake 3 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Challenge Quake 3. If not, see .
===========================================================================
*/
// outputs min/max depth values for mip levels 0 to 7 in one go
#include "common.hlsli"
cbuffer RootConstants
{
uint destTextureIndex0;
uint destTextureIndex1;
uint destTextureIndex2;
uint destTextureIndex3;
uint destTextureIndex4;
uint destTextureIndex5;
uint destTextureIndex6;
uint depthTextureIndex;
uint depthSamplerIndex;
}
groupshared float2 s_depth[32][32];
void ProcessMip(uint threadCount, uint scale, uint destTextureIndex, uint3 gtid, uint3 gid, bool writeToSM)
{
if(gtid.x < threadCount && gtid.y < threadCount)
{
uint2 baseCoords = gtid.xy * scale * 2;
uint4 coords = uint4(baseCoords, baseCoords + scale.xx);
float2 v0 = s_depth[coords.x][coords.y];
float2 v1 = s_depth[coords.x][coords.w];
float2 v2 = s_depth[coords.z][coords.y];
float2 v3 = s_depth[coords.z][coords.w];
float minZ = min4(v0.x, v1.x, v2.x, v3.x);
float maxZ = max4(v0.y, v1.y, v2.y, v3.y);
float2 minMaxZ = float2(minZ, maxZ);
if(writeToSM)
{
s_depth[coords.x][coords.y] = minMaxZ;
}
RWTexture2D dst = ResourceDescriptorHeap[destTextureIndex];
dst[gid.xy * threadCount + gtid.xy] = minMaxZ;
}
}
[numthreads(32, 32, 1)]
void cs(uint3 dtid : SV_DispatchThreadID, uint3 gtid : SV_GroupThreadID, uint3 gid : SV_GroupID)
{
Texture2D depthTexture = ResourceDescriptorHeap[depthTextureIndex];
SamplerState depthSampler = SamplerDescriptorHeap[depthSamplerIndex];
RWTexture2D dst0 = ResourceDescriptorHeap[destTextureIndex0];
RWTexture2D dst1 = ResourceDescriptorHeap[destTextureIndex1];
float2 depthTextureSize = float2(GetTextureSize(depthTexture));
// GatherRed order: x=(0, 1), y=(1, 1), z=(1, 0), w=(0, 0)
float2 tc = (float2(dtid.xy * 2) + float2(0.5, 0.5)) / depthTextureSize;
float4 mip0 = depthTexture.GatherRed(depthSampler, tc);
float minZ = min4(mip0.x, mip0.y, mip0.z, mip0.w);
float maxZ = max4(mip0.x, mip0.y, mip0.z, mip0.w);
float2 minMaxZ = float2(minZ, maxZ);
s_depth[gtid.x][gtid.y] = minMaxZ;
dst0[dtid.xy * 2 + int2(0, 0)] = mip0.ww;
dst0[dtid.xy * 2 + int2(0, 1)] = mip0.xx;
dst0[dtid.xy * 2 + int2(1, 0)] = mip0.zz;
dst0[dtid.xy * 2 + int2(1, 1)] = mip0.yy;
dst1[dtid.xy] = minMaxZ;
GroupMemoryBarrierWithGroupSync();
ProcessMip(16, 1, destTextureIndex2, gtid, gid, true);
GroupMemoryBarrierWithGroupSync();
ProcessMip(8, 2, destTextureIndex3, gtid, gid, true);
GroupMemoryBarrierWithGroupSync();
ProcessMip(4, 4, destTextureIndex4, gtid, gid, true);
GroupMemoryBarrierWithGroupSync();
ProcessMip(2, 8, destTextureIndex5, gtid, gid, true);
GroupMemoryBarrierWithGroupSync();
ProcessMip(1, 16, destTextureIndex6, gtid, gid, false);
}