From 496ed9b96de63983f60e5ddd772f2e54c84eec5c Mon Sep 17 00:00:00 2001 From: Try Date: Wed, 15 Jul 2026 00:38:09 +0200 Subject: [PATCH 1/6] hiz version 2 --- game/graphics/renderer.cpp | 11 +++ game/graphics/shaders.cpp | 5 +- game/graphics/shaders.h | 2 +- shader/CMakeLists.txt | 1 + shader/hiz/hiz_mip2.comp | 148 +++++++++++++++++++++++++++++++++++++ 5 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 shader/hiz/hiz_mip2.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index d9ac74264..584cba2e2 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -151,6 +151,7 @@ void Renderer::resetSwapchain() { } else { hiz.counterBuf = device.ssbo(Tempest::Uninitialized, std::max(hw/4, 1u)*std::max(hh/4, 1u)*sizeof(uint32_t)); } + hiz.counterBuf = device.ssbo(nullptr, sizeof(uint32_t)); sceneOpaque = device.attachment(TextureFormat::R11G11B10UF,w,h); sceneDepth = device.attachment(TextureFormat::R32F, w,h); @@ -1052,6 +1053,15 @@ void Renderer::buildHiZ(Tempest::Encoder& cmd) { cmd.dispatch(size_t(hiz.hiZ.w()), size_t(hiz.hiZ.h())); const uint32_t maxBind = 8, mip = hiz.hiZ.mipCount(); + cmd.setBinding(0, hiz.counterBuf); + for(uint32_t i=0; i& cmd) { cmd.setPushData(&mip, sizeof(mip)); cmd.setPipeline(shaders.hiZMip); cmd.dispatchThreads(w,h); + */ } void Renderer::drawVsm(Tempest::Encoder& cmd, WorldView& wview) { diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 38062e8ee..5e8479858 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -176,8 +176,9 @@ void Shaders::compileShaders() { cmaa2DeferredColorApply2x2 = device.pipeline(Tempest::Points,RenderState(),vs,fs); } - hiZPot = computeShader("hiz_pot.comp.sprv"); - hiZMip = computeShader("hiz_mip.comp.sprv"); + hiZPot = computeShader("hiz_pot.comp.sprv"); + hiZMip = computeShader("hiz_mip.comp.sprv"); + hiZMip2 = computeShader("hiz_mip2.comp.sprv"); if(Gothic::options().doRayQuery) { rtDbg = postEffect("triangle_uv", "rt_dbg", RenderState::ZTestMode::NoEqual); diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 1d2f50e79..bb0904598 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -68,7 +68,7 @@ class Shaders { Tempest::RenderPipeline cmaa2DeferredColorApply2x2; // HiZ - Tempest::ComputePipeline hiZPot, hiZMip; + Tempest::ComputePipeline hiZPot, hiZMip, hiZMip2; // Cluster Tempest::ComputePipeline clusterInit, clusterPatch; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index ec2f3736a..88b5f435d 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -281,6 +281,7 @@ if(IOS) add_shader(hiz_mip.comp hiz/hiz_mip.comp -DIOS) else() add_shader(hiz_mip.comp hiz/hiz_mip.comp) + add_shader(hiz_mip2.comp hiz/hiz_mip2.comp) endif() add_shader(hiz_pot.comp hiz/hiz_pot.comp) diff --git a/shader/hiz/hiz_mip2.comp b/shader/hiz/hiz_mip2.comp new file mode 100644 index 000000000..61ef37467 --- /dev/null +++ b/shader/hiz/hiz_mip2.comp @@ -0,0 +1,148 @@ +#version 450 + +#extension GL_EXT_control_flow_attributes : enable +// #extension GL_EXT_samplerless_texture_functions : enable + +layout(local_size_x = 8, local_size_y = 8) in; + +layout(binding = 0, std430) buffer coherent SB0 { uint counter; }; +layout(binding = 1, r16) uniform coherent image2D mip0; +layout(binding = 2, r16) uniform coherent image2D mip1; +layout(binding = 3, r16) uniform coherent image2D mip2; +layout(binding = 4, r16) uniform coherent image2D mip3; +layout(binding = 5, r16) uniform coherent image2D mip4; +layout(binding = 6, r16) uniform coherent image2D mip5; +layout(binding = 7, r16) uniform coherent image2D mip6; +layout(binding = 8, r16) uniform coherent image2D mip7; // 128x128 +//layout(binding = 9, r16) uniform coherent image2D mip8; + +layout(push_constant, std140) uniform PushConstant { + uint mipCount; + }; + +shared float tile[8][8]; +shared uint cnt; + +float load(int mip, ivec2 uv) { +#if defined(IOS) + // ios metal-shader compiller has ugly bug: + // https://developer.apple.com/forums/thread/750478 + switch(mip) { + case 0: return imageLoad(mip0, uv).x; + default: return 1; + } + return 1; +#else + switch(mip) { + case 0: return imageLoad(mip0, uv).x; + case 1: return imageLoad(mip1, uv).x; + case 2: return imageLoad(mip2, uv).x; + case 3: return imageLoad(mip3, uv).x; + case 4: return imageLoad(mip4, uv).x; + case 5: return imageLoad(mip5, uv).x; + case 6: return imageLoad(mip6, uv).x; + case 7: return imageLoad(mip7, uv).x; + } + return -1; +#endif + } + +void store(int mip, ivec2 uv, float z) { + switch(mip) { + case 1: + imageStore(mip1, uv, vec4(z)); + break; + case 2: + imageStore(mip2, uv, vec4(z)); + break; + case 3: + imageStore(mip3, uv, vec4(z)); + break; + case 4: + imageStore(mip4, uv, vec4(z)); + break; + case 5: + imageStore(mip5, uv, vec4(z)); + break; + case 6: + imageStore(mip6, uv, vec4(z)); + break; + case 7: + imageStore(mip7, uv, vec4(z)); + break; + } + } + +float gatherImg(int mip, ivec2 uv, ivec2 srcSz, ivec2 dstSz) { + if(!all(lessThan(uv, dstSz))) + return 0; + + ivec2 srcUV0 = uv*2; + ivec2 srcUV1 = min(srcUV0+1, srcSz-1); + + float z00 = load(mip, ivec2(srcUV0.x,srcUV0.y)); + float z01 = load(mip, ivec2(srcUV0.x,srcUV1.y)); + float z10 = load(mip, ivec2(srcUV1.x,srcUV0.y)); + float z11 = load(mip, ivec2(srcUV1.x,srcUV1.y)); + return max(max(z00, z01), max(z10, z11)); + } + +float gatherTile(ivec2 local) { + local *= 2; + float z00 = tile[local.x+0][local.y+0]; + float z01 = tile[local.x+0][local.y+1]; + float z10 = tile[local.x+1][local.y+0]; + float z11 = tile[local.x+1][local.y+1]; + return max(max(z00, z01), max(z10, z11)); + } + +void processTile(int baseMip, uint mipCount) { + ivec2 local = ivec2(gl_LocalInvocationID.xy); + ivec2 group = ivec2(gl_WorkGroupID.xy); + ivec2 gsize = ivec2(gl_WorkGroupSize.xy); + + ivec2 uv = ivec2(0); + ivec2 imgSz = imageSize(mip0); + ivec2 srcSz = max(ivec2(1,1), imgSz >> (baseMip+0)); + ivec2 dstSz = max(ivec2(1,1), imgSz >> (baseMip+1)); + + float z = 0; + if(all(lessThan(uv, dstSz))) { + uv = group*gsize + local; + z = gatherImg(baseMip, uv, srcSz, dstSz); + store(baseMip+1, uv, z); + } + tile[local.x][local.y] = z; + barrier(); + + for(int i=2; baseMip+i Date: Wed, 15 Jul 2026 00:42:21 +0200 Subject: [PATCH 2/6] refactor --- shader/hiz/hiz_mip2.comp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/shader/hiz/hiz_mip2.comp b/shader/hiz/hiz_mip2.comp index 61ef37467..21338f79a 100644 --- a/shader/hiz/hiz_mip2.comp +++ b/shader/hiz/hiz_mip2.comp @@ -112,10 +112,11 @@ void processTile(int baseMip, uint mipCount) { z = gatherImg(baseMip, uv, srcSz, dstSz); store(baseMip+1, uv, z); } - tile[local.x][local.y] = z; - barrier(); for(int i=2; baseMip+i Date: Wed, 15 Jul 2026 19:14:07 +0200 Subject: [PATCH 3/6] fixup --- shader/hiz/hiz_mip2.comp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/shader/hiz/hiz_mip2.comp b/shader/hiz/hiz_mip2.comp index 21338f79a..cd6f1e7c1 100644 --- a/shader/hiz/hiz_mip2.comp +++ b/shader/hiz/hiz_mip2.comp @@ -96,20 +96,18 @@ float gatherTile(ivec2 local) { return max(max(z00, z01), max(z10, z11)); } -void processTile(int baseMip, uint mipCount) { +void processTile(ivec2 group, int baseMip, uint mipCount) { ivec2 local = ivec2(gl_LocalInvocationID.xy); - ivec2 group = ivec2(gl_WorkGroupID.xy); ivec2 gsize = ivec2(gl_WorkGroupSize.xy); - ivec2 uv = ivec2(0); ivec2 imgSz = imageSize(mip0); ivec2 srcSz = max(ivec2(1,1), imgSz >> (baseMip+0)); ivec2 dstSz = max(ivec2(1,1), imgSz >> (baseMip+1)); - float z = 0; + float z = 0; + ivec2 uv = group*gsize + local; if(all(lessThan(uv, dstSz))) { - uv = group*gsize + local; - z = gatherImg(baseMip, uv, srcSz, dstSz); + z = gatherImg(baseMip, uv, srcSz, dstSz); store(baseMip+1, uv, z); } @@ -121,14 +119,15 @@ void processTile(int baseMip, uint mipCount) { if(local.x Date: Wed, 15 Jul 2026 19:40:27 +0200 Subject: [PATCH 4/6] fixup --- shader/hiz/hiz_mip2.comp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shader/hiz/hiz_mip2.comp b/shader/hiz/hiz_mip2.comp index cd6f1e7c1..43c71f714 100644 --- a/shader/hiz/hiz_mip2.comp +++ b/shader/hiz/hiz_mip2.comp @@ -1,7 +1,6 @@ #version 450 #extension GL_EXT_control_flow_attributes : enable -// #extension GL_EXT_samplerless_texture_functions : enable layout(local_size_x = 8, local_size_y = 8) in; @@ -111,12 +110,13 @@ void processTile(ivec2 group, int baseMip, uint mipCount) { store(baseMip+1, uv, z); } + [[unroll]] for(int i=2; baseMip+i Date: Wed, 15 Jul 2026 21:08:50 +0200 Subject: [PATCH 5/6] ios --- shader/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 88b5f435d..28159a4bf 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -279,6 +279,7 @@ add_shader(ssao_blur.comp ssao/ssao_blur.comp) # GPU-driven: HiZ if(IOS) add_shader(hiz_mip.comp hiz/hiz_mip.comp -DIOS) + add_shader(hiz_mip2.comp hiz/hiz_mip2.comp) else() add_shader(hiz_mip.comp hiz/hiz_mip.comp) add_shader(hiz_mip2.comp hiz/hiz_mip2.comp) From de0e23338c9c97f68927486e9aac1e8eef7ec13c Mon Sep 17 00:00:00 2001 From: Try Date: Wed, 15 Jul 2026 21:58:40 +0200 Subject: [PATCH 6/6] cleanup --- game/graphics/renderer.cpp | 27 +------ game/graphics/renderer.h | 5 +- game/graphics/shaders.cpp | 1 - game/graphics/shaders.h | 2 +- shader/CMakeLists.txt | 2 - shader/hiz/hiz_mip.comp | 101 ++++++++++++++++--------- shader/hiz/hiz_mip2.comp | 148 ------------------------------------- 7 files changed, 71 insertions(+), 215 deletions(-) delete mode 100644 shader/hiz/hiz_mip2.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 584cba2e2..c7851eeb4 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -144,14 +144,8 @@ void Renderer::resetSwapchain() { hh = std::max(1u, (hh+1)/2u); } - hiz.atomicImg = device.properties().hasAtomicFormat(TextureFormat::R32U); hiz.hiZ = device.image2d(TextureFormat::R16, hw, hh, true); - if(hiz.atomicImg) { - hiz.counter = device.image2d(TextureFormat::R32U, std::max(hw/4, 1u), std::max(hh/4, 1u), false); - } else { - hiz.counterBuf = device.ssbo(Tempest::Uninitialized, std::max(hw/4, 1u)*std::max(hh/4, 1u)*sizeof(uint32_t)); - } - hiz.counterBuf = device.ssbo(nullptr, sizeof(uint32_t)); + hiz.counter = device.ssbo(nullptr, sizeof(uint32_t)); sceneOpaque = device.attachment(TextureFormat::R11G11B10UF,w,h); sceneDepth = device.attachment(TextureFormat::R32F, w,h); @@ -1053,27 +1047,12 @@ void Renderer::buildHiZ(Tempest::Encoder& cmd) { cmd.dispatch(size_t(hiz.hiZ.w()), size_t(hiz.hiZ.h())); const uint32_t maxBind = 8, mip = hiz.hiZ.mipCount(); - cmd.setBinding(0, hiz.counterBuf); - for(uint32_t i=0; i& cmd, WorldView& wview) { diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index 576b74f8b..e47b9bcb6 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -193,10 +193,7 @@ class Renderer final { struct { Tempest::StorageImage hiZ; - Tempest::StorageImage counter; - Tempest::StorageBuffer counterBuf; - - bool atomicImg = false; + Tempest::StorageBuffer counter; } hiz; struct { diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 5e8479858..19aa4a299 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -178,7 +178,6 @@ void Shaders::compileShaders() { hiZPot = computeShader("hiz_pot.comp.sprv"); hiZMip = computeShader("hiz_mip.comp.sprv"); - hiZMip2 = computeShader("hiz_mip2.comp.sprv"); if(Gothic::options().doRayQuery) { rtDbg = postEffect("triangle_uv", "rt_dbg", RenderState::ZTestMode::NoEqual); diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index bb0904598..1d2f50e79 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -68,7 +68,7 @@ class Shaders { Tempest::RenderPipeline cmaa2DeferredColorApply2x2; // HiZ - Tempest::ComputePipeline hiZPot, hiZMip, hiZMip2; + Tempest::ComputePipeline hiZPot, hiZMip; // Cluster Tempest::ComputePipeline clusterInit, clusterPatch; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 28159a4bf..ec2f3736a 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -279,10 +279,8 @@ add_shader(ssao_blur.comp ssao/ssao_blur.comp) # GPU-driven: HiZ if(IOS) add_shader(hiz_mip.comp hiz/hiz_mip.comp -DIOS) - add_shader(hiz_mip2.comp hiz/hiz_mip2.comp) else() add_shader(hiz_mip.comp hiz/hiz_mip.comp) - add_shader(hiz_mip2.comp hiz/hiz_mip2.comp) endif() add_shader(hiz_pot.comp hiz/hiz_pot.comp) diff --git a/shader/hiz/hiz_mip.comp b/shader/hiz/hiz_mip.comp index 6d9d6da29..d87453ea1 100644 --- a/shader/hiz/hiz_mip.comp +++ b/shader/hiz/hiz_mip.comp @@ -1,11 +1,10 @@ #version 450 #extension GL_EXT_control_flow_attributes : enable -#extension GL_EXT_samplerless_texture_functions : enable layout(local_size_x = 8, local_size_y = 8) in; -layout(binding = 0, r32ui) uniform coherent uimage2D counters; +layout(binding = 0, std430) buffer coherent SB0 { uint counter; }; layout(binding = 1, r16) uniform coherent image2D mip0; layout(binding = 2, r16) uniform coherent image2D mip1; layout(binding = 3, r16) uniform coherent image2D mip2; @@ -20,10 +19,14 @@ layout(push_constant, std140) uniform PushConstant { uint mipCount; }; +shared float tile[8][8]; +shared uint cnt; + float load(int mip, ivec2 uv) { -#if defined(IOS) +#if defined(IOS) && 0 // ios metal-shader compiller has ugly bug: // https://developer.apple.com/forums/thread/750478 + // NOTE: longer an issue, on recent ios, by looks of it. But maybe issue been hidden by changes in the shader switch(mip) { case 0: return imageLoad(mip0, uv).x; default: return 1; @@ -70,7 +73,13 @@ void store(int mip, ivec2 uv, float z) { } } -float gather(int mip, ivec2 srcUV0, ivec2 srcUV1) { +float gatherImg(int mip, ivec2 uv, ivec2 srcSz, ivec2 dstSz) { + if(!all(lessThan(uv, dstSz))) + return 0; + + ivec2 srcUV0 = uv*2; + ivec2 srcUV1 = min(srcUV0+1, srcSz-1); + float z00 = load(mip, ivec2(srcUV0.x,srcUV0.y)); float z01 = load(mip, ivec2(srcUV0.x,srcUV1.y)); float z10 = load(mip, ivec2(srcUV1.x,srcUV0.y)); @@ -78,41 +87,63 @@ float gather(int mip, ivec2 srcUV0, ivec2 srcUV1) { return max(max(z00, z01), max(z10, z11)); } -uint addCounter(int mip, ivec2 uv) { - uint bit = (mip-1)*3; - uint counter = imageAtomicAdd(counters, uv, 1u << bit); - counter = (counter >> bit) & 0x3; - return counter+1; +float gatherTile(ivec2 local) { + local *= 2; + float z00 = tile[local.x+0][local.y+0]; + float z01 = tile[local.x+0][local.y+1]; + float z10 = tile[local.x+1][local.y+0]; + float z11 = tile[local.x+1][local.y+1]; + return max(max(z00, z01), max(z10, z11)); } -void clearCounter(int mip, ivec2 uv) { - uint bits = 0x7u << ((mip-1)*3); - imageAtomicAnd(counters, uv, ~bits); +void processTile(ivec2 group, int baseMip, uint mipCount) { + ivec2 local = ivec2(gl_LocalInvocationID.xy); + ivec2 gsize = ivec2(gl_WorkGroupSize.xy); + + ivec2 imgSz = imageSize(mip0); + ivec2 srcSz = max(ivec2(1,1), imgSz >> (baseMip+0)); + ivec2 dstSz = max(ivec2(1,1), imgSz >> (baseMip+1)); + + float z = 0; + ivec2 uv = group*gsize + local; + if(all(lessThan(uv, dstSz))) { + z = gatherImg(baseMip, uv, srcSz, dstSz); + store(baseMip+1, uv, z); + } + + [[unroll]] + for(int i=2; baseMip+i=dstSz.x || uv.y>=dstSz.y) - return; - - const float z = gather(mip-1, uv*2, min(uv*2+1, srcSz-1)); - store(mip, uv, z); - memoryBarrierImage(); - - uint counter = addCounter(mip, uv/2); - ivec2 area = min(ivec2(2), dstSz - (uv/2)*2); - if(counter!=area.x*area.y) - return; - clearCounter(mip, uv/2); - uv = uv/2; - dstSz = max(ivec2(1,1), dstSz/2); - srcSz = max(ivec2(1,1), srcSz/2); + processTile(ivec2(gl_WorkGroupID.xy), 0, mipCount); + + if(mipCount<=4) + return; + + memoryBarrierImage(); + barrier(); + + if(gl_LocalInvocationIndex==0) { + cnt = atomicAdd(counter, 1); } + barrier(); + + if(cnt < gl_NumWorkGroups.x*gl_NumWorkGroups.y-1) + return; + + atomicExchange(counter, 0); // skip buffer memory-barrier + processTile(ivec2(0), 4, mipCount); } diff --git a/shader/hiz/hiz_mip2.comp b/shader/hiz/hiz_mip2.comp deleted file mode 100644 index 43c71f714..000000000 --- a/shader/hiz/hiz_mip2.comp +++ /dev/null @@ -1,148 +0,0 @@ -#version 450 - -#extension GL_EXT_control_flow_attributes : enable - -layout(local_size_x = 8, local_size_y = 8) in; - -layout(binding = 0, std430) buffer coherent SB0 { uint counter; }; -layout(binding = 1, r16) uniform coherent image2D mip0; -layout(binding = 2, r16) uniform coherent image2D mip1; -layout(binding = 3, r16) uniform coherent image2D mip2; -layout(binding = 4, r16) uniform coherent image2D mip3; -layout(binding = 5, r16) uniform coherent image2D mip4; -layout(binding = 6, r16) uniform coherent image2D mip5; -layout(binding = 7, r16) uniform coherent image2D mip6; -layout(binding = 8, r16) uniform coherent image2D mip7; // 128x128 -//layout(binding = 9, r16) uniform coherent image2D mip8; - -layout(push_constant, std140) uniform PushConstant { - uint mipCount; - }; - -shared float tile[8][8]; -shared uint cnt; - -float load(int mip, ivec2 uv) { -#if defined(IOS) - // ios metal-shader compiller has ugly bug: - // https://developer.apple.com/forums/thread/750478 - switch(mip) { - case 0: return imageLoad(mip0, uv).x; - default: return 1; - } - return 1; -#else - switch(mip) { - case 0: return imageLoad(mip0, uv).x; - case 1: return imageLoad(mip1, uv).x; - case 2: return imageLoad(mip2, uv).x; - case 3: return imageLoad(mip3, uv).x; - case 4: return imageLoad(mip4, uv).x; - case 5: return imageLoad(mip5, uv).x; - case 6: return imageLoad(mip6, uv).x; - case 7: return imageLoad(mip7, uv).x; - } - return -1; -#endif - } - -void store(int mip, ivec2 uv, float z) { - switch(mip) { - case 1: - imageStore(mip1, uv, vec4(z)); - break; - case 2: - imageStore(mip2, uv, vec4(z)); - break; - case 3: - imageStore(mip3, uv, vec4(z)); - break; - case 4: - imageStore(mip4, uv, vec4(z)); - break; - case 5: - imageStore(mip5, uv, vec4(z)); - break; - case 6: - imageStore(mip6, uv, vec4(z)); - break; - case 7: - imageStore(mip7, uv, vec4(z)); - break; - } - } - -float gatherImg(int mip, ivec2 uv, ivec2 srcSz, ivec2 dstSz) { - if(!all(lessThan(uv, dstSz))) - return 0; - - ivec2 srcUV0 = uv*2; - ivec2 srcUV1 = min(srcUV0+1, srcSz-1); - - float z00 = load(mip, ivec2(srcUV0.x,srcUV0.y)); - float z01 = load(mip, ivec2(srcUV0.x,srcUV1.y)); - float z10 = load(mip, ivec2(srcUV1.x,srcUV0.y)); - float z11 = load(mip, ivec2(srcUV1.x,srcUV1.y)); - return max(max(z00, z01), max(z10, z11)); - } - -float gatherTile(ivec2 local) { - local *= 2; - float z00 = tile[local.x+0][local.y+0]; - float z01 = tile[local.x+0][local.y+1]; - float z10 = tile[local.x+1][local.y+0]; - float z11 = tile[local.x+1][local.y+1]; - return max(max(z00, z01), max(z10, z11)); - } - -void processTile(ivec2 group, int baseMip, uint mipCount) { - ivec2 local = ivec2(gl_LocalInvocationID.xy); - ivec2 gsize = ivec2(gl_WorkGroupSize.xy); - - ivec2 imgSz = imageSize(mip0); - ivec2 srcSz = max(ivec2(1,1), imgSz >> (baseMip+0)); - ivec2 dstSz = max(ivec2(1,1), imgSz >> (baseMip+1)); - - float z = 0; - ivec2 uv = group*gsize + local; - if(all(lessThan(uv, dstSz))) { - z = gatherImg(baseMip, uv, srcSz, dstSz); - store(baseMip+1, uv, z); - } - - [[unroll]] - for(int i=2; baseMip+i