#pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch // Each #kernel tells which function to compile; you can have many kernels #pragma kernel MipMin KERNEL_SIZE=8 #pragma kernel MipMin2 KERNEL_SIZE=8 #pragma kernel MipMinOdd KERNEL_SIZE=8 #pragma multi_compile _ STEREO_INSTANCING_ON STEREO_MULTIVIEW_ON #pragma multi_compile_local _ SRV_SOURCE #pragma multi_compile_local _ MIN_AND_MAX #if defined(STEREO_INSTANCING_ON) #define UNITY_STEREO_INSTANCING_ENABLED #endif #if defined(STEREO_MULTIVIEW_ON) #define UNITY_STEREO_MULTIVIEW_ENABLED #endif #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" // Create a RenderTexture with enableRandomWrite flag and set it // with cs.SetTexture #if defined(MIN_AND_MAX) #define float1or2 float2 #else #define float1or2 float #endif #if defined(SRV_SOURCE) TEXTURE2D_X_FLOAT(_MipSource); #else RW_TEXTURE2D_X(float1or2, _MipSource); #endif RW_TEXTURE2D_X(float1or2, _MipDest); RW_TEXTURE2D_X(float1or2, _MipDest2); #if defined(STEREO_INSTANCING_ON) || defined(STEREO_MULTIVIEW_ON) #define COORD_DEPTH(uv) (uv).xyz #else #define COORD_DEPTH(uv) (uv).xy #endif #if defined(SRV_SOURCE) #if UNITY_REVERSED_Z #if defined(MIN_AND_MAX) #define XR_MESH_CORRECTION(d) float2(d.x == 1 ? 0 : d.x, d.y == 1 ? 1 : d.y) #else #define XR_MESH_CORRECTION(d) (d.x == 1 ? 0 : d.x) #endif #else #if defined(MIN_AND_MAX) #define XR_MESH_CORRECTION(d) float2(d.x == 0 ? 1 : d.x, d.y == 0 ? 0 : d.y) #else #define XR_MESH_CORRECTION(d) (d.x == 0 ? 1 : d.x) #endif #endif #else #define XR_MESH_CORRECTION(d) d #endif #if !defined(MIN_AND_MAX) #if defined(SRV_SOURCE) #if defined(STEREO_INSTANCING_ON) || defined(STEREO_MULTIVIEW_ON) #define MIPSOURCE(uv) XR_MESH_CORRECTION((_MipSource.Load(int4(uv.xyz, 0)).r)) #else #define MIPSOURCE(uv) _MipSource.Load(int3(uv.xy, 0)).r #endif #else #define MIPSOURCE(uv) _MipSource[uv].r #endif #else #if defined(SRV_SOURCE) #if defined(STEREO_INSTANCING_ON) || defined(STEREO_MULTIVIEW_ON) #define MIPSOURCE(uv) XR_MESH_CORRECTION((_MipSource.Load(int4(uv.xyz, 0)).rr)) #else #define MIPSOURCE(uv) _MipSource.Load(int3(uv.xy, 0)).rr #endif #else #define MIPSOURCE(uv) _MipSource[uv].rg #endif #endif //CBUFFER_START(cb) int4 data1; //current mip width, current mip height, lower mip width, lower mip height int4 data2; // number of mips to process at once, is U odd, is V odd, are both odd //CBUFFER_END groupshared uint minLevel1[4][4]; //groupshared uint maxLevel1[4][4]; #if UNITY_REVERSED_Z // #define MIN_DEPTH 1 #define MIN_DEPTH(l, r) max(l, r) #define MAX_DEPTH(l, r) min(l, r) #define INIT_DEPTH 0xFFFF0000u #define INTERLOCKED_MIN(a, b) InterlockedMax(a, b) #define INTERLOCKED_MAX(a, b) InterlockedMin(a, b) #else // #define MIN_DEPTH 0 #define MIN_DEPTH(l, r) min(l, r) #define MAX_DEPTH(l, r) max(l, r) #define INIT_DEPTH 0x0000FFFFu #define INTERLOCKED_MIN(a, b) InterlockedMin(a, b) #define INTERLOCKED_MAX(a, b) InterlockedMax(a, b) #endif [numthreads(KERNEL_SIZE, KERNEL_SIZE,1)] void MipMin(uint3 id : SV_DispatchThreadID) { //if (id.x < data1.x && id.y < data1.y) //{ uint2 srcPixelUV = id.xy << 1; uint3 uv00 = uint3(min(srcPixelUV + uint2(0u, 0u), data1.zw), id.z); float1or2 p00 = MIPSOURCE(COORD_DEPTH(uv00)); uint3 uv10 = uint3(min(srcPixelUV + uint2(1u, 0u), data1.zw), id.z); float1or2 p10 = MIPSOURCE(COORD_DEPTH(uv10)); uint3 uv01 = uint3(min(srcPixelUV + uint2(0u, 1u), data1.zw), id.z); float1or2 p01 = MIPSOURCE(COORD_DEPTH(uv01)); uint3 uv11 = uint3(min(srcPixelUV + uint2(1u, 1u), data1.zw), id.z); float1or2 p11 = MIPSOURCE(COORD_DEPTH(uv11)); float min4 = MIN_DEPTH(MIN_DEPTH(p00.r, p01.r), MIN_DEPTH(p10.r, p11.r)); #if defined(MIN_AND_MAX) float max4 = MAX_DEPTH(MAX_DEPTH(p00.g, p01.g), MAX_DEPTH(p10.g, p11.g)); #else float max4 = 0.0; #endif _MipDest[COORD_DEPTH(id)] = (float1or2)float4(min4,max4,0,0); } [numthreads(KERNEL_SIZE, KERNEL_SIZE, 1)] void MipMin2(uint3 id : SV_DispatchThreadID, uint3 groupID : SV_GroupThreadID, uint groupIndex : SV_GroupIndex) { //uint2 id2D = id.xy + uint2((groupID.z & 1u) ? 4u : 0u, groupID.z > 1 ? 4u : 0u); if (groupID.x < 4 && groupID.y < 4) { minLevel1[groupID.x][groupID.y] = INIT_DEPTH; //maxLevel1[groupID.x][groupID.y] = INIT_DEPTH; } GroupMemoryBarrierWithGroupSync(); //if (id.x < data1.x && id.y < data1.y) //{ uint2 srcPixelUV = id.xy << 1; uint3 uv00 = uint3(min(srcPixelUV + uint2(0u, 0u), data1.zw), id.z); float1or2 p00 = MIPSOURCE(COORD_DEPTH(uv00)); uint3 uv10 = uint3(min(srcPixelUV + uint2(1u, 0u), data1.zw), id.z); float1or2 p10 = MIPSOURCE(COORD_DEPTH(uv10)); uint3 uv01 = uint3(min(srcPixelUV + uint2(0u, 1u), data1.zw), id.z); float1or2 p01 = MIPSOURCE(COORD_DEPTH(uv01)); uint3 uv11 = uint3(min(srcPixelUV + uint2(1u, 1u), data1.zw), id.z); float1or2 p11 = MIPSOURCE(COORD_DEPTH(uv11)); float minLevel0 = MIN_DEPTH(MIN_DEPTH(p00.r, p01.r), MIN_DEPTH(p10.r, p11.r)); #if defined(MIN_AND_MAX) float maxLevel0 = MAX_DEPTH(MAX_DEPTH(p00.g, p01.g), MAX_DEPTH(p10.g, p11.g)); #else float maxLevel0 = 0.0; #endif _MipDest[COORD_DEPTH(id)] = (float1or2)float4(minLevel0, maxLevel0, 0, 0); uint2 miniGroupId = uint2(0u,0u); [branch] if (data2.x > 1) { miniGroupId = groupID.xy >> 1; uint minLevel0U = f32tof16(minLevel0) | (minLevel1[miniGroupId.x][miniGroupId.y] & 0xFFFF0000u); INTERLOCKED_MIN(minLevel1[miniGroupId.x][miniGroupId.y], minLevel0U); } GroupMemoryBarrierWithGroupSync(); #if defined(MIN_AND_MAX) [branch] if (data2.x > 1) { uint maxLevel0U = (f32tof16(maxLevel0) << 16) | (minLevel1[miniGroupId.x][miniGroupId.y] & 0x0000FFFFu); INTERLOCKED_MAX(minLevel1[miniGroupId.x][miniGroupId.y], maxLevel0U); } GroupMemoryBarrierWithGroupSync(); #endif [branch] if (data2.x > 1) { uint3 uv2 = uint3(id.xy >> 1u, id.z); [branch] if (((groupID.x & 1u) == 0u) && ((groupID.y & 1u) == 0u)) { float r0 = f16tof32(minLevel1[miniGroupId.x][miniGroupId.y] & 0x0000FFFFu); #if defined(MIN_AND_MAX) float r1 = f16tof32(minLevel1[miniGroupId.x][miniGroupId.y] >> 16u); #else float r1 = 0; #endif _MipDest2[COORD_DEPTH(uv2)] = (float1or2)float4(r0,r1,0,0); } } } [numthreads(KERNEL_SIZE, KERNEL_SIZE, 1)] void MipMinOdd(uint3 id : SV_DispatchThreadID) { //if (id.x < data1.x && id.y < data1.y) uint2 srcPixelUV = id.xy << 1; uint3 uv00 = uint3(min(srcPixelUV + uint2(0u, 0u), data1.zw), id.z); float1or2 p00 = MIPSOURCE(COORD_DEPTH(uv00)); uint3 uv10 = uint3(min(srcPixelUV + uint2(1u, 0u), data1.zw), id.z); float1or2 p10 = MIPSOURCE(COORD_DEPTH(uv10)); uint3 uv01 = uint3(min(srcPixelUV + uint2(0u, 1u), data1.zw), id.z); float1or2 p01 = MIPSOURCE(COORD_DEPTH(uv01)); uint3 uv11 = uint3(min(srcPixelUV + uint2(1u, 1u), data1.zw), id.z); float1or2 p11 = MIPSOURCE(COORD_DEPTH(uv11)); float minLevel0 = MIN_DEPTH(MIN_DEPTH(p00.r, p01.r), MIN_DEPTH(p10.r, p11.r)); #if defined(MIN_AND_MAX) float maxLevel0 = MAX_DEPTH(MAX_DEPTH(p00.g, p01.g), MAX_DEPTH(p10.g, p11.g)); #else float maxLevel0 = 0.0f; #endif if (data2.y == 1) { uint3 uv20 = uint3(min(srcPixelUV + uint2(2u, 0u), data1.zw), id.z); float2 p20 = MIPSOURCE(COORD_DEPTH(uv20)); uint3 uv21 = uint3(min(srcPixelUV + uint2(2u, 1u), data1.zw), id.z); float2 p21 = MIPSOURCE(COORD_DEPTH(uv21)); minLevel0 = MIN_DEPTH(MIN_DEPTH(p20.r, p21.r), minLevel0); #if defined(MIN_AND_MAX) maxLevel0 = MAX_DEPTH(MAX_DEPTH(p20.g, p21.g), maxLevel0); #endif } if (data2.z == 1) { uint3 uv02 = uint3(min(srcPixelUV + uint2(0u, 2u), data1.zw), id.z); float2 p02 = MIPSOURCE(COORD_DEPTH(uv02)); uint3 uv12 = uint3(min(srcPixelUV + uint2(1u, 2u), data1.zw), id.z); float2 p12 = MIPSOURCE(COORD_DEPTH(uv12)); minLevel0 = MIN_DEPTH(MIN_DEPTH(p02.r, p12.r), minLevel0); #if defined(MIN_AND_MAX) maxLevel0 = MAX_DEPTH(MAX_DEPTH(p02.g, p12.g), maxLevel0); #endif } if (data2.z == 1 && data2.y == 1) { uint3 uv22 = uint3(min(srcPixelUV + uint2(2u, 2u), data1.zw), id.z); float2 p22 = MIPSOURCE(COORD_DEPTH(uv22)); minLevel0 = MIN_DEPTH(p22.r, minLevel0); #if defined(MIN_AND_MAX) maxLevel0 = MAX_DEPTH(p22.g, maxLevel0); #endif } _MipDest[COORD_DEPTH(id)] = (float1or2)float4(minLevel0, maxLevel0, 0,0); //} }