From eb1a86031f90adc6cd583e647a9bfe4bafb8f9e6 Mon Sep 17 00:00:00 2001 From: Try Date: Wed, 27 May 2026 00:06:53 +0200 Subject: [PATCH 01/52] surfel rendering initial --- game/graphics/renderer.cpp | 87 +++++++++++++++++ game/graphics/renderer.h | 14 ++- game/graphics/shaders.cpp | 18 ++++ game/graphics/shaders.h | 5 + shader/CMakeLists.txt | 9 ++ shader/lighting/rt_dbg/hash_dbg.frag | 96 +++++++++++++++++++ shader/lighting/surfels/surf_alloc.comp | 116 +++++++++++++++++++++++ shader/lighting/surfels/surf_alloc2.comp | 60 ++++++++++++ shader/lighting/surfels/surf_common.glsl | 52 ++++++++++ shader/lighting/surfels/surf_dbg.frag | 49 ++++++++++ shader/lighting/surfels/surf_dbg.vert | 71 ++++++++++++++ shader/lighting/surfels/surf_init.comp | 12 +++ 12 files changed, 588 insertions(+), 1 deletion(-) create mode 100644 shader/lighting/rt_dbg/hash_dbg.frag create mode 100644 shader/lighting/surfels/surf_alloc.comp create mode 100644 shader/lighting/surfels/surf_alloc2.comp create mode 100644 shader/lighting/surfels/surf_common.glsl create mode 100644 shader/lighting/surfels/surf_dbg.frag create mode 100644 shader/lighting/surfels/surf_dbg.vert create mode 100644 shader/lighting/surfels/surf_init.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index e79cfda70..c8748f064 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -372,6 +372,14 @@ StorageBuffer& Renderer::usesSsbo(Tempest::StorageBuffer& ret, size_t size) { return ret; } +StorageBuffer& Renderer::usesSsboInit(Tempest::StorageBuffer& ret, size_t size) { + if(ret.byteSize()==size) + return ret; + Resources::recycle(std::move(ret)); + ret = Resources::device().ssbo(nullptr, size); + return ret; + } + StorageBuffer& Renderer::usesScratch(Tempest::StorageBuffer& ret, size_t size) { if(ret.byteSize()>=size) return ret; @@ -653,6 +661,7 @@ void Renderer::draw(Tempest::Attachment& result, Encoder& cmd, ui prepareSSAO(cmd,*wview); prepareFog (cmd,*wview); prepareGi (cmd,*wview); + prepareSurfels(cmd,*wview); cmd.setFramebuffer({{sceneLinear, Tempest::Discard, Tempest::Preserve}}, {zbuffer, Tempest::Readonly}); drawShadowResolve(cmd,*wview); @@ -670,8 +679,10 @@ void Renderer::draw(Tempest::Attachment& result, Encoder& cmd, ui cmd.setDebugMarker("Translucent"); wview->drawTranslucent(cmd, fId); + //drawHashDbg(sceneLinear, cmd, *wview); drawProbesDbg(cmd, *wview); drawProbesHitDbg(cmd); + drawSurfelsDbg(cmd, *wview); drawVsmDbg(cmd, *wview); drawSwrDbg(cmd, *wview); drawRtsmDbg(cmd, *wview); @@ -696,6 +707,7 @@ void Renderer::draw(Tempest::Attachment& result, Encoder& cmd, ui } //drawRayQueryDbg(cmd, *wview); + //drawHashDbg(result, cmd, *wview); wview->postFrameupdate(); } @@ -989,6 +1001,28 @@ void Renderer::drawRtsmDbg(Tempest::Encoder& cmd, const cmd.draw(nullptr, 0, 3); } +void Renderer::drawHashDbg(Attachment& result, Tempest::Encoder& cmd, const WorldView& wview) { + static bool enable = true; + if(!enable) + return; + + auto& scene = wview.sceneGlobals(); + + struct Push { + Vec3 originLwc; + } push; + push.originLwc = scene.originLwc; + + cmd.setDebugMarker("Hash-dbg"); + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, zbuffer); + + cmd.setFramebuffer({{result, Tempest::Preserve, Tempest::Preserve}}); + cmd.setPipeline(shaders.hashDbg); + cmd.draw(nullptr, 0, 3); + } + void Renderer::drawHiZ(Encoder& cmd, WorldView& view) { cmd.setDebugMarker("HiZ-occluders"); cmd.setFramebuffer({}, {zbuffer, 1.f, Tempest::Preserve}); @@ -1899,6 +1933,45 @@ void Renderer::prepareEpipolar(Tempest::Encoder& cmd, Wo cmd.dispatch(uint32_t(epTrace.h())); } +void Renderer::prepareSurfels(Tempest::Encoder& cmd, WorldView& wview) { + static bool alloc = true; + + const uint32_t hashGridSize = 4'194'304; // SHaRC docimentation recommends 2^22 + cmd.setDebugMarker("Surfels"); + + auto& scene = wview.sceneGlobals(); + auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc.sizeofBuffer(4, surf.maxSurfels)); + auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); + auto& hashGrid = usesSsboInit(surf.hashGrid, hashGridSize); + + if(alloc) { + struct Push { + Vec3 originLwc; + } push; + push.originLwc = scene.originLwc; + + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, hashGrid); + // + cmd.setBinding(11, dbgImage); + + cmd.setPipeline(shaders.surfInit); + cmd.dispatchThreads(hashGridSize); + + cmd.setPipeline(shaders.surfAlloc); + cmd.dispatchThreads(sceneDepth.size()); + + cmd.setPipeline(shaders.surfAlloc2); + cmd.dispatchThreads(hashGridSize); + //alloc = false; + } + } + void Renderer::prepareIrradiance(Encoder& cmd, WorldView& wview) { auto& scene = wview.sceneGlobals(); @@ -2179,6 +2252,20 @@ void Renderer::drawRayQueryDbg(Tempest::Encoder& cmd, co cmd.draw(nullptr, 0, 3); } +void Renderer::drawSurfelsDbg(Encoder& cmd, const WorldView& wview) { + static bool enable = true; + if(!enable) + return; + + cmd.setDebugMarker("GI-dbg"); + cmd.setBinding(0, wview.sceneGlobals().uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, surf.surfels); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, sceneDepth, Sampler::nearest()); + cmd.setPipeline(shaders.surfDbg); + cmd.draw(nullptr, 0, 36, 0, surf.maxSurfels); + } + void Renderer::drawProbesDbg(Encoder& cmd, const WorldView& wview) { if(!settings.giEnabled) return; diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index 9a4b38e04..5d259643a 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -41,8 +41,8 @@ class Renderer final { }; Tempest::Size internalResolution() const; float internalResolutionScale() const; - void updateCamera(const Camera &camera); + void updateCamera(const Camera &camera); bool requiresTlas() const; Tempest::StorageImage& usesImage2d(Tempest::StorageImage& ret, Tempest::TextureFormat frm, uint32_t w, uint32_t h, bool mips = false); @@ -50,6 +50,7 @@ class Renderer final { Tempest::StorageImage& usesImage3d(Tempest::StorageImage& ret, Tempest::TextureFormat frm, uint32_t w, uint32_t h, uint32_t d, bool mips = false); Tempest::ZBuffer& usesZBuffer(Tempest::ZBuffer& ret, Tempest::TextureFormat frm, uint32_t w, uint32_t h); Tempest::StorageBuffer& usesSsbo(Tempest::StorageBuffer& ret, size_t size); + Tempest::StorageBuffer& usesSsboInit(Tempest::StorageBuffer& ret, size_t size); Tempest::StorageBuffer& usesScratch(Tempest::StorageBuffer& ret, size_t size); void prepareUniforms(); @@ -63,6 +64,7 @@ class Renderer final { void prepareGi (Tempest::Encoder& cmd, WorldView& wview); void prepareExposure (Tempest::Encoder& cmd, WorldView& wview); void prepareEpipolar (Tempest::Encoder& cmd, WorldView& wview); + void prepareSurfels (Tempest::Encoder& cmd, WorldView& wview); void drawHiZ (Tempest::Encoder& cmd, WorldView& view); void buildHiZ (Tempest::Encoder& cmd); @@ -93,10 +95,12 @@ class Renderer final { void drawRayQueryDbg (Tempest::Encoder& cmd, const WorldView& wview); void drawProbesDbg (Tempest::Encoder& cmd, const WorldView& wview); + void drawSurfelsDbg (Tempest::Encoder& cmd, const WorldView& wview); void drawProbesHitDbg (Tempest::Encoder& cmd); void drawVsmDbg (Tempest::Encoder& cmd, const WorldView& wview); void drawSwrDbg (Tempest::Encoder& cmd, const WorldView& wview); void drawRtsmDbg (Tempest::Encoder& cmd, const WorldView& wview); + void drawHashDbg (Tempest::Attachment& result, Tempest::Encoder& cmd, const WorldView& wview); void setupSettings(); void toggleGi(); @@ -205,6 +209,14 @@ class Renderer final { Tempest::StorageImage probesLightingPrev; } gi; + struct { + const uint32_t maxSurfels = 16*1024; + Tempest::StorageBuffer surfels; + Tempest::StorageBuffer hashGrid; + + Tempest::StorageImage dbgImage; + } surf; + struct { Tempest::Attachment frame; uint32_t numFrames = 0; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 63958d473..674088149 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -181,6 +181,7 @@ void Shaders::compileShaders() { if(Gothic::options().doRayQuery) { rtDbg = postEffect("triangle_uv", "rt_dbg", RenderState::ZTestMode::NoEqual); } + hashDbg = postEffect("triangle_uv", "hash_dbg"); if(Gothic::options().doRayQuery) { RenderState state; @@ -235,6 +236,23 @@ void Shaders::compileShaders() { probeAmbient = device.pipeline(Triangles,state,vs,fs); } + if(true) { + RenderState state; + state.setCullFaceMode(RenderState::CullMode::NoCull); + state.setZTestMode (RenderState::ZTestMode::Less); + state.setZWriteEnabled(false); + + auto sh = GothicShader::get("surf_dbg.vert.sprv"); + auto vs = device.shader(sh.data,sh.len); + sh = GothicShader::get("surf_dbg.frag.sprv"); + auto fs = device.shader(sh.data,sh.len); + surfDbg = device.pipeline(Triangles,state,vs,fs); + + surfInit = computeShader("surf_init.comp.sprv"); + surfAlloc = computeShader("surf_alloc.comp.sprv"); + surfAlloc2 = computeShader("surf_alloc2.comp.sprv"); + } + if(Shaders::isVsmSupported()) { fogEpipolarOcclusion = computeShader("fog_epipolar_occlusion.comp.sprv"); fogEpipolarVsm = computeShader("fog_epipolar_vsm.comp.sprv"); diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index ecba2b9ac..9673cbc88 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -75,6 +75,7 @@ class Shaders { // RT/RQ Tempest::RenderPipeline rtDbg; Tempest::RenderPipeline rtPathtrace; + Tempest::RenderPipeline hashDbg; // GI Tempest::RenderPipeline probeDbg, probeHitDbg; @@ -83,6 +84,10 @@ class Shaders { Tempest::ComputePipeline probeTrace, probeLighting; Tempest::RenderPipeline probeAmbient; + // GI-Surf + Tempest::RenderPipeline surfDbg; + Tempest::ComputePipeline surfInit, surfAlloc, surfAlloc2; + // Epipolar Tempest::ComputePipeline fogEpipolarVsm; Tempest::ComputePipeline fogEpipolarOcclusion; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index d87c2f35d..492643d2c 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -285,6 +285,7 @@ add_shader(hiz_pot.comp hiz/hiz_pot.comp) # RayQuery add_shader(rt_dbg.frag lighting/rt_dbg/rt_dbg.frag -DRAY_QUERY -DRAY_QUERY_AT) +add_shader(hash_dbg.frag lighting/rt_dbg/hash_dbg.frag) # Global illumination add_shader(probe_dbg.vert lighting/rt/probe_dbg.vert) @@ -306,6 +307,14 @@ add_shader(probe_lighting.comp lighting/rt/probe_lighting.comp) add_shader(probe_ambient.vert triangle.vert) add_shader(probe_ambient.frag lighting/rt/probe_ambient.frag) +# Surfels +add_shader(surf_dbg.vert lighting/surfels/surf_dbg.vert) +add_shader(surf_dbg.frag lighting/surfels/surf_dbg.frag) + +add_shader(surf_init.comp lighting/surfels/surf_init.comp) +add_shader(surf_alloc.comp lighting/surfels/surf_alloc.comp) +add_shader(surf_alloc2.comp lighting/surfels/surf_alloc2.comp) + # Pathtracing add_shader(pathtrace.frag lighting/pt/pathtrace.frag -DRAY_QUERY -DRAY_QUERY_AT) diff --git a/shader/lighting/rt_dbg/hash_dbg.frag b/shader/lighting/rt_dbg/hash_dbg.frag new file mode 100644 index 000000000..847cb4909 --- /dev/null +++ b/shader/lighting/rt_dbg/hash_dbg.frag @@ -0,0 +1,96 @@ +#version 460 + +#include "scene.glsl" +#include "common.glsl" + +layout(location = 0) in vec2 inUV; +layout(location = 0) out vec4 outColor; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1) uniform texture2D depth; + +uint pcg(uint v) { + uint state = v * 747796405u + 2891336453u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; + } + +uint computeDepthSlice(float linDepth, float near, float far, uint num_slices) { + float z = linDepth; + // Compute logarithmic slice index + float slice_float = log(z / near) * (float(num_slices) / log(far / near)); + // Clamp to ensure it doesn't exceed the grid bounds + return clamp(uint(slice_float), 0u, num_slices - 1u); + } + +float computeTargetCellSize(float d, float aperture, vec2 resolution, float pixelFeatureSize) { + // Equation 2: Evaluate the angular factor based on resolution aspect ratio + float term1 = aperture / resolution.x; + float term2 = (aperture * resolution.x) / (resolution.y * resolution.y); + float maxFactor = max(term1, term2); + + // Compute target feature size in world space + float sw = d * tan(maxFactor * pixelFeatureSize); + return sw; + } + +// Computes the discretized cell size (s_wd) rounding to the nearest power-of-two level +float computeAdaptiveCellSize(float sw, float smin) { + // Avoid log2 of zero or negative numbers if sw is too small + if(sw <= smin) + return smin; + + // Equation 3: Discretize to power-of-two bands to create discrete levels of detail + float logScale = floor(log2(sw / smin)); + float swd = pow(2.0, logScale) * smin; + return swd; + } + +float computeCellSize(float d, float fov, vec2 resolution, + float pixelFeatureSize, float smin) { + float sw = computeTargetCellSize(d, fov, resolution, pixelFeatureSize); + return computeAdaptiveCellSize(sw, smin); + } + +float surfDist(vec3 pos, float cellSize) { + pos /= cellSize; + vec3 p = floor(pos) + 0.5 - (pos); + p *= 2/sqrt(2.0); + return dot(p,p); //quad distance + } + +uint surfHash(vec3 pos, float cellSize) { + ivec3 p = ivec3(pos / cellSize); + uint hashKey = pcg(p.x + pcg(p.y + pcg(p.z))); + return hashKey; + } + +void main(void) { + const float d = texelFetch(depth, ivec2(gl_FragCoord.xy), 0).r; + if(d>=1.0) + discard; + + const float lD = max(linearDepth(d, scene.clipInfo), 10); + const mat4 inv = scene.viewProjectLwcInv; + const vec4 pos = inv*vec4(inUV * 2.0 - 1.0, d, 1); + + float fov = 67.5f*M_PI/180.0; + float cellSize = 25; + + // float sz = computeCellSize(lD, fov, textureSize(depth,0), 16, cellSize); + // float sz = computeCellSize(lD, fov, textureSize(depth,0), 2, 1); + float sz = computeCellSize(lD, fov, textureSize(depth,0), 32, 1); + uint h = surfHash(pos.xyz/pos.w + originLwc, sz); + float dx = surfDist(pos.xyz/pos.w + originLwc, sz); + //uint sx = computeDepthSlice(lD, 10, 100000, 32); + + // outColor = vec4(debugColors[h%debugColors.length()], 1.0); + outColor = vec4(dx * debugColors[h%debugColors.length()], 1.0); + // outColor = vec4(dx); + // outColor = vec4(debugColors[sx%debugColors.length()], 1.0); + } diff --git a/shader/lighting/surfels/surf_alloc.comp b/shader/lighting/surfels/surf_alloc.comp new file mode 100644 index 000000000..0c6d6097a --- /dev/null +++ b/shader/lighting/surfels/surf_alloc.comp @@ -0,0 +1,116 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +const float fov = 67.5f*M_PI/180.0; + +layout(local_size_x = 16, local_size_y = 16) in; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; + +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; + +layout(binding = 11, rgba8) uniform image2D dbgImage; + +shared uint vote; +void makeVote(ivec2 at) { + atomicMin(vote, (at.x + at.y*gl_WorkGroupSize.x)); + } + +vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { + const mat4 inv = scene.viewProjectLwcInv; + // const mat4 inv = scene.viewProjectInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return pos.xyz/pos.w + originLwc; + } + +float surfDist(vec3 pos, vec3 norm, float cellSize) { +#if 1 + pos = pos/cellSize; + + vec3 p = floor(pos + sign(norm)*0.5)+0.5 - (pos); + p *= 2/sqrt(2.0); + return dot(p,p); //quad distance +#else + pos = pos/cellSize; + vec3 p = floor(pos)+0.5 - (pos); + p *= 2/sqrt(2.0); + return dot(p,p); //quad distance +#endif + } + +uint surfHash(vec3 pos, float cellSize) { + ivec3 p = ivec3(pos / cellSize); + uint hashKey = pcg(p.x + pcg(p.y + pcg(p.z))); + return hashKey; + } + +uint packSurfId(float dist, ivec2 fragCoord, ivec2 screenSize) { + uint lo = (fragCoord.x + fragCoord.y*screenSize.x) & 0x0FFFFFF; + uint up = min(uint(dist * 0xFF), 0xFF) << 24; + return up | lo; + } + +float computeCellSize2(float z, float px, float minSz) { + float clipRadius = (2.0 * px) * scene.screenResInv.y; + float worldRadius = clipRadius * (-z) / scene.project[1][1]; + + int fib = int(worldRadius/minSz); + int prev = 1; + for(int i=1; i= SKY_DEPTH) + return; + + const vec3 pos = worldPos(z, fragCoord, screenSize); + const float ld = max(linearDepth(z, scene.clipInfo), 10); + + // const float sz = computeCellSize2(z, 32, 5); + const float sz = computeCellSize(ld, fov, textureSize(depth,0), 32, 1); + // const float sz = computeCellSize(ld, fov, textureSize(depth,0), 64, 5); + + const float dist = surfDist(pos, norm, sz); + const uint hKey = surfHash(pos, sz) % hashGrid.length(); + + if(dist<0) + return; + + const uint sId = packSurfId(dist, fragCoord, screenSize); + atomicMin(hashGrid[hKey], sId); + + imageStore(dbgImage, fragCoord, vec4(debugColors[hKey%debugColors.length()], 1.0)); + } + diff --git a/shader/lighting/surfels/surf_alloc2.comp b/shader/lighting/surfels/surf_alloc2.comp new file mode 100644 index 000000000..5c292abb5 --- /dev/null +++ b/shader/lighting/surfels/surf_alloc2.comp @@ -0,0 +1,60 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +const float fov = 67.5f*M_PI/180.0; +const float cellSize = 25; + +layout(local_size_x = 64) in; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; + +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; + +vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { + const mat4 inv = scene.viewProjectLwcInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return pos.xyz/pos.w + originLwc; + } + +ivec2 unpackSurfId(uint pkg, ivec2 screenSize) { + pkg &= 0x0FFFFFF; + return ivec2(pkg%screenSize.x, pkg/screenSize.x); + } + +void main() { + const uint hKey = gl_GlobalInvocationID.x; + if(hKey >= hashGrid.length()) + return; + + const uint sId = hashGrid[hKey]; + if(sId==0xFFFFFFFF) + return; + + const ivec2 screenSize = ivec2(textureSize(depth,0)); + const ivec2 fragCoord = unpackSurfId(sId, screenSize); + + const uint id = atomicAdd(count.x, 1); + if(id>=surfels.length()) + return; + + const float z = texelFetch(depth, fragCoord, 0).x; + const vec3 pos = worldPos(z, fragCoord, screenSize); + + Surfel sx; + sx.pos = pos; + sx.norm = texelFetch(gbufNormal, fragCoord, 0).r; + surfels[id] = sx; + } diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl new file mode 100644 index 000000000..0c36b0447 --- /dev/null +++ b/shader/lighting/surfels/surf_common.glsl @@ -0,0 +1,52 @@ +#ifndef SURF_COMMON_GLSL +#define SURF_COMMON_GLSL + +const float SKY_DEPTH = 0.999995; + +struct Surfel { + vec3 pos; + uint norm; + }; + +uint pcg(uint v) { + uint state = v * 747796405u + 2891336453u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; + } + +float computeTargetCellSize(float d, float aperture, vec2 resolution, float pixelFeatureSize) { + // Equation 2: Evaluate the angular factor based on resolution aspect ratio + float term1 = aperture / resolution.x; + float term2 = (aperture * resolution.x) / (resolution.y * resolution.y); + float maxFactor = max(term1, term2); + + // Compute target feature size in world space + float sw = d * tan(maxFactor * pixelFeatureSize); + return sw; + } + +// Computes the discretized cell size (s_wd) rounding to the nearest power-of-two level +float computeAdaptiveCellSize(float sw, float smin) { + // Avoid log2 of zero or negative numbers if sw is too small + if(sw <= smin) + return smin; + + // Equation 3: Discretize to power-of-two bands to create discrete levels of detail + float logScale = floor(log2(sw / smin)); + float swd = pow(2.0, logScale) * smin; + return swd; + } + +float computeCellSize(float d, float fov, vec2 resolution, + float pixelFeatureSize, float smin) { + float sw = computeTargetCellSize(d, fov, resolution, pixelFeatureSize); + return computeAdaptiveCellSize(sw, smin); + } + +uint hash(vec3 pos, float cellSize) { + ivec3 p = ivec3(floor(pos / cellSize)); + uint hashKey = pcg(uint(cellSize) + pcg(p.x + pcg(p.y + pcg(p.z)))); + return hashKey; + } + +#endif \ No newline at end of file diff --git a/shader/lighting/surfels/surf_dbg.frag b/shader/lighting/surfels/surf_dbg.frag new file mode 100644 index 000000000..354c01cb4 --- /dev/null +++ b/shader/lighting/surfels/surf_dbg.frag @@ -0,0 +1,49 @@ +#version 460 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; + +layout(location = 0) in vec3 center; +layout(location = 1) in vec3 normal; +layout(location = 2) in float radius; +layout(location = 3) in flat uint instanceIndex; + +layout(location = 0) out vec4 outColor; + +vec3 unprojectDepth(float z) { + const vec2 fragCoord = (gl_FragCoord.xy*scene.screenResInv)*2.0-vec2(1.0); + const vec4 pos = vec4(fragCoord.xy, z, 1.0);///gl_FragCoord.w); + const vec4 ret = scene.viewProjectInv*pos; + return (ret.xyz/ret.w); + } + +void main(void) { + //vec3 norm = normalFetch(gbufNormal, ivec2(gl_FragCoord.xy)); + float z = texelFetch(depth, ivec2(gl_FragCoord.xy), 0).x; + vec3 wpos = unprojectDepth(z); + vec3 view = normalize(wpos-scene.camPos); + + const Surfel p = surfels[instanceIndex]; + const vec3 delta = wpos - center; + const float distToPlane = dot(delta, normal); + const vec3 projectedPoint = (delta - distToPlane * normal) / radius; + const float qDist = dot(projectedPoint, projectedPoint); + + if(qDist > 1) + discard; + + if(length(delta) > radius) + ;//discard; + + vec3 clr = debugColors[instanceIndex % debugColors.length()] * (1.0-qDist); + outColor = vec4(clr,1.0); + // outColor = vec4(1,0,0,1.0); + } diff --git a/shader/lighting/surfels/surf_dbg.vert b/shader/lighting/surfels/surf_dbg.vert new file mode 100644 index 000000000..a8b9acfe5 --- /dev/null +++ b/shader/lighting/surfels/surf_dbg.vert @@ -0,0 +1,71 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 3) uniform sampler2D depth; + +layout(location = 0) out vec3 center; +layout(location = 1) out vec3 normal; +layout(location = 2) out float radius; +layout(location = 3) out flat uint instanceIndex; + +const vec3 v[8] = { + {-1,-1,-1}, + { 1,-1,-1}, + { 1, 1,-1}, + {-1, 1,-1}, + + {-1,-1, 1}, + { 1,-1, 1}, + { 1, 1, 1}, + {-1, 1, 1}, + }; + +const uint index[36] = { + 0, 1, 3, 3, 1, 2, + 1, 5, 2, 2, 5, 6, + 5, 4, 6, 6, 4, 7, + 4, 0, 7, 7, 0, 3, + 3, 2, 7, 7, 2, 6, + 4, 5, 0, 0, 5, 1 + }; + +uint surfHash(vec3 pos, float cellSize) { + ivec3 p = ivec3(pos / cellSize); + uint hashKey = pcg(p.x + pcg(p.y + pcg(p.z))); + return hashKey; + } + +void main() { + const uint surfelId = gl_InstanceIndex; + if(surfelId>=count.x) { + gl_Position = vec4(0); + return; + } + + Surfel p = surfels[surfelId]; + + const vec3 vert = v[index[gl_VertexIndex]]; + const vec4 pp = scene.viewProject * vec4(p.pos, 1.0); + + float pixelRadius = 4.0; + float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; + float worldRadius = clipRadius * (-pp.z) / scene.project[1][1]; + + //radius = 5; + radius = worldRadius; + gl_Position = scene.viewProject * vec4(p.pos + vert * radius, 1.0); + center = p.pos; + normal = decodeNormal(p.norm); + + const float ld = max(linearDepth(pp.z/pp.w, scene.clipInfo), 10); + const float fov = 67.5f*M_PI/180.0; + const float sz = computeCellSize(ld, fov, textureSize(depth,0), 64, 1); + instanceIndex = surfHash(p.pos, 5); //surfelId; + } diff --git a/shader/lighting/surfels/surf_init.comp b/shader/lighting/surfels/surf_init.comp new file mode 100644 index 000000000..b40fb99b3 --- /dev/null +++ b/shader/lighting/surfels/surf_init.comp @@ -0,0 +1,12 @@ +#version 450 + +layout(local_size_x = 64) in; + +layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; + +void main() { + const uint hKey = gl_GlobalInvocationID.x; + if(hKey >= hashGrid.length()) + return; + hashGrid[hKey] = 0xFFFFFFFF; + } From 01963e7668b12fd0ca692237586b21a6d58fde05 Mon Sep 17 00:00:00 2001 From: Try Date: Wed, 27 May 2026 22:38:26 +0200 Subject: [PATCH 02/52] spatial hashing in progress --- shader/lighting/rt_dbg/hash_dbg.frag | 34 +++++++++++++---------- shader/lighting/surfels/surf_alloc.comp | 36 ++++++++++++++++++------- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/shader/lighting/rt_dbg/hash_dbg.frag b/shader/lighting/rt_dbg/hash_dbg.frag index 847cb4909..93e6bc102 100644 --- a/shader/lighting/rt_dbg/hash_dbg.frag +++ b/shader/lighting/rt_dbg/hash_dbg.frag @@ -20,12 +20,12 @@ uint pcg(uint v) { return (word >> 22u) ^ word; } -uint computeDepthSlice(float linDepth, float near, float far, uint num_slices) { +uint computeDepthSlice(float linDepth, float near, float far, uint numSlices) { float z = linDepth; // Compute logarithmic slice index - float slice_float = log(z / near) * (float(num_slices) / log(far / near)); + float slice_float = log(z / near) * (float(numSlices) / log(far / near)); // Clamp to ensure it doesn't exceed the grid bounds - return clamp(uint(slice_float), 0u, num_slices - 1u); + return clamp(uint(slice_float), 0u, numSlices - 1u); } float computeTargetCellSize(float d, float aperture, vec2 resolution, float pixelFeatureSize) { @@ -57,15 +57,19 @@ float computeCellSize(float d, float fov, vec2 resolution, return computeAdaptiveCellSize(sw, smin); } -float surfDist(vec3 pos, float cellSize) { - pos /= cellSize; - vec3 p = floor(pos) + 0.5 - (pos); - p *= 2/sqrt(2.0); +ivec3 hasGridPos(vec3 wpos, float cellSize) { + wpos = wpos / cellSize; + return ivec3(round(wpos)); + } + +float surfDist(ivec3 hpos, vec3 pos, float cellSize) { + vec3 p = (pos/cellSize - hpos); + p *= 2;///sqrt(2.0); return dot(p,p); //quad distance } -uint surfHash(vec3 pos, float cellSize) { - ivec3 p = ivec3(pos / cellSize); +uint surfHash(ivec3 hpos) { + ivec3 p = hpos; uint hashKey = pcg(p.x + pcg(p.y + pcg(p.z))); return hashKey; } @@ -84,13 +88,15 @@ void main(void) { // float sz = computeCellSize(lD, fov, textureSize(depth,0), 16, cellSize); // float sz = computeCellSize(lD, fov, textureSize(depth,0), 2, 1); - float sz = computeCellSize(lD, fov, textureSize(depth,0), 32, 1); - uint h = surfHash(pos.xyz/pos.w + originLwc, sz); - float dx = surfDist(pos.xyz/pos.w + originLwc, sz); + float sz = computeCellSize(lD, fov, textureSize(depth,0), 32, 1); + vec3 wpos = pos.xyz/pos.w + originLwc; + ivec3 ipos = hasGridPos(wpos, sz); + uint h = surfHash(ipos); + float dx = surfDist(ipos, wpos, sz); //uint sx = computeDepthSlice(lD, 10, 100000, 32); // outColor = vec4(debugColors[h%debugColors.length()], 1.0); - outColor = vec4(dx * debugColors[h%debugColors.length()], 1.0); - // outColor = vec4(dx); + // outColor = vec4(dx * debugColors[h%debugColors.length()], 1.0); + outColor = vec4(dx); // outColor = vec4(debugColors[sx%debugColors.length()], 1.0); } diff --git a/shader/lighting/surfels/surf_alloc.comp b/shader/lighting/surfels/surf_alloc.comp index 0c6d6097a..3aadd02b6 100644 --- a/shader/lighting/surfels/surf_alloc.comp +++ b/shader/lighting/surfels/surf_alloc.comp @@ -37,7 +37,7 @@ vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { } float surfDist(vec3 pos, vec3 norm, float cellSize) { -#if 1 +#if 0 pos = pos/cellSize; vec3 p = floor(pos + sign(norm)*0.5)+0.5 - (pos); @@ -79,6 +79,23 @@ float computeCellSize2(float z, float px, float minSz) { return max(worldRadius, minSz); } +ivec3 hasGridPos(vec3 wpos, float cellSize) { + wpos = wpos / cellSize; + return ivec3(round(wpos)); + } + +float surfDist(ivec3 hpos, vec3 pos, float cellSize) { + vec3 p = (pos/cellSize - hpos); + p *= 2;///sqrt(2.0); + return dot(p,p); //quad distance + } + +uint surfHash(ivec3 hpos) { + ivec3 p = hpos; + uint hashKey = pcg(p.x + pcg(p.y + pcg(p.z))); + return hashKey; + } + void main() { if(gl_GlobalInvocationID.xy==ivec2(0)) count = uvec4(0); @@ -95,18 +112,17 @@ void main() { if(z >= SKY_DEPTH) return; - const vec3 pos = worldPos(z, fragCoord, screenSize); - const float ld = max(linearDepth(z, scene.clipInfo), 10); + const vec3 wpos = worldPos(z, fragCoord, screenSize); + const float ld = max(linearDepth(z, scene.clipInfo), 10); - // const float sz = computeCellSize2(z, 32, 5); - const float sz = computeCellSize(ld, fov, textureSize(depth,0), 32, 1); - // const float sz = computeCellSize(ld, fov, textureSize(depth,0), 64, 5); + const float sz = computeCellSize(ld, fov, textureSize(depth,0), 32, 1); + const ivec3 ipos = hasGridPos(wpos, sz); + const float dist = surfDist(ipos, wpos, sz); - const float dist = surfDist(pos, norm, sz); - const uint hKey = surfHash(pos, sz) % hashGrid.length(); + const uint hKey = surfHash(ipos) % hashGrid.length(); - if(dist<0) - return; + if(dist>0.5) + ;//return; const uint sId = packSurfId(dist, fragCoord, screenSize); atomicMin(hashGrid[hKey], sId); From a71d7f3d842513269da9a2da373227932d430612 Mon Sep 17 00:00:00 2001 From: Try Date: Wed, 27 May 2026 22:59:41 +0200 Subject: [PATCH 03/52] spatial hashing in progress --- game/graphics/renderer.cpp | 8 +- game/graphics/shaders.cpp | 6 +- game/graphics/shaders.h | 2 +- shader/CMakeLists.txt | 2 +- shader/lighting/rt_dbg/hash_dbg.frag | 40 +------- shader/lighting/surfels/surf_alloc.comp | 112 ++++------------------- shader/lighting/surfels/surf_alloc2.comp | 60 ------------ shader/lighting/surfels/surf_common.glsl | 20 ++-- shader/lighting/surfels/surf_dbg.vert | 18 +++- shader/lighting/surfels/surf_vote.comp | 94 +++++++++++++++++++ 10 files changed, 150 insertions(+), 212 deletions(-) delete mode 100644 shader/lighting/surfels/surf_alloc2.comp create mode 100644 shader/lighting/surfels/surf_vote.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index c8748f064..329f150c7 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -679,7 +679,7 @@ void Renderer::draw(Tempest::Attachment& result, Encoder& cmd, ui cmd.setDebugMarker("Translucent"); wview->drawTranslucent(cmd, fId); - //drawHashDbg(sceneLinear, cmd, *wview); + drawHashDbg(sceneLinear, cmd, *wview); drawProbesDbg(cmd, *wview); drawProbesHitDbg(cmd); drawSurfelsDbg(cmd, *wview); @@ -1940,7 +1940,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setDebugMarker("Surfels"); auto& scene = wview.sceneGlobals(); - auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc.sizeofBuffer(4, surf.maxSurfels)); + auto& surfels = usesSsboInit(surf.surfels, shaders.surfVote.sizeofBuffer(4, surf.maxSurfels)); auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); auto& hashGrid = usesSsboInit(surf.hashGrid, hashGridSize); @@ -1963,10 +1963,10 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setPipeline(shaders.surfInit); cmd.dispatchThreads(hashGridSize); - cmd.setPipeline(shaders.surfAlloc); + cmd.setPipeline(shaders.surfVote); cmd.dispatchThreads(sceneDepth.size()); - cmd.setPipeline(shaders.surfAlloc2); + cmd.setPipeline(shaders.surfAlloc); cmd.dispatchThreads(hashGridSize); //alloc = false; } diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 674088149..db725903f 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -248,9 +248,9 @@ void Shaders::compileShaders() { auto fs = device.shader(sh.data,sh.len); surfDbg = device.pipeline(Triangles,state,vs,fs); - surfInit = computeShader("surf_init.comp.sprv"); - surfAlloc = computeShader("surf_alloc.comp.sprv"); - surfAlloc2 = computeShader("surf_alloc2.comp.sprv"); + surfInit = computeShader("surf_init.comp.sprv"); + surfVote = computeShader("surf_vote.comp.sprv"); + surfAlloc = computeShader("surf_alloc.comp.sprv"); } if(Shaders::isVsmSupported()) { diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 9673cbc88..6632b1787 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -86,7 +86,7 @@ class Shaders { // GI-Surf Tempest::RenderPipeline surfDbg; - Tempest::ComputePipeline surfInit, surfAlloc, surfAlloc2; + Tempest::ComputePipeline surfInit, surfVote, surfAlloc; // Epipolar Tempest::ComputePipeline fogEpipolarVsm; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 492643d2c..ae7f2e1eb 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -312,8 +312,8 @@ add_shader(surf_dbg.vert lighting/surfels/surf_dbg.vert) add_shader(surf_dbg.frag lighting/surfels/surf_dbg.frag) add_shader(surf_init.comp lighting/surfels/surf_init.comp) +add_shader(surf_vote.comp lighting/surfels/surf_vote.comp) add_shader(surf_alloc.comp lighting/surfels/surf_alloc.comp) -add_shader(surf_alloc2.comp lighting/surfels/surf_alloc2.comp) # Pathtracing add_shader(pathtrace.frag lighting/pt/pathtrace.frag -DRAY_QUERY -DRAY_QUERY_AT) diff --git a/shader/lighting/rt_dbg/hash_dbg.frag b/shader/lighting/rt_dbg/hash_dbg.frag index 93e6bc102..f7dcfe81c 100644 --- a/shader/lighting/rt_dbg/hash_dbg.frag +++ b/shader/lighting/rt_dbg/hash_dbg.frag @@ -1,5 +1,6 @@ #version 460 +#include "lighting/surfels/surf_common.glsl" #include "scene.glsl" #include "common.glsl" @@ -14,12 +15,6 @@ layout(binding = 0, std140) uniform UboScene { }; layout(binding = 1) uniform texture2D depth; -uint pcg(uint v) { - uint state = v * 747796405u + 2891336453u; - uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; - return (word >> 22u) ^ word; - } - uint computeDepthSlice(float linDepth, float near, float far, uint numSlices) { float z = linDepth; // Compute logarithmic slice index @@ -28,35 +23,6 @@ uint computeDepthSlice(float linDepth, float near, float far, uint numSlices) { return clamp(uint(slice_float), 0u, numSlices - 1u); } -float computeTargetCellSize(float d, float aperture, vec2 resolution, float pixelFeatureSize) { - // Equation 2: Evaluate the angular factor based on resolution aspect ratio - float term1 = aperture / resolution.x; - float term2 = (aperture * resolution.x) / (resolution.y * resolution.y); - float maxFactor = max(term1, term2); - - // Compute target feature size in world space - float sw = d * tan(maxFactor * pixelFeatureSize); - return sw; - } - -// Computes the discretized cell size (s_wd) rounding to the nearest power-of-two level -float computeAdaptiveCellSize(float sw, float smin) { - // Avoid log2 of zero or negative numbers if sw is too small - if(sw <= smin) - return smin; - - // Equation 3: Discretize to power-of-two bands to create discrete levels of detail - float logScale = floor(log2(sw / smin)); - float swd = pow(2.0, logScale) * smin; - return swd; - } - -float computeCellSize(float d, float fov, vec2 resolution, - float pixelFeatureSize, float smin) { - float sw = computeTargetCellSize(d, fov, resolution, pixelFeatureSize); - return computeAdaptiveCellSize(sw, smin); - } - ivec3 hasGridPos(vec3 wpos, float cellSize) { wpos = wpos / cellSize; return ivec3(round(wpos)); @@ -64,7 +30,7 @@ ivec3 hasGridPos(vec3 wpos, float cellSize) { float surfDist(ivec3 hpos, vec3 pos, float cellSize) { vec3 p = (pos/cellSize - hpos); - p *= 2;///sqrt(2.0); + p *= 2/sqrt(2.0); return dot(p,p); //quad distance } @@ -88,7 +54,7 @@ void main(void) { // float sz = computeCellSize(lD, fov, textureSize(depth,0), 16, cellSize); // float sz = computeCellSize(lD, fov, textureSize(depth,0), 2, 1); - float sz = computeCellSize(lD, fov, textureSize(depth,0), 32, 1); + float sz = computeCellSize(lD, fov, textureSize(depth,0), SURFEL_CELL); vec3 wpos = pos.xyz/pos.w + originLwc; ivec3 ipos = hasGridPos(wpos, sz); uint h = surfHash(ipos); diff --git a/shader/lighting/surfels/surf_alloc.comp b/shader/lighting/surfels/surf_alloc.comp index 3aadd02b6..5c292abb5 100644 --- a/shader/lighting/surfels/surf_alloc.comp +++ b/shader/lighting/surfels/surf_alloc.comp @@ -5,8 +5,9 @@ #include "common.glsl" const float fov = 67.5f*M_PI/180.0; +const float cellSize = 25; -layout(local_size_x = 16, local_size_y = 16) in; +layout(local_size_x = 64) in; layout(std140, push_constant) uniform Push { vec3 originLwc; @@ -21,112 +22,39 @@ layout(binding = 3) uniform sampler2D depth; layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; -layout(binding = 11, rgba8) uniform image2D dbgImage; - -shared uint vote; -void makeVote(ivec2 at) { - atomicMin(vote, (at.x + at.y*gl_WorkGroupSize.x)); - } - vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { const mat4 inv = scene.viewProjectLwcInv; - // const mat4 inv = scene.viewProjectInv; const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); return pos.xyz/pos.w + originLwc; } -float surfDist(vec3 pos, vec3 norm, float cellSize) { -#if 0 - pos = pos/cellSize; - - vec3 p = floor(pos + sign(norm)*0.5)+0.5 - (pos); - p *= 2/sqrt(2.0); - return dot(p,p); //quad distance -#else - pos = pos/cellSize; - vec3 p = floor(pos)+0.5 - (pos); - p *= 2/sqrt(2.0); - return dot(p,p); //quad distance -#endif - } - -uint surfHash(vec3 pos, float cellSize) { - ivec3 p = ivec3(pos / cellSize); - uint hashKey = pcg(p.x + pcg(p.y + pcg(p.z))); - return hashKey; - } - -uint packSurfId(float dist, ivec2 fragCoord, ivec2 screenSize) { - uint lo = (fragCoord.x + fragCoord.y*screenSize.x) & 0x0FFFFFF; - uint up = min(uint(dist * 0xFF), 0xFF) << 24; - return up | lo; - } - -float computeCellSize2(float z, float px, float minSz) { - float clipRadius = (2.0 * px) * scene.screenResInv.y; - float worldRadius = clipRadius * (-z) / scene.project[1][1]; - - int fib = int(worldRadius/minSz); - int prev = 1; - for(int i=1; i= hashGrid.length()) return; - const float z = texelFetch(depth,fragCoord,0).x; - const vec3 norm = normalFetch(gbufNormal,fragCoord); - if(z >= SKY_DEPTH) + const uint sId = hashGrid[hKey]; + if(sId==0xFFFFFFFF) return; - const vec3 wpos = worldPos(z, fragCoord, screenSize); - const float ld = max(linearDepth(z, scene.clipInfo), 10); - - const float sz = computeCellSize(ld, fov, textureSize(depth,0), 32, 1); - const ivec3 ipos = hasGridPos(wpos, sz); - const float dist = surfDist(ipos, wpos, sz); - - const uint hKey = surfHash(ipos) % hashGrid.length(); + const ivec2 screenSize = ivec2(textureSize(depth,0)); + const ivec2 fragCoord = unpackSurfId(sId, screenSize); - if(dist>0.5) - ;//return; + const uint id = atomicAdd(count.x, 1); + if(id>=surfels.length()) + return; - const uint sId = packSurfId(dist, fragCoord, screenSize); - atomicMin(hashGrid[hKey], sId); + const float z = texelFetch(depth, fragCoord, 0).x; + const vec3 pos = worldPos(z, fragCoord, screenSize); - imageStore(dbgImage, fragCoord, vec4(debugColors[hKey%debugColors.length()], 1.0)); + Surfel sx; + sx.pos = pos; + sx.norm = texelFetch(gbufNormal, fragCoord, 0).r; + surfels[id] = sx; } - diff --git a/shader/lighting/surfels/surf_alloc2.comp b/shader/lighting/surfels/surf_alloc2.comp deleted file mode 100644 index 5c292abb5..000000000 --- a/shader/lighting/surfels/surf_alloc2.comp +++ /dev/null @@ -1,60 +0,0 @@ -#version 450 - -#include "lighting/surfels/surf_common.glsl" -#include "scene.glsl" -#include "common.glsl" - -const float fov = 67.5f*M_PI/180.0; -const float cellSize = 25; - -layout(local_size_x = 64) in; - -layout(std140, push_constant) uniform Push { - vec3 originLwc; - }; -layout(binding = 0, std140) uniform UboScene { - SceneDesc scene; - }; - -layout(binding = 1) uniform sampler2D gbufDiffuse; -layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform sampler2D depth; -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; - -vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { - const mat4 inv = scene.viewProjectLwcInv; - const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; - const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); - return pos.xyz/pos.w + originLwc; - } - -ivec2 unpackSurfId(uint pkg, ivec2 screenSize) { - pkg &= 0x0FFFFFF; - return ivec2(pkg%screenSize.x, pkg/screenSize.x); - } - -void main() { - const uint hKey = gl_GlobalInvocationID.x; - if(hKey >= hashGrid.length()) - return; - - const uint sId = hashGrid[hKey]; - if(sId==0xFFFFFFFF) - return; - - const ivec2 screenSize = ivec2(textureSize(depth,0)); - const ivec2 fragCoord = unpackSurfId(sId, screenSize); - - const uint id = atomicAdd(count.x, 1); - if(id>=surfels.length()) - return; - - const float z = texelFetch(depth, fragCoord, 0).x; - const vec3 pos = worldPos(z, fragCoord, screenSize); - - Surfel sx; - sx.pos = pos; - sx.norm = texelFetch(gbufNormal, fragCoord, 0).r; - surfels[id] = sx; - } diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 0c36b0447..2c14d4da2 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -1,7 +1,9 @@ #ifndef SURF_COMMON_GLSL #define SURF_COMMON_GLSL -const float SKY_DEPTH = 0.999995; +const float SKY_DEPTH = 0.999995; +const float SURFEL_FOOTPRINT = 64; +const float SURFEL_CELL = 32;//SURFEL_FOOTPRINT/sqrt(2); struct Surfel { vec3 pos; @@ -26,21 +28,21 @@ float computeTargetCellSize(float d, float aperture, vec2 resolution, float pixe } // Computes the discretized cell size (s_wd) rounding to the nearest power-of-two level -float computeAdaptiveCellSize(float sw, float smin) { +float computeAdaptiveCellSize(float sw, float sMin) { // Avoid log2 of zero or negative numbers if sw is too small - if(sw <= smin) - return smin; + if(sw <= sMin) + return sMin; // Equation 3: Discretize to power-of-two bands to create discrete levels of detail - float logScale = floor(log2(sw / smin)); - float swd = pow(2.0, logScale) * smin; + float logScale = floor(log2(sw / sMin)); + float swd = pow(2.0, logScale) * sMin; return swd; } -float computeCellSize(float d, float fov, vec2 resolution, - float pixelFeatureSize, float smin) { +float computeCellSize(float d, float fov, vec2 resolution, float pixelFeatureSize) { + const float sMin = 1; // min 1 centimeter float sw = computeTargetCellSize(d, fov, resolution, pixelFeatureSize); - return computeAdaptiveCellSize(sw, smin); + return computeAdaptiveCellSize(sw, sMin); } uint hash(vec3 pos, float cellSize) { diff --git a/shader/lighting/surfels/surf_dbg.vert b/shader/lighting/surfels/surf_dbg.vert index a8b9acfe5..fc30290ea 100644 --- a/shader/lighting/surfels/surf_dbg.vert +++ b/shader/lighting/surfels/surf_dbg.vert @@ -36,8 +36,13 @@ const uint index[36] = { 4, 5, 0, 0, 5, 1 }; -uint surfHash(vec3 pos, float cellSize) { - ivec3 p = ivec3(pos / cellSize); +vec3 hasGridPos(vec3 wpos, float cellSize) { + wpos = wpos / cellSize; + return round(wpos); + } + +uint surfHash(vec3 hpos, float cellSize) { + ivec3 p = ivec3(round(hpos*cellSize)); uint hashKey = pcg(p.x + pcg(p.y + pcg(p.z))); return hashKey; } @@ -64,8 +69,11 @@ void main() { center = p.pos; normal = decodeNormal(p.norm); - const float ld = max(linearDepth(pp.z/pp.w, scene.clipInfo), 10); const float fov = 67.5f*M_PI/180.0; - const float sz = computeCellSize(ld, fov, textureSize(depth,0), 64, 1); - instanceIndex = surfHash(p.pos, 5); //surfelId; + const float ld = max(linearDepth(pp.z/pp.w, scene.clipInfo), 10); + + const float sz = computeCellSize(ld, fov, textureSize(depth,0), SURFEL_CELL); + const vec3 wpos = p.pos; + const vec3 ipos = hasGridPos(wpos, sz); + instanceIndex = surfHash(ipos, sz); } diff --git a/shader/lighting/surfels/surf_vote.comp b/shader/lighting/surfels/surf_vote.comp new file mode 100644 index 000000000..8663f1612 --- /dev/null +++ b/shader/lighting/surfels/surf_vote.comp @@ -0,0 +1,94 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +const float fov = 67.5f*M_PI/180.0; + +layout(local_size_x = 16, local_size_y = 16) in; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; + +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; + +layout(binding = 11, rgba8) uniform image2D dbgImage; + +shared uint vote; +void makeVote(ivec2 at) { + atomicMin(vote, (at.x + at.y*gl_WorkGroupSize.x)); + } + +vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { + const mat4 inv = scene.viewProjectLwcInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return pos.xyz/pos.w + originLwc; + } + +uint packSurfId(float dist, ivec2 fragCoord, ivec2 screenSize) { + uint lo = (fragCoord.x + fragCoord.y*screenSize.x) & 0x0FFFFFF; + uint up = min(uint(dist * 0xFF), 0xFF) << 24; + return up | lo; + } + +vec3 hasGridPos(vec3 wpos, float cellSize) { + wpos = wpos / cellSize; + return round(wpos); + } + +float surfDist(vec3 hpos, vec3 pos, float cellSize) { + vec3 p = (pos/cellSize - hpos); + p *= 2/sqrt(2.0); + return dot(p,p); //quad distance + } + +uint surfHash(vec3 hpos, float cellSize) { + ivec3 p = ivec3(round(hpos*cellSize)); + uint hashKey = pcg(p.x + pcg(p.y + pcg(p.z))); + return hashKey; + } + +void main() { + if(gl_GlobalInvocationID.xy==ivec2(0)) + count = uvec4(0); + + const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); + const ivec2 screenSize = ivec2(textureSize(depth,0)); + const bool valid = all(lessThan(fragCoord, screenSize)); + + if(!valid) + return; + + const float z = texelFetch(depth,fragCoord,0).x; + const vec3 norm = normalFetch(gbufNormal,fragCoord); + if(z >= SKY_DEPTH) + return; + + const vec3 wpos = worldPos(z, fragCoord, screenSize); + const float ld = max(linearDepth(z, scene.clipInfo), 10); + + const float sz = computeCellSize(ld, fov, textureSize(depth,0), SURFEL_CELL); + const vec3 ipos = hasGridPos(wpos, sz); + const float dist = surfDist(ipos, wpos, sz); + + const uint hKey = surfHash(ipos, sz) % hashGrid.length(); + + if(dist>0.5) + return; + + const uint sId = packSurfId(dist, fragCoord, screenSize); + atomicMin(hashGrid[hKey], sId); + + imageStore(dbgImage, fragCoord, vec4(debugColors[hKey%debugColors.length()], 1.0)); + } + From 79f3e058e0745ee25247abe4464aa2aca6f599e3 Mon Sep 17 00:00:00 2001 From: Try Date: Fri, 29 May 2026 01:36:53 +0200 Subject: [PATCH 04/52] improve hash functions --- shader/common.glsl | 15 +++++++++ shader/lighting/pt/pathtrace.frag | 9 ------ shader/lighting/rt_dbg/hash_dbg.frag | 2 +- shader/lighting/surfels/surf_common.glsl | 41 ++++++++++++++++++------ shader/lighting/surfels/surf_dbg.vert | 6 ++-- shader/lighting/surfels/surf_init.comp | 4 +++ shader/lighting/surfels/surf_vote.comp | 9 ------ shader/ssao/ssao.comp | 14 +++----- 8 files changed, 58 insertions(+), 42 deletions(-) diff --git a/shader/common.glsl b/shader/common.glsl index 512b656f1..e9e4d9348 100644 --- a/shader/common.glsl +++ b/shader/common.glsl @@ -335,6 +335,21 @@ vec3 normalFetch(in utexture2D gbufNormal, ivec2 p) { return decodeNormal(n); } +uint wangHash(inout uint seed) { + seed = uint(seed ^ uint(61)) ^ uint(seed >> uint(16)); + seed *= uint(9); + seed = seed ^ (seed >> 4); + seed *= uint(0x27d4eb2d); + seed = seed ^ (seed >> 15); + return seed; + } + +uint pcgHash(uint v) { + uint state = v * 747796405u + 2891336453u; + uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; + } + // PCG3D // https://www.jcgt.org/published/0009/03/02/ // https://www.shadertoy.com/view/XlGcRh diff --git a/shader/lighting/pt/pathtrace.frag b/shader/lighting/pt/pathtrace.frag index 10d868cb3..312ad5157 100644 --- a/shader/lighting/pt/pathtrace.frag +++ b/shader/lighting/pt/pathtrace.frag @@ -28,15 +28,6 @@ layout(binding = 2) uniform texture2D irradiance; layout(binding = 3) uniform sampler2D skyLUT; layout(binding = 4) uniform sampler2D textureSm1; -uint wangHash(inout uint seed) { - seed = uint(seed ^ uint(61)) ^ uint(seed >> uint(16)); - seed *= uint(9); - seed = seed ^ (seed >> 4); - seed *= uint(0x27d4eb2d); - seed = seed ^ (seed >> 15); - return seed; - } - uint srand(uvec2 fragCoord, uint seed) { return uint(uint(fragCoord.x) * uint(1973) + uint(fragCoord.y) * uint(9277) + uint(seed) * uint(26699)) | uint(1); } diff --git a/shader/lighting/rt_dbg/hash_dbg.frag b/shader/lighting/rt_dbg/hash_dbg.frag index f7dcfe81c..4a13ba1fb 100644 --- a/shader/lighting/rt_dbg/hash_dbg.frag +++ b/shader/lighting/rt_dbg/hash_dbg.frag @@ -36,7 +36,7 @@ float surfDist(ivec3 hpos, vec3 pos, float cellSize) { uint surfHash(ivec3 hpos) { ivec3 p = hpos; - uint hashKey = pcg(p.x + pcg(p.y + pcg(p.z))); + uint hashKey = pcgHash(p.x + pcgHash(p.y + pcgHash(p.z))); return hashKey; } diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 2c14d4da2..4ed6699e3 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -1,8 +1,10 @@ #ifndef SURF_COMMON_GLSL #define SURF_COMMON_GLSL +#include "common.glsl" + const float SKY_DEPTH = 0.999995; -const float SURFEL_FOOTPRINT = 64; +//const float SURFEL_FOOTPRINT = 64; const float SURFEL_CELL = 32;//SURFEL_FOOTPRINT/sqrt(2); struct Surfel { @@ -10,12 +12,6 @@ struct Surfel { uint norm; }; -uint pcg(uint v) { - uint state = v * 747796405u + 2891336453u; - uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; - return (word >> 22u) ^ word; - } - float computeTargetCellSize(float d, float aperture, vec2 resolution, float pixelFeatureSize) { // Equation 2: Evaluate the angular factor based on resolution aspect ratio float term1 = aperture / resolution.x; @@ -45,10 +41,35 @@ float computeCellSize(float d, float fov, vec2 resolution, float pixelFeatureSiz return computeAdaptiveCellSize(sw, sMin); } -uint hash(vec3 pos, float cellSize) { - ivec3 p = ivec3(floor(pos / cellSize)); - uint hashKey = pcg(uint(cellSize) + pcg(p.x + pcg(p.y + pcg(p.z)))); +uint surfHash(vec3 pos, float cellSize) { +#if 0 + ivec3 p = ivec3(round(pos * cellSize)); + uint hashKey = pcgHash(p.x + pcgHash(p.y + pcgHash(p.z))); return hashKey; +#else + ivec3 p = ivec3(round(pos * cellSize)); + + uint hash = 0x811C9DC5; + hash ^= p.x; + hash *= 0x01000193; // FNV-1a prime + hash = (hash << 13) | (hash >> 19); + + hash ^= p.y; + hash *= 0x01000193; + hash = (hash << 17) | (hash >> 15); + + hash ^= p.z; + hash *= 0x01000193; + + // 5. Avalanche step to ensure every input bit affects every output bit + hash ^= hash >> 16; + hash *= 0x7feb352d; + hash ^= hash >> 15; + hash *= 0x846ca68b; + hash ^= hash >> 16; + + return hash; +#endif } #endif \ No newline at end of file diff --git a/shader/lighting/surfels/surf_dbg.vert b/shader/lighting/surfels/surf_dbg.vert index fc30290ea..2907e2afb 100644 --- a/shader/lighting/surfels/surf_dbg.vert +++ b/shader/lighting/surfels/surf_dbg.vert @@ -41,9 +41,9 @@ vec3 hasGridPos(vec3 wpos, float cellSize) { return round(wpos); } -uint surfHash(vec3 hpos, float cellSize) { +uint surfHash_(vec3 hpos, float cellSize) { ivec3 p = ivec3(round(hpos*cellSize)); - uint hashKey = pcg(p.x + pcg(p.y + pcg(p.z))); + uint hashKey = pcgHash(p.x + pcgHash(p.y + pcgHash(p.z))); return hashKey; } @@ -59,7 +59,7 @@ void main() { const vec3 vert = v[index[gl_VertexIndex]]; const vec4 pp = scene.viewProject * vec4(p.pos, 1.0); - float pixelRadius = 4.0; + float pixelRadius = 5.0; float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; float worldRadius = clipRadius * (-pp.z) / scene.project[1][1]; diff --git a/shader/lighting/surfels/surf_init.comp b/shader/lighting/surfels/surf_init.comp index b40fb99b3..6104c98c8 100644 --- a/shader/lighting/surfels/surf_init.comp +++ b/shader/lighting/surfels/surf_init.comp @@ -2,9 +2,13 @@ layout(local_size_x = 64) in; +layout(binding = 4, std430) buffer SB0 { uvec4 count; }; layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; void main() { + if(gl_GlobalInvocationID.xy==ivec2(0)) + count = uvec4(0); + const uint hKey = gl_GlobalInvocationID.x; if(hKey >= hashGrid.length()) return; diff --git a/shader/lighting/surfels/surf_vote.comp b/shader/lighting/surfels/surf_vote.comp index 8663f1612..3b15abe60 100644 --- a/shader/lighting/surfels/surf_vote.comp +++ b/shader/lighting/surfels/surf_vote.comp @@ -52,16 +52,7 @@ float surfDist(vec3 hpos, vec3 pos, float cellSize) { return dot(p,p); //quad distance } -uint surfHash(vec3 hpos, float cellSize) { - ivec3 p = ivec3(round(hpos*cellSize)); - uint hashKey = pcg(p.x + pcg(p.y + pcg(p.z))); - return hashKey; - } - void main() { - if(gl_GlobalInvocationID.xy==ivec2(0)) - count = uvec4(0); - const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); const ivec2 screenSize = ivec2(textureSize(depth,0)); const bool valid = all(lessThan(fragCoord, screenSize)); diff --git a/shader/ssao/ssao.comp b/shader/ssao/ssao.comp index 1c0b66120..91b44d2eb 100644 --- a/shader/ssao/ssao.comp +++ b/shader/ssao/ssao.comp @@ -97,16 +97,10 @@ bool isSolved(float diff, int samples) { // return d < 0.1 + samples*0.005; } -float whangHashNoise(uvec2 uv, uint s) { +float wangHashNoise(uvec2 uv, uint s) { uint seed = (uv.x*1664525u + uv.y) + s; - - seed = (seed ^ 61u) ^(seed >> 16u); - seed *= 9u; - seed = seed ^(seed >> 4u); - seed *= uint(0x27d4eb2d); - seed = seed ^(seed >> 15u); - - float value = float(seed) / (4294967296.0); + uint hash = wangHash(seed); + float value = float(hash) / (4294967296.0); return value; } @@ -238,7 +232,7 @@ void main() { } // const float f0 = M_PI*2.0*interleavedGradientNoise(fragCoord); - const float f0 = M_PI*2.0*whangHashNoise(uvec2(fragCoord), 0); + const float f0 = M_PI*2.0*wangHashNoise(uvec2(fragCoord), 0); int maxSteps = estimateMaxSteps(at0.z); atomicMax(shMaxSteps, maxSteps); From 12a028e49e1ed27376dcd7ec3be08ad9aa8719ae Mon Sep 17 00:00:00 2001 From: Try Date: Sun, 31 May 2026 17:17:20 +0200 Subject: [PATCH 05/52] irradiance cache first prototype --- game/graphics/renderer.cpp | 55 ++++++++- game/graphics/renderer.h | 1 + game/graphics/shaders.cpp | 4 + game/graphics/shaders.h | 1 + shader/CMakeLists.txt | 3 + shader/lighting/surfels/irr_alloc.comp | 140 +++++++++++++++++++++++ shader/lighting/surfels/irr_mip.comp | 34 ++++++ shader/lighting/surfels/irr_scatter.comp | 101 ++++++++++++++++ shader/lighting/surfels/surf_dbg.vert | 14 ++- 9 files changed, 344 insertions(+), 9 deletions(-) create mode 100644 shader/lighting/surfels/irr_alloc.comp create mode 100644 shader/lighting/surfels/irr_mip.comp create mode 100644 shader/lighting/surfels/irr_scatter.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 329f150c7..1524e91ee 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -679,7 +679,7 @@ void Renderer::draw(Tempest::Attachment& result, Encoder& cmd, ui cmd.setDebugMarker("Translucent"); wview->drawTranslucent(cmd, fId); - drawHashDbg(sceneLinear, cmd, *wview); + // drawHashDbg(sceneLinear, cmd, *wview); drawProbesDbg(cmd, *wview); drawProbesHitDbg(cmd); drawSurfelsDbg(cmd, *wview); @@ -1936,15 +1936,17 @@ void Renderer::prepareEpipolar(Tempest::Encoder& cmd, Wo void Renderer::prepareSurfels(Tempest::Encoder& cmd, WorldView& wview) { static bool alloc = true; - const uint32_t hashGridSize = 4'194'304; // SHaRC docimentation recommends 2^22 + const uint32_t hashGridSize = 4'194'304; // SHaRC docimentation recommends 2^22 + static uint32_t maxSurfels = 8096; cmd.setDebugMarker("Surfels"); auto& scene = wview.sceneGlobals(); auto& surfels = usesSsboInit(surf.surfels, shaders.surfVote.sizeofBuffer(4, surf.maxSurfels)); auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); auto& hashGrid = usesSsboInit(surf.hashGrid, hashGridSize); + auto& pdfTree = usesImage2d (surf.pdfTree, TextureFormat::R32F, zbuffer.size(), true); - if(alloc) { + if(false && alloc) { struct Push { Vec3 originLwc; } push; @@ -1970,6 +1972,53 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatchThreads(hashGridSize); //alloc = false; } + + if(true && alloc) { + struct Push { + Vec3 originLwc; + uint32_t maxSurfels; + } push = {}; + push.originLwc = scene.originLwc; + push.maxSurfels = maxSurfels; + + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, hashGrid); + cmd.setBinding(6, pdfTree); + // + cmd.setBinding(11, dbgImage); + + cmd.setPipeline(shaders.surfInit); + cmd.dispatchThreads(hashGridSize); //for sake of zeroing counters + + cmd.setPipeline(shaders.irrAlloc); + cmd.dispatchThreads(sceneDepth.size()); + + uint32_t w = uint32_t(pdfTree.w()), h = uint32_t(pdfTree.h()); + cmd.setPipeline(shaders.irrMip); + for(uint32_t i=1; i(w/2, 1); + h = std::max(h/2, 1); + cmd.dispatchThreads(w,h); + } + + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, hashGrid); + cmd.setBinding(6, pdfTree); + cmd.setPipeline(shaders.irrScatter); + cmd.dispatchThreads(maxSurfels); + } } void Renderer::prepareIrradiance(Encoder& cmd, WorldView& wview) { diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index 5d259643a..8eb3c0246 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -213,6 +213,7 @@ class Renderer final { const uint32_t maxSurfels = 16*1024; Tempest::StorageBuffer surfels; Tempest::StorageBuffer hashGrid; + Tempest::StorageImage pdfTree; Tempest::StorageImage dbgImage; } surf; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index db725903f..b9c03ecab 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -251,6 +251,10 @@ void Shaders::compileShaders() { surfInit = computeShader("surf_init.comp.sprv"); surfVote = computeShader("surf_vote.comp.sprv"); surfAlloc = computeShader("surf_alloc.comp.sprv"); + + irrAlloc = computeShader("irr_alloc.comp.sprv"); + irrMip = computeShader("irr_mip.comp.sprv"); + irrScatter = computeShader("irr_scatter.comp.sprv"); } if(Shaders::isVsmSupported()) { diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 6632b1787..edaa9f643 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -87,6 +87,7 @@ class Shaders { // GI-Surf Tempest::RenderPipeline surfDbg; Tempest::ComputePipeline surfInit, surfVote, surfAlloc; + Tempest::ComputePipeline irrAlloc, irrMip, irrScatter; // Epipolar Tempest::ComputePipeline fogEpipolarVsm; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index ae7f2e1eb..33b393895 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -314,6 +314,9 @@ add_shader(surf_dbg.frag lighting/surfels/surf_dbg.frag) add_shader(surf_init.comp lighting/surfels/surf_init.comp) add_shader(surf_vote.comp lighting/surfels/surf_vote.comp) add_shader(surf_alloc.comp lighting/surfels/surf_alloc.comp) +add_shader(irr_alloc.comp lighting/surfels/irr_alloc.comp) +add_shader(irr_mip.comp lighting/surfels/irr_mip.comp) +add_shader(irr_scatter.comp lighting/surfels/irr_scatter.comp) # Pathtracing add_shader(pathtrace.frag lighting/pt/pathtrace.frag -DRAY_QUERY -DRAY_QUERY_AT) diff --git a/shader/lighting/surfels/irr_alloc.comp b/shader/lighting/surfels/irr_alloc.comp new file mode 100644 index 000000000..dfa9aeeae --- /dev/null +++ b/shader/lighting/surfels/irr_alloc.comp @@ -0,0 +1,140 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 16, local_size_y = 16) in; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; + +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +// +layout(binding = 6, r32f) uniform image2D pdfTree; +// +layout(binding = 11, rgba8) uniform image2D dbgImage; + + +ivec2 fragCoord; +ivec2 screenSize; + +vec3 worldPos(float z) { + const mat4 inv = scene.viewProjectLwcInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return pos.xyz/pos.w + originLwc; + } + +float wangHashNoise(uvec2 uv, uint s) { + uint seed = (uv.x*1664525u + uv.y) + s; + uint hash = wangHash(seed); + float value = float(hash) / (4294967296.0); + return value; + } + +float readZ(in vec2 posf) { + return textureLod(depth, posf.xy*0.5+vec2(0.5), 0).r; + } + +vec3 unproject(ivec2 hit, float z) { + const vec2 inPos = vec2(2*hit+ivec2(1,1))/vec2(screenSize)-vec2(1,1); + const vec3 at = vec3(inPos.xy, z); + const vec3 pos = projectiveUnproject(scene.projectInv, at); + return pos; + } + +vec3 reconstructNormal(const ivec2 at) { + const vec3 norm = normalFetch(gbufNormal, at); + const vec3 nx = mat3(scene.view) * norm; + return nx; + } + +float pixelToWorld(float pixelRadius, float z) { + z = linearDepth(z, scene.clipInfo); + float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; + float worldRadius = (clipRadius * z) / scene.project[1][1]; + return worldRadius; + } + +vec4 hitPass(ivec2 fragCoord, float h0, const vec3 pos0, float z0, const vec3 norm) { + if(z0==1.0) + return vec4(0); + + int step = 32; + float rI = pixelToWorld(step, z0); // ideally, sholud be harmonic mean of ray hits + + float wInv = 10; + + float c = cos(h0), s = sin(h0); + ivec2 hit = fragCoord + ivec2(round(vec2(c,s)*step)); + hit = clamp(hit, ivec2(0), screenSize-1); + + const vec3 norm1 = reconstructNormal(hit); + + const float z1 = texelFetch(depth, hit, 0).r; + const vec3 pos1 = unproject(hit, z1); + + const vec3 dp = pos1-pos0; + const float lenDp = length(dp); + if(lenDp>rI*2) + ;//return vec4(0,0,1,1); + + // Making_Radiance_and_Irradiance_Caching_Practical_A.pdf + // part 3, Weighting Function + const float wDist = (lenDp)/max(rI*2.0, 1); + const float wAng = sqrt(1.0 - min(dot(norm,norm1),1)); + wInv = wDist*1 + wAng*1; + + const float wOcclusion = 1;//max(0, dot(dp/lenDp, norm1)); + + //return vec4(wDist-1); + float ret = 1.0/max(wInv,0.01); + return vec4(max(1.0 - ret, 0)); + + //const float selfOcclusionTerm = abs(dot(dp/lenDp, norm)); + //const float wErr = lenDp/rI + dot(norm, dp/lenDp); + //return vec4(1.0/(0.01+wErr)); + } + +void main() { + screenSize = ivec2(textureSize(depth,0)); + fragCoord = ivec2(gl_GlobalInvocationID.xy); + + const bool valid = all(lessThan(fragCoord, screenSize)); + const vec2 inPos = vec2(2*fragCoord+ivec2(1,1))/vec2(screenSize)-vec2(1,1); + + const float z0 = readZ(inPos.xy); + const vec3 pos0 = unproject(fragCoord,z0); + + const vec3 norm = valid ? reconstructNormal(fragCoord) : vec3(0); + const float f0 = M_PI*2.0*wangHashNoise(uvec2(fragCoord), 0); + + vec4 hit = hitPass(fragCoord,f0,pos0,z0,norm); + + if(z0<0.9999) + atomicAdd(count.y, 1); + + imageStore(pdfTree, ivec2(gl_GlobalInvocationID.xy), vec4(hit.x)); + // imageStore(pdfTree, ivec2(gl_GlobalInvocationID.xy), vec4(1)); + + imageStore(dbgImage, ivec2(gl_GlobalInvocationID.xy), hit); + + if(false && z0<0.9999 && gl_LocalInvocationIndex==0) { + // dummy for now + const uint id = atomicAdd(count.x, 1); + if(id>=surfels.length()) + return; + Surfel sx; + sx.pos = worldPos(z0); + sx.norm = texelFetch(gbufNormal, fragCoord, 0).r; + surfels[id] = sx; + } + } diff --git a/shader/lighting/surfels/irr_mip.comp b/shader/lighting/surfels/irr_mip.comp new file mode 100644 index 000000000..594981638 --- /dev/null +++ b/shader/lighting/surfels/irr_mip.comp @@ -0,0 +1,34 @@ +#version 450 + +layout(local_size_x = 8, local_size_y = 8) in; + +layout(binding = 0, r32f) uniform readonly image2D srcMip; +layout(binding = 1, r32f) uniform writeonly image2D dstMip; + +void main() { + ivec2 dstCoord = ivec2(gl_GlobalInvocationID.xy); + ivec2 dstSize = imageSize(dstMip); + ivec2 srcSize = imageSize(srcMip); + + if(dstCoord.x >= dstSize.x || dstCoord.y >= dstSize.y) + return; + + ivec2 coord0 = dstCoord * 2; + ivec2 coord1 = coord0+2; + + // bottom-right corner might have 3x3 footprint in npot image + if(dstCoord.x+1==dstSize.x) + coord1.x = srcSize.x; + if(dstCoord.y+1==dstSize.y) + coord1.y = srcSize.y; + + float ret = 0; + for(int i=coord0.x; i=sz.x || at.y>=sz.y) + return 0; + return texelFetch(pdfTree, at, mip).x; + } + +void sampleTree(ivec2 coord0, ivec2 coord1, int mip, inout float index, inout ivec2 p) { + for(int i=coord0.x; i0;) { + --i; + + ivec2 srcSize = textureSize(pdfTree, i+0); + ivec2 dstSize = textureSize(pdfTree, i+1); + + ivec2 coord0 = p*2; + ivec2 coord1 = coord0+2; + if(p.x+1==dstSize.x) + coord1.x = srcSize.x; + if(p.y+1==dstSize.y) + coord1.y = srcSize.y; + p *= 2; + sampleTree(coord0, coord1, i, index, p); + } + + return p; + } + +void main() { + const uint index = gl_GlobalInvocationID.x; + const int mipCount = textureQueryLevels(pdfTree); + const float maxV = texelFetch(pdfTree, ivec2(0), mipCount-1).x; + const uint maxN = count.y; + if(index>=maxN || index>=maxSurfels) + return; + + const ivec2 at = find(index/float(maxSurfels), maxV); + + if(at.x<0) + return; //error + + const uint id = atomicAdd(count.x, 1); + if(id>=surfels.length()) + return; + + const ivec2 screenSize = ivec2(textureSize(depth,0)); + const float z = texelFetch(depth, at, 0).x; + if(z==1.0) + return; + + Surfel sx; + sx.pos = worldPos(z, at, screenSize); + sx.norm = texelFetch(gbufNormal, at, 0).r; + surfels[id] = sx; + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_dbg.vert b/shader/lighting/surfels/surf_dbg.vert index 2907e2afb..caab78352 100644 --- a/shader/lighting/surfels/surf_dbg.vert +++ b/shader/lighting/surfels/surf_dbg.vert @@ -41,10 +41,11 @@ vec3 hasGridPos(vec3 wpos, float cellSize) { return round(wpos); } -uint surfHash_(vec3 hpos, float cellSize) { - ivec3 p = ivec3(round(hpos*cellSize)); - uint hashKey = pcgHash(p.x + pcgHash(p.y + pcgHash(p.z))); - return hashKey; +float pixelToWorld(float pixelRadius, float z) { + z = linearDepth(z, scene.clipInfo); + float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; + float worldRadius = (clipRadius * z) / scene.project[1][1]; + return worldRadius; } void main() { @@ -60,8 +61,9 @@ void main() { const vec4 pp = scene.viewProject * vec4(p.pos, 1.0); float pixelRadius = 5.0; - float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; - float worldRadius = clipRadius * (-pp.z) / scene.project[1][1]; + // float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; + // float worldRadius = clipRadius * (-pp.z) / scene.project[1][1]; + float worldRadius = pixelToWorld(pixelRadius, pp.z/pp.w); //radius = 5; radius = worldRadius; From 706b75620704d4426a50c9c6069dbea76cf957a3 Mon Sep 17 00:00:00 2001 From: Try Date: Mon, 1 Jun 2026 02:02:34 +0200 Subject: [PATCH 06/52] new surfels clustering method --- game/graphics/renderer.cpp | 56 ++++++++++- game/graphics/renderer.h | 3 + game/graphics/shaders.cpp | 4 + game/graphics/shaders.h | 1 + shader/CMakeLists.txt | 4 + shader/lighting/surfels/surf_adaptive.comp | 53 ++++++++++ shader/lighting/surfels/surf_init.comp | 5 +- shader/lighting/surfels/surf_mip.comp | 64 ++++++++++++ shader/lighting/surfels/surf_scatter.comp | 112 +++++++++++++++++++++ 9 files changed, 298 insertions(+), 4 deletions(-) create mode 100644 shader/lighting/surfels/surf_adaptive.comp create mode 100644 shader/lighting/surfels/surf_mip.comp create mode 100644 shader/lighting/surfels/surf_scatter.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 1524e91ee..051d67995 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1944,7 +1944,9 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor auto& surfels = usesSsboInit(surf.surfels, shaders.surfVote.sizeofBuffer(4, surf.maxSurfels)); auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); auto& hashGrid = usesSsboInit(surf.hashGrid, hashGridSize); - auto& pdfTree = usesImage2d (surf.pdfTree, TextureFormat::R32F, zbuffer.size(), true); + auto& pdfTree = usesImage2d (surf.pdfTree, TextureFormat::R32F, zbuffer.size(), true); + auto& posTree = usesImage2d (surf.posTree, TextureFormat::RGBA32F, zbuffer.size(), true); + auto& normTree = usesImage2d (surf.normTree, TextureFormat::RGBA16, zbuffer.size(), true); if(false && alloc) { struct Push { @@ -1973,7 +1975,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor //alloc = false; } - if(true && alloc) { + if(false && alloc) { struct Push { Vec3 originLwc; uint32_t maxSurfels; @@ -2019,6 +2021,56 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setPipeline(shaders.irrScatter); cmd.dispatchThreads(maxSurfels); } + + if(true && alloc) { + struct Push { + Vec3 originLwc; + uint32_t maxSurfels; + } push = {}; + push.originLwc = scene.originLwc; + push.maxSurfels = maxSurfels; + + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, posTree); + cmd.setBinding(6, normTree); + cmd.setBinding(7, pdfTree); + // + cmd.setBinding(11, dbgImage); + + cmd.setPipeline(shaders.surfInit); + cmd.dispatchThreads(1); //for sake of zeroing counters + + cmd.setPipeline(shaders.surfAdaptive); + cmd.dispatchThreads(sceneDepth.size()); + // + cmd.setPipeline(shaders.surfMip); + for(uint32_t i=1; i(uint32_t(sceneDepth.w()) >> i, 1); + uint32_t h = std::max(uint32_t(sceneDepth.h()) >> i, 1); + cmd.dispatchThreads(w,h); + } + // + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, pdfTree); + cmd.setPipeline(shaders.surfScatter); + cmd.dispatchThreads(maxSurfels); + } } void Renderer::prepareIrradiance(Encoder& cmd, WorldView& wview) { diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index 8eb3c0246..952a13869 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -215,6 +215,9 @@ class Renderer final { Tempest::StorageBuffer hashGrid; Tempest::StorageImage pdfTree; + Tempest::StorageImage posTree; + Tempest::StorageImage normTree; + Tempest::StorageImage dbgImage; } surf; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index b9c03ecab..3af2cad58 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -255,6 +255,10 @@ void Shaders::compileShaders() { irrAlloc = computeShader("irr_alloc.comp.sprv"); irrMip = computeShader("irr_mip.comp.sprv"); irrScatter = computeShader("irr_scatter.comp.sprv"); + + surfAdaptive = computeShader("surf_adaptive.comp.sprv"); + surfMip = computeShader("surf_mip.comp.sprv"); + surfScatter = computeShader("surf_scatter.comp.sprv"); } if(Shaders::isVsmSupported()) { diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index edaa9f643..688566b1d 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -88,6 +88,7 @@ class Shaders { Tempest::RenderPipeline surfDbg; Tempest::ComputePipeline surfInit, surfVote, surfAlloc; Tempest::ComputePipeline irrAlloc, irrMip, irrScatter; + Tempest::ComputePipeline surfAdaptive, surfMip, surfScatter; // Epipolar Tempest::ComputePipeline fogEpipolarVsm; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 33b393895..30e15f165 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -318,6 +318,10 @@ add_shader(irr_alloc.comp lighting/surfels/irr_alloc.comp) add_shader(irr_mip.comp lighting/surfels/irr_mip.comp) add_shader(irr_scatter.comp lighting/surfels/irr_scatter.comp) +add_shader(surf_adaptive.comp lighting/surfels/surf_adaptive.comp) +add_shader(surf_mip.comp lighting/surfels/surf_mip.comp) +add_shader(surf_scatter.comp lighting/surfels/surf_scatter.comp) + # Pathtracing add_shader(pathtrace.frag lighting/pt/pathtrace.frag -DRAY_QUERY -DRAY_QUERY_AT) diff --git a/shader/lighting/surfels/surf_adaptive.comp b/shader/lighting/surfels/surf_adaptive.comp new file mode 100644 index 000000000..9b3371563 --- /dev/null +++ b/shader/lighting/surfels/surf_adaptive.comp @@ -0,0 +1,53 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 16, local_size_y = 16) in; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; + +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5, rgba32f) uniform image2D posTree; +layout(binding = 6, rgba16) uniform image2D normTree; +layout(binding = 7, r32f) uniform image2D pdfTree; +// +layout(binding = 11, rgba8) uniform image2D dbgImage; + + +vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { + const mat4 inv = scene.viewProjectLwcInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return pos.xyz/pos.w + originLwc; + } + +void main() { + const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); + const ivec2 screenSize = ivec2(textureSize(depth,0)); + const bool valid = all(lessThan(fragCoord, screenSize)); + + if(!valid) + return; + + const float z = texelFetch(depth,fragCoord,0).x; + const bool sky = (z >= SKY_DEPTH); + if(!sky) + atomicAdd(count.y, 1); + + const vec3 norm = sky ? vec3(0) : normalFetch(gbufNormal,fragCoord); + const vec3 wpos = sky ? vec3(0) : worldPos(z, fragCoord, screenSize); + + imageStore(posTree, fragCoord, vec4(wpos,sky ? 0 : 1)); + imageStore(normTree, fragCoord, vec4(norm*0.5+0.5,0)); + imageStore(pdfTree, fragCoord, vec4(sky ? 0 : 0.005)); + } diff --git a/shader/lighting/surfels/surf_init.comp b/shader/lighting/surfels/surf_init.comp index 6104c98c8..569057913 100644 --- a/shader/lighting/surfels/surf_init.comp +++ b/shader/lighting/surfels/surf_init.comp @@ -3,14 +3,15 @@ layout(local_size_x = 64) in; layout(binding = 4, std430) buffer SB0 { uvec4 count; }; -layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; +//layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; void main() { if(gl_GlobalInvocationID.xy==ivec2(0)) count = uvec4(0); - +/* const uint hKey = gl_GlobalInvocationID.x; if(hKey >= hashGrid.length()) return; hashGrid[hKey] = 0xFFFFFFFF; + */ } diff --git a/shader/lighting/surfels/surf_mip.comp b/shader/lighting/surfels/surf_mip.comp new file mode 100644 index 000000000..02fd4229a --- /dev/null +++ b/shader/lighting/surfels/surf_mip.comp @@ -0,0 +1,64 @@ +#version 450 + +layout(local_size_x = 8, local_size_y = 8) in; + +layout(binding = 0, rgba32f) uniform readonly image2D srcPos; +layout(binding = 1, rgba16) uniform readonly image2D srcNorm; +layout(binding = 2, r32f) uniform readonly image2D srcPdf; +layout(binding = 3, rgba32f) uniform writeonly image2D dstPos; +layout(binding = 4, rgba16) uniform writeonly image2D dstNorm; +layout(binding = 5, r32f) uniform writeonly image2D dstPdf; + +float samplePass(bool avgPass, ivec2 coord0, ivec2 coord1, inout vec4 avgPos, inout vec3 avgNormal) { + float normErr = 0, posErr = 0, parentErr = 0; + + for(int i=coord0.x; i= dstSize.x || dstCoord.y >= dstSize.y) + return; + + ivec2 coord0 = dstCoord * 2; + ivec2 coord1 = coord0+2; + + // bottom-right corner might have 3x3 footprint in npot image + if(dstCoord.x+1==dstSize.x) + coord1.x = srcSize.x; + if(dstCoord.y+1==dstSize.y) + coord1.y = srcSize.y; + + vec4 pos = vec4(0); + vec3 norm = vec3(0); + samplePass(true, coord0, coord1, pos, norm); + + float cnt = pos.w; + pos.xyz /= max(cnt,1); + norm = normalize(norm); + + const float err = cnt>0 ? samplePass(false, coord0, coord1, pos, norm) : 0; + + imageStore(dstPos, dstCoord, vec4(pos)); + imageStore(dstNorm, dstCoord, vec4(norm*0.5+0.5,0)); + imageStore(dstPdf, dstCoord, vec4(err)); + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_scatter.comp b/shader/lighting/surfels/surf_scatter.comp new file mode 100644 index 000000000..70cfebaa8 --- /dev/null +++ b/shader/lighting/surfels/surf_scatter.comp @@ -0,0 +1,112 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 64) in; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + uint maxSurfels; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; + +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5) uniform sampler2D pdfTree; + +vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { + const mat4 inv = scene.viewProjectLwcInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return pos.xyz/pos.w + originLwc; + } + +uint pdfFetch(in usampler2D pdfTree, ivec2 at, int mip) { + const ivec2 sz = textureSize(pdfTree, mip); + if(at.x>=sz.x || at.y>=sz.y) + return 0; + return texelFetch(pdfTree, at, mip).x; + } + +void sampleTree(ivec2 coord0, ivec2 coord1, int mip, inout float index, inout ivec2 p) { + float vSum = 0; + for(int i=coord0.x; i0) { + p = ivec2(i,r); + index /= v; + return; + } + index = index-v; + } + } + } + +ivec2 find(float index) { + const int mipCount = textureQueryLevels(pdfTree); + + ivec2 p = ivec2(0); + for(int i=mipCount-1; i>0;) { + --i; + + ivec2 srcSize = textureSize(pdfTree, i+0); + ivec2 dstSize = textureSize(pdfTree, i+1); + + ivec2 coord0 = p*2; + ivec2 coord1 = coord0+2; + if(p.x+1==dstSize.x) + coord1.x = srcSize.x; + if(p.y+1==dstSize.y) + coord1.y = srcSize.y; + p *= 2; + sampleTree(coord0, coord1, i, index, p); + } + + return p; + } + +void main() { + const uint index = gl_GlobalInvocationID.x; + const int mipCount = textureQueryLevels(pdfTree); + const uint maxN = count.y; + if(index>=maxN || index>=maxSurfels) + return; + + const ivec2 at = find(index/float(maxSurfels)); + + if(at.x<0) + return; //error + + const uint id = atomicAdd(count.x, 1); + if(id>=surfels.length()) + return; + + const ivec2 screenSize = ivec2(textureSize(depth,0)); + const float z = texelFetch(depth, at, 0).x; + if(z==1.0) + return; + + Surfel sx; + sx.pos = worldPos(z, at, screenSize); + sx.norm = texelFetch(gbufNormal, at, 0).r; + surfels[id] = sx; + } \ No newline at end of file From a8b34fd5e071eb2ce911977b3294be741357c5bb Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 2 Jun 2026 00:57:22 +0200 Subject: [PATCH 07/52] surfel apply pass initial --- game/graphics/renderer.cpp | 73 ++++++++++- game/graphics/renderer.h | 3 + game/graphics/shaders.cpp | 6 + game/graphics/shaders.h | 2 + shader/CMakeLists.txt | 4 + shader/lighting/surfels/surf_adaptive.comp | 1 - shader/lighting/surfels/surf_apply.comp | 130 ++++++++++++++++++++ shader/lighting/surfels/surf_bin_alloc.comp | 20 +++ shader/lighting/surfels/surf_bin_clear.comp | 20 +++ shader/lighting/surfels/surf_binning.comp | 40 ++++++ shader/lighting/surfels/surf_mip.comp | 4 +- shader/lighting/surfels/surf_scatter.comp | 3 +- 12 files changed, 301 insertions(+), 5 deletions(-) create mode 100644 shader/lighting/surfels/surf_apply.comp create mode 100644 shader/lighting/surfels/surf_bin_alloc.comp create mode 100644 shader/lighting/surfels/surf_bin_clear.comp create mode 100644 shader/lighting/surfels/surf_binning.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 051d67995..45589c55b 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -43,6 +43,12 @@ static Size tileCount(Size sz, int s) { return sz; } +static Size tileCount(IVec2 sz, int s) { + sz.x = (sz.x+s-1)/s; + sz.y = (sz.y+s-1)/s; + return Size(sz.x,sz.y); + } + Renderer::Renderer(Tempest::Swapchain& swapchain) : swapchain(swapchain) { auto& device = Resources::device(); @@ -1937,7 +1943,8 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor static bool alloc = true; const uint32_t hashGridSize = 4'194'304; // SHaRC docimentation recommends 2^22 - static uint32_t maxSurfels = 8096; + static uint32_t maxSurfels = 8192; + static int32_t tileSize = 64; cmd.setDebugMarker("Surfels"); auto& scene = wview.sceneGlobals(); @@ -1947,6 +1954,11 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor auto& pdfTree = usesImage2d (surf.pdfTree, TextureFormat::R32F, zbuffer.size(), true); auto& posTree = usesImage2d (surf.posTree, TextureFormat::RGBA32F, zbuffer.size(), true); auto& normTree = usesImage2d (surf.normTree, TextureFormat::RGBA16, zbuffer.size(), true); + auto& surfList = usesSsboInit(surf.surfList, surf.maxSurfels*sizeof(uint32_t)); + + auto tc = tileCount(zbuffer.size().toPoint()+IVec2(tileSize), tileSize); + auto& surfCnts = usesImage2d (surf.surfCnts, TextureFormat::R32U, tc); + auto& surfBins = usesImage2d (surf.surfBins, TextureFormat::R32U, tc); if(false && alloc) { struct Push { @@ -2071,6 +2083,65 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setPipeline(shaders.surfScatter); cmd.dispatchThreads(maxSurfels); } + + static bool binning = true; + if(binning) { + struct Push { + int32_t tileSize; + int32_t allocPass; + } push = {}; + push.tileSize = tileSize; + + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, surfels); + cmd.setBinding(2, surfCnts); + cmd.setBinding(3, surfBins); + cmd.setBinding(4, surfList); + cmd.setBinding(4, surfList); + + cmd.setPipeline(shaders.surfBinClear); + cmd.dispatchThreads(surfBins.size()); + + push.allocPass = 0; + cmd.setPushData(push); + cmd.setPipeline(shaders.surfBinning); + cmd.dispatchThreads(maxSurfels); + + cmd.setPipeline(shaders.surfBinAlloc); + cmd.dispatchThreads(surfBins.size()); + + push.allocPass = 1; + cmd.setPushData(push); + cmd.setPipeline(shaders.surfBinning); + cmd.dispatchThreads(maxSurfels); + //binning = false; + } + + static bool apply = true; + if(apply) { + struct Push { + Vec3 originLwc; + int32_t tileSize; + } push = {}; + push.originLwc = scene.originLwc; + push.tileSize = tileSize; + + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, surfList); + cmd.setBinding(6, surfCnts); + cmd.setBinding(7, surfBins); + // + cmd.setBinding(11, dbgImage); + + cmd.setPipeline(shaders.surfApply); + cmd.dispatchThreads(zbuffer.size()); + } } void Renderer::prepareIrradiance(Encoder& cmd, WorldView& wview) { diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index 952a13869..49db29c0d 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -218,6 +218,9 @@ class Renderer final { Tempest::StorageImage posTree; Tempest::StorageImage normTree; + Tempest::StorageImage surfCnts, surfBins; + Tempest::StorageBuffer surfList; + Tempest::StorageImage dbgImage; } surf; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 3af2cad58..bb594c2be 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -259,6 +259,12 @@ void Shaders::compileShaders() { surfAdaptive = computeShader("surf_adaptive.comp.sprv"); surfMip = computeShader("surf_mip.comp.sprv"); surfScatter = computeShader("surf_scatter.comp.sprv"); + + surfBinning = computeShader("surf_binning.comp.sprv"); + surfBinClear = computeShader("surf_bin_clear.comp.sprv"); + surfBinAlloc = computeShader("surf_bin_alloc.comp.sprv"); + + surfApply = computeShader("surf_apply.comp.sprv"); } if(Shaders::isVsmSupported()) { diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 688566b1d..361868956 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -89,6 +89,8 @@ class Shaders { Tempest::ComputePipeline surfInit, surfVote, surfAlloc; Tempest::ComputePipeline irrAlloc, irrMip, irrScatter; Tempest::ComputePipeline surfAdaptive, surfMip, surfScatter; + Tempest::ComputePipeline surfBinClear, surfBinning, surfBinAlloc; + Tempest::ComputePipeline surfApply; // Epipolar Tempest::ComputePipeline fogEpipolarVsm; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 30e15f165..a4ff1f39a 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -321,6 +321,10 @@ add_shader(irr_scatter.comp lighting/surfels/irr_scatter.comp) add_shader(surf_adaptive.comp lighting/surfels/surf_adaptive.comp) add_shader(surf_mip.comp lighting/surfels/surf_mip.comp) add_shader(surf_scatter.comp lighting/surfels/surf_scatter.comp) +add_shader(surf_binning.comp lighting/surfels/surf_binning.comp) +add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) +add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) +add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) # Pathtracing add_shader(pathtrace.frag lighting/pt/pathtrace.frag -DRAY_QUERY -DRAY_QUERY_AT) diff --git a/shader/lighting/surfels/surf_adaptive.comp b/shader/lighting/surfels/surf_adaptive.comp index 9b3371563..bb6d5c432 100644 --- a/shader/lighting/surfels/surf_adaptive.comp +++ b/shader/lighting/surfels/surf_adaptive.comp @@ -23,7 +23,6 @@ layout(binding = 7, r32f) uniform image2D pdfTree; // layout(binding = 11, rgba8) uniform image2D dbgImage; - vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { const mat4 inv = scene.viewProjectLwcInv; const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp new file mode 100644 index 000000000..a6dd6d7cf --- /dev/null +++ b/shader/lighting/surfels/surf_apply.comp @@ -0,0 +1,130 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 16, local_size_y = 16) in; + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + uint tileSize; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5, std430) buffer SB1 { uint surfelList[]; }; +layout(binding = 6, r32ui) uniform uimage2D surfCnts; +layout(binding = 7, r32ui) uniform uimage2D surfBins; + +layout(binding = 11, rgba8) uniform image2D dbgImage; + +const uint MaxSurfInCache = 64; +shared uint surfCount; +shared vec4 surfelsPos [MaxSurfInCache]; +shared vec4 surfelsNorm[MaxSurfInCache]; +shared vec2 surfelsScr [MaxSurfInCache]; + +vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { + const mat4 inv = scene.viewProjectLwcInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return pos.xyz/pos.w + originLwc; + } + +float pixelToWorld(float pixelRadius, float z) { + z = linearDepth(z, scene.clipInfo); + float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; + float worldRadius = (clipRadius * z) / scene.project[1][1]; + return worldRadius; + } + +void pullTile(ivec2 tileId) { + const uint laneID = gl_LocalInvocationIndex; + + const uint cnt = imageLoad(surfCnts, tileId).x; + const uint ptr = imageLoad(surfBins, tileId).x; + const int pixelRadius = 16; + + for(uint i=laneID; i=MaxSurfInCache) + return; + + uint sId = surfelList[ptr+i]; + + const Surfel s = surfels[sId]; + const vec4 pos4 = scene.viewProject * vec4(s.pos, 1.0); + + const vec3 pos = pos4.xyz/pos4.w; + const ivec2 ipos = ivec2((pos.xy*0.5+0.5) * vec2(scene.screenRes))/ivec2(gl_WorkGroupSize.xy); + + if(gl_WorkGroupID.xy!=ipos) + ;//continue; + + const float wRadius = pixelToWorld(pixelRadius, pos.z); + surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); + surfelsNorm[id] = vec4(decodeNormal(s.norm), wRadius); + surfelsScr [id] = vec2((pos.xy*0.5+0.5) * vec2(scene.screenRes)); + } + } + +void main() { + surfCount = 0; + barrier(); + + const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); + const ivec2 screenSize = ivec2(textureSize(depth,0)); + const bool valid = all(lessThan(fragCoord, screenSize)); + + const float z = valid ? texelFetch(depth,fragCoord,0).x : 0; + const bool sky = (z >= SKY_DEPTH); + + ivec2 t = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy)/int(tileSize); + pullTile(t+ivec2(0,0)); + pullTile(t+ivec2(1,0)); + pullTile(t+ivec2(0,1)); + pullTile(t+ivec2(1,1)); + barrier(); + + if(!valid || sky) + return; + + const vec3 wpos = worldPos(z, fragCoord, screenSize); + const vec3 norm = normalFetch(gbufNormal,fragCoord); + + vec4 clr = vec4(0); + float maxW = 0; + for(int i=0; imaxW) { + maxW = w; + //clr = dbg; + } + clr += vec4(dbg*w, w); + } + + if(clr.a>0) + clr.rgb /= clr.a; + + // imageStore(dbgImage, fragCoord, vec4(surfCount/255.0)); + // imageStore(dbgImage, fragCoord, vec4(maxW)); + imageStore(dbgImage, fragCoord, vec4(clr.rgb,1)); + } diff --git a/shader/lighting/surfels/surf_bin_alloc.comp b/shader/lighting/surfels/surf_bin_alloc.comp new file mode 100644 index 000000000..b1c4391f5 --- /dev/null +++ b/shader/lighting/surfels/surf_bin_alloc.comp @@ -0,0 +1,20 @@ +#version 450 + +layout(local_size_x = 8, local_size_y = 8) in; + +layout(binding = 1, std430) buffer SB0 { uvec4 count; }; +layout(binding = 2, r32ui) uniform uimage2D surfCnts; +layout(binding = 3, r32ui) uniform uimage2D surfBins; + +void main() { + const ivec2 tile = ivec2(gl_GlobalInvocationID.xy); + const ivec2 sz = imageSize(surfBins); + if(tile.x>=sz.x || tile.y>=sz.y) + return; + + const uint v = imageLoad(surfCnts, tile).x; + const uint ptr = atomicAdd(count.z, v); + + imageStore(surfCnts, tile, uvec4(0)); + imageStore(surfBins, tile, uvec4(ptr)); + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_bin_clear.comp b/shader/lighting/surfels/surf_bin_clear.comp new file mode 100644 index 000000000..c73c298b8 --- /dev/null +++ b/shader/lighting/surfels/surf_bin_clear.comp @@ -0,0 +1,20 @@ +#version 450 + +layout(local_size_x = 8, local_size_y = 8) in; + +layout(binding = 1, std430) buffer SB0 { uvec4 count; }; +layout(binding = 2, r32ui) uniform uimage2D surfCnts; +layout(binding = 3, r32ui) uniform uimage2D surfBins; + +void main() { + if(gl_GlobalInvocationID.xy==uvec2(0)) + count.z = 0; + + const ivec2 tile = ivec2(gl_GlobalInvocationID.xy); + const ivec2 sz = imageSize(surfBins); + if(tile.x>=sz.x || tile.y>=sz.y) + return; + + imageStore(surfCnts, tile, uvec4(0)); + imageStore(surfBins, tile, uvec4(0)); + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_binning.comp b/shader/lighting/surfels/surf_binning.comp new file mode 100644 index 000000000..9dbfe6518 --- /dev/null +++ b/shader/lighting/surfels/surf_binning.comp @@ -0,0 +1,40 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 64) in; + +layout(std140, push_constant) uniform Push { + int tileSize; + int allocPass; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 2, r32ui) uniform uimage2D surfCnts; +layout(binding = 3, r32ui) uniform uimage2D surfBins; +layout(binding = 4, std430) buffer SB1 { uint surfelIds[]; }; + +void main() { + const uint surfelId = gl_GlobalInvocationID.x; + if(surfelId>=count.x) + return; + + const Surfel p = surfels[surfelId]; + const vec4 pos4 = scene.viewProject * vec4(p.pos, 1.0); + + const vec3 pos = pos4.xyz/pos4.w; + ivec2 ipos = ivec2((pos.xy*0.5+0.5) * vec2(scene.screenRes))+tileSize/2; + + ivec2 sz = imageSize(surfCnts); + ivec2 tile = clamp(ipos/tileSize, ivec2(0), sz); + + const uint lptr = imageAtomicAdd(surfCnts, tile, 1); + if(allocPass>0) { + const uint ptr = imageLoad(surfBins, tile).x + lptr; + surfelIds[ptr] = surfelId; + } + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_mip.comp b/shader/lighting/surfels/surf_mip.comp index 02fd4229a..699c81754 100644 --- a/shader/lighting/surfels/surf_mip.comp +++ b/shader/lighting/surfels/surf_mip.comp @@ -22,8 +22,8 @@ float samplePass(bool avgPass, ivec2 coord0, ivec2 coord1, inout vec4 avgPos, in vec3 norm = imageLoad(srcNorm, ivec2(i,r)).xyz*2.0 - 1.0; normErr += (1.0 - dot(norm, avgNormal)); - //posErr += abs(dot(pos - avgPos.xyz, avgNormal)); - posErr += abs(dot(normalize(pos - avgPos.xyz), avgNormal)); + posErr += abs(dot(pos - avgPos.xyz, avgNormal)); + // posErr += abs(dot(normalize(pos - avgPos.xyz), avgNormal)); parentErr += imageLoad(srcPdf, ivec2(i,r)).x; } } diff --git a/shader/lighting/surfels/surf_scatter.comp b/shader/lighting/surfels/surf_scatter.comp index 70cfebaa8..9dba2c15c 100644 --- a/shader/lighting/surfels/surf_scatter.comp +++ b/shader/lighting/surfels/surf_scatter.comp @@ -43,7 +43,8 @@ void sampleTree(ivec2 coord0, ivec2 coord1, int mip, inout float index, inout iv } if(vSum<=0) { - p = ivec2(0); + index = 0; + p = coord0; return; } From 55a92ed1f0e274dd0b83500771026b9211e8f516 Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 2 Jun 2026 15:58:06 +0200 Subject: [PATCH 08/52] surf vote: account for normals --- game/graphics/renderer.cpp | 18 ++++++++------ shader/lighting/rt_dbg/hash_dbg.frag | 30 +++++++++++++++++++----- shader/lighting/surfels/surf_apply.comp | 2 +- shader/lighting/surfels/surf_common.glsl | 26 ++++++++++++++++---- shader/lighting/surfels/surf_dbg.vert | 9 +++---- shader/lighting/surfels/surf_init.comp | 5 ++-- shader/lighting/surfels/surf_vote.comp | 25 ++++++++++++++------ 7 files changed, 82 insertions(+), 33 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 45589c55b..598070463 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -685,7 +685,7 @@ void Renderer::draw(Tempest::Attachment& result, Encoder& cmd, ui cmd.setDebugMarker("Translucent"); wview->drawTranslucent(cmd, fId); - // drawHashDbg(sceneLinear, cmd, *wview); + //drawHashDbg(sceneLinear, cmd, *wview); drawProbesDbg(cmd, *wview); drawProbesHitDbg(cmd); drawSurfelsDbg(cmd, *wview); @@ -1022,7 +1022,8 @@ void Renderer::drawHashDbg(Attachment& result, Tempest::Encoder& cmd, Wo } void Renderer::prepareSurfels(Tempest::Encoder& cmd, WorldView& wview) { - static bool alloc = true; + static bool enable = true; + if(!enable) + return; const uint32_t hashGridSize = 4'194'304; // SHaRC docimentation recommends 2^22 static uint32_t maxSurfels = 8192; @@ -1960,7 +1963,8 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor auto& surfCnts = usesImage2d (surf.surfCnts, TextureFormat::R32U, tc); auto& surfBins = usesImage2d (surf.surfBins, TextureFormat::R32U, tc); - if(false && alloc) { + static bool alloc = true; + if(true && alloc) { struct Push { Vec3 originLwc; } push; @@ -2034,7 +2038,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatchThreads(maxSurfels); } - if(true && alloc) { + if(false && alloc) { struct Push { Vec3 originLwc; uint32_t maxSurfels; @@ -2084,7 +2088,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatchThreads(maxSurfels); } - static bool binning = true; + static bool binning = false; if(binning) { struct Push { int32_t tileSize; @@ -2118,7 +2122,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor //binning = false; } - static bool apply = true; + static bool apply = false; if(apply) { struct Push { Vec3 originLwc; diff --git a/shader/lighting/rt_dbg/hash_dbg.frag b/shader/lighting/rt_dbg/hash_dbg.frag index 4a13ba1fb..482f0d4d7 100644 --- a/shader/lighting/rt_dbg/hash_dbg.frag +++ b/shader/lighting/rt_dbg/hash_dbg.frag @@ -13,7 +13,9 @@ layout(std140, push_constant) uniform Push { layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; -layout(binding = 1) uniform texture2D depth; +//layout(binding = 1) uniform texture2D depth; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform texture2D depth; uint computeDepthSlice(float linDepth, float near, float far, uint numSlices) { float z = linDepth; @@ -34,9 +36,19 @@ float surfDist(ivec3 hpos, vec3 pos, float cellSize) { return dot(p,p); //quad distance } -uint surfHash(ivec3 hpos) { +float surfDist(ivec3 hpos, vec3 pos, float cellSize, uint inorm, vec3 norm) { + vec3 p = (pos/cellSize - hpos); + p *= 2/sqrt(2.0); + float ed = length(p); //quad distance + + vec3 n = i_octahedral_8(inorm); + float en = sqrt(max(1.0 - dot(n,norm),0.0)); + return ed+en; + } + +uint surfHash(ivec3 hpos, uint inorm) { ivec3 p = hpos; - uint hashKey = pcgHash(p.x + pcgHash(p.y + pcgHash(p.z))); + uint hashKey = pcgHash(pcgHash(p.x + pcgHash(p.y + pcgHash(p.z))) + inorm); return hashKey; } @@ -45,6 +57,8 @@ void main(void) { if(d>=1.0) discard; + const vec3 norm = normalFetch(gbufNormal, ivec2(gl_FragCoord.xy)); + const float lD = max(linearDepth(d, scene.clipInfo), 10); const mat4 inv = scene.viewProjectLwcInv; const vec4 pos = inv*vec4(inUV * 2.0 - 1.0, d, 1); @@ -56,9 +70,13 @@ void main(void) { // float sz = computeCellSize(lD, fov, textureSize(depth,0), 2, 1); float sz = computeCellSize(lD, fov, textureSize(depth,0), SURFEL_CELL); vec3 wpos = pos.xyz/pos.w + originLwc; - ivec3 ipos = hasGridPos(wpos, sz); - uint h = surfHash(ipos); - float dx = surfDist(ipos, wpos, sz); + + ivec3 ipos = hasGridPos(wpos, sz); + uint inorm = octahedral_8(norm); + + uint h = surfHash(ipos, inorm); + float dx = surfDist(ipos, wpos, sz, inorm, norm); + //uint sx = computeDepthSlice(lD, 10, 100000, 32); // outColor = vec4(debugColors[h%debugColors.length()], 1.0); diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp index a6dd6d7cf..6b34d7bd9 100644 --- a/shader/lighting/surfels/surf_apply.comp +++ b/shader/lighting/surfels/surf_apply.comp @@ -109,7 +109,7 @@ void main() { float eNorm = sqrt(max(2 - 2*dot(norm, surfelsNorm[i].xyz), 0.0001)); float wPix = dot(ds,ds); - wPix = max(1-wPix*wPix,0); + wPix = max(1-wPix,0); float w = wPix/max(eDist+eNorm, 0.0001); diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 4ed6699e3..09931bb34 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -5,13 +5,29 @@ const float SKY_DEPTH = 0.999995; //const float SURFEL_FOOTPRINT = 64; -const float SURFEL_CELL = 32;//SURFEL_FOOTPRINT/sqrt(2); +const float SURFEL_CELL = 64;//SURFEL_FOOTPRINT/sqrt(2); struct Surfel { vec3 pos; uint norm; }; +uint octahedral_8(in vec3 nor) { + nor.xy /= ( abs( nor.x ) + abs( nor.y ) + abs( nor.z ) ); + nor.xy = (nor.z >= 0.0) ? nor.xy : (1.0-abs(nor.yx))*msign(nor.xy); + uvec2 d = uvec2(round(7.5 + nor.xy*7.5)); + return d.x|(d.y<<4u); + } + +vec3 i_octahedral_8( uint data ) { + uvec2 iv = uvec2( data, data>>4u ) & 15u; vec2 v = vec2(iv)/7.5 - 1.0; + vec3 nor = vec3(v, 1.0 - abs(v.x) - abs(v.y)); // Rune Stubbe's version, + float t = max(-nor.z,0.0); // much faster than original + nor.x += (nor.x>0.0)?-t:t; // implementation of this + nor.y += (nor.y>0.0)?-t:t; // technique + return normalize( nor ); + } + float computeTargetCellSize(float d, float aperture, vec2 resolution, float pixelFeatureSize) { // Equation 2: Evaluate the angular factor based on resolution aspect ratio float term1 = aperture / resolution.x; @@ -41,10 +57,10 @@ float computeCellSize(float d, float fov, vec2 resolution, float pixelFeatureSiz return computeAdaptiveCellSize(sw, sMin); } -uint surfHash(vec3 pos, float cellSize) { -#if 0 - ivec3 p = ivec3(round(pos * cellSize)); - uint hashKey = pcgHash(p.x + pcgHash(p.y + pcgHash(p.z))); +uint surfHash(vec3 pos, float cellSize, uint inorm) { +#if 1 + ivec3 p = ivec3(round(pos * cellSize)); + uint hashKey = pcgHash(inorm + pcgHash(p.x + pcgHash(p.y + pcgHash(p.z)))); return hashKey; #else ivec3 p = ivec3(round(pos * cellSize)); diff --git a/shader/lighting/surfels/surf_dbg.vert b/shader/lighting/surfels/surf_dbg.vert index caab78352..e5b87ff90 100644 --- a/shader/lighting/surfels/surf_dbg.vert +++ b/shader/lighting/surfels/surf_dbg.vert @@ -74,8 +74,9 @@ void main() { const float fov = 67.5f*M_PI/180.0; const float ld = max(linearDepth(pp.z/pp.w, scene.clipInfo), 10); - const float sz = computeCellSize(ld, fov, textureSize(depth,0), SURFEL_CELL); - const vec3 wpos = p.pos; - const vec3 ipos = hasGridPos(wpos, sz); - instanceIndex = surfHash(ipos, sz); + const float sz = computeCellSize(ld, fov, textureSize(depth,0), SURFEL_CELL); + const vec3 wpos = p.pos; + const vec3 ipos = hasGridPos(wpos, sz); + const uint inorm = octahedral_8(normal); + instanceIndex = surfHash(ipos, sz, inorm); } diff --git a/shader/lighting/surfels/surf_init.comp b/shader/lighting/surfels/surf_init.comp index 569057913..6104c98c8 100644 --- a/shader/lighting/surfels/surf_init.comp +++ b/shader/lighting/surfels/surf_init.comp @@ -3,15 +3,14 @@ layout(local_size_x = 64) in; layout(binding = 4, std430) buffer SB0 { uvec4 count; }; -//layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; +layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; void main() { if(gl_GlobalInvocationID.xy==ivec2(0)) count = uvec4(0); -/* + const uint hKey = gl_GlobalInvocationID.x; if(hKey >= hashGrid.length()) return; hashGrid[hKey] = 0xFFFFFFFF; - */ } diff --git a/shader/lighting/surfels/surf_vote.comp b/shader/lighting/surfels/surf_vote.comp index 3b15abe60..808f74e38 100644 --- a/shader/lighting/surfels/surf_vote.comp +++ b/shader/lighting/surfels/surf_vote.comp @@ -52,6 +52,16 @@ float surfDist(vec3 hpos, vec3 pos, float cellSize) { return dot(p,p); //quad distance } +float surfDist(vec3 hpos, vec3 pos, float cellSize, uint inorm, vec3 norm) { + vec3 p = (pos/cellSize - hpos); + p *= 2/sqrt(2.0); + float ed = length(p); // distance + + vec3 n = i_octahedral_8(inorm); + float en = sqrt(max(1.0 - dot(n,norm),0.0)); + return ed+en; + } + void main() { const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); const ivec2 screenSize = ivec2(textureSize(depth,0)); @@ -65,16 +75,17 @@ void main() { if(z >= SKY_DEPTH) return; - const vec3 wpos = worldPos(z, fragCoord, screenSize); - const float ld = max(linearDepth(z, scene.clipInfo), 10); + const float ld = max(linearDepth(z, scene.clipInfo), 10); + const float sz = computeCellSize(ld, fov, textureSize(depth,0), SURFEL_CELL); - const float sz = computeCellSize(ld, fov, textureSize(depth,0), SURFEL_CELL); - const vec3 ipos = hasGridPos(wpos, sz); - const float dist = surfDist(ipos, wpos, sz); + const vec3 wpos = worldPos(z, fragCoord, screenSize); + const vec3 ipos = hasGridPos(wpos, sz); + const uint inorm = octahedral_8(norm); - const uint hKey = surfHash(ipos, sz) % hashGrid.length(); + const float dist = surfDist(ipos, wpos, sz, inorm, norm); + const uint hKey = surfHash(ipos, sz, inorm) % hashGrid.length(); - if(dist>0.5) + if(dist>0.9) return; const uint sId = packSurfId(dist, fragCoord, screenSize); From 3795e996909ab44af6140c4394b2eef6c9d5f56b Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 2 Jun 2026 22:03:48 +0200 Subject: [PATCH 09/52] tile based irradiance cache --- game/graphics/renderer.cpp | 27 +++- game/graphics/shaders.cpp | 2 + game/graphics/shaders.h | 1 + shader/CMakeLists.txt | 2 + shader/lighting/surfels/irr_alloc.comp | 6 +- shader/lighting/surfels/surf_init.comp | 5 +- shader/lighting/surfels/surf_tiled.comp | 178 ++++++++++++++++++++++++ 7 files changed, 215 insertions(+), 6 deletions(-) create mode 100644 shader/lighting/surfels/surf_tiled.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 598070463..704ea5cd3 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1964,7 +1964,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor auto& surfBins = usesImage2d (surf.surfBins, TextureFormat::R32U, tc); static bool alloc = true; - if(true && alloc) { + if(false && alloc) { struct Push { Vec3 originLwc; } push; @@ -2088,6 +2088,31 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatchThreads(maxSurfels); } + if(true && alloc) { + struct Push { + Vec3 originLwc; + uint32_t maxSurfels; + } push = {}; + push.originLwc = scene.originLwc; + push.maxSurfels = maxSurfels; + + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + // + cmd.setBinding(11, dbgImage); + + cmd.setPipeline(shaders.surfInit); + cmd.dispatchThreads(1); //for sake of zeroing counters + + const auto tc = tileCount(zbuffer.size(), 128); + cmd.setPipeline(shaders.surfTiled); + cmd.dispatch(tc); + } + static bool binning = false; if(binning) { struct Push { diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index bb594c2be..cf58fc3bb 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -265,6 +265,8 @@ void Shaders::compileShaders() { surfBinAlloc = computeShader("surf_bin_alloc.comp.sprv"); surfApply = computeShader("surf_apply.comp.sprv"); + + surfTiled = computeShader("surf_tiled.comp.sprv"); } if(Shaders::isVsmSupported()) { diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 361868956..80f7392c2 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -91,6 +91,7 @@ class Shaders { Tempest::ComputePipeline surfAdaptive, surfMip, surfScatter; Tempest::ComputePipeline surfBinClear, surfBinning, surfBinAlloc; Tempest::ComputePipeline surfApply; + Tempest::ComputePipeline surfTiled; // Epipolar Tempest::ComputePipeline fogEpipolarVsm; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index a4ff1f39a..7a707e27e 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -326,6 +326,8 @@ add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) +add_shader(surf_tiled.comp lighting/surfels/surf_tiled.comp) + # Pathtracing add_shader(pathtrace.frag lighting/pt/pathtrace.frag -DRAY_QUERY -DRAY_QUERY_AT) diff --git a/shader/lighting/surfels/irr_alloc.comp b/shader/lighting/surfels/irr_alloc.comp index dfa9aeeae..54f470b49 100644 --- a/shader/lighting/surfels/irr_alloc.comp +++ b/shader/lighting/surfels/irr_alloc.comp @@ -90,8 +90,8 @@ vec4 hitPass(ivec2 fragCoord, float h0, const vec3 pos0, float z0, const vec3 no // Making_Radiance_and_Irradiance_Caching_Practical_A.pdf // part 3, Weighting Function const float wDist = (lenDp)/max(rI*2.0, 1); - const float wAng = sqrt(1.0 - min(dot(norm,norm1),1)); - wInv = wDist*1 + wAng*1; + const float wAng = sqrt(max(1.0 - dot(norm,norm1),0)); + wInv = wDist*0 + wAng*1; const float wOcclusion = 1;//max(0, dot(dp/lenDp, norm1)); @@ -122,7 +122,7 @@ void main() { if(z0<0.9999) atomicAdd(count.y, 1); - imageStore(pdfTree, ivec2(gl_GlobalInvocationID.xy), vec4(hit.x)); + imageStore(pdfTree, ivec2(gl_GlobalInvocationID.xy), vec4(hit.x+0.001)); // imageStore(pdfTree, ivec2(gl_GlobalInvocationID.xy), vec4(1)); imageStore(dbgImage, ivec2(gl_GlobalInvocationID.xy), hit); diff --git a/shader/lighting/surfels/surf_init.comp b/shader/lighting/surfels/surf_init.comp index 6104c98c8..569057913 100644 --- a/shader/lighting/surfels/surf_init.comp +++ b/shader/lighting/surfels/surf_init.comp @@ -3,14 +3,15 @@ layout(local_size_x = 64) in; layout(binding = 4, std430) buffer SB0 { uvec4 count; }; -layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; +//layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; void main() { if(gl_GlobalInvocationID.xy==ivec2(0)) count = uvec4(0); - +/* const uint hKey = gl_GlobalInvocationID.x; if(hKey >= hashGrid.length()) return; hashGrid[hKey] = 0xFFFFFFFF; + */ } diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp new file mode 100644 index 000000000..f58b1a72f --- /dev/null +++ b/shader/lighting/surfels/surf_tiled.comp @@ -0,0 +1,178 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 16, local_size_y = 16) in; + +const ivec2 TileSize = ivec2(128); +const int DefaultCoverage = 100; +const float NormalBias = 0.0015; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; + +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; } glob; + +// +layout(binding = 11, rgba8) uniform image2D dbgImage; + +// +struct Surf { + vec4 pos; // pos, size + vec3 norm; + }; +shared Surf pointQueue[64]; +shared int pointQueueSize; + +shared uint fragVote; + +vec3 rayOrigin(ivec2 frag, float depth, vec3 normal) { + const vec2 fragCoord = ((frag.xy+0.5)*scene.screenResInv)*2.0 - vec2(1.0); + const vec4 scr = vec4(fragCoord.x, fragCoord.y, depth, 1.0); + const vec4 wpos = scene.viewProjectLwcInv * scr; + return (wpos.xyz + normal*NormalBias)/wpos.w; + } + +vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { + const mat4 inv = scene.viewProjectLwcInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return (pos.xyz)/pos.w + originLwc; + } + +float pixelToWorld(float pixelRadius, float z) { + z = linearDepth(z, scene.clipInfo); + float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; + float worldRadius = (clipRadius * z) / scene.project[1][1]; + return worldRadius; + } + + +float calculteWeight(const Surf s, const vec3 wpos, const vec3 norm) { + vec3 ldir = wpos - s.pos.xyz; + float dist = length(ldir); + float dotN = dot(norm, s.norm.xyz); + + float eGeom = dist/s.pos.w + sqrt(max(2 - 2*dotN, 0)); + //float eOccl = step(-0.1, dot(normalize(ldir), s.norm.xyz)); // allow small occlusion + float eOccl = dot(normalize(ldir), s.norm.xyz)*0.5+0.5; // allow small occlusion +//return eOccl; + float w = (1.0*eOccl)/max(eGeom, 0.001) - 0.0001; + return w; + } + +void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { + const bool valid = all(lessThan(fragCoord, screenSize)); + if(!valid) + return; + + const float z = texelFetch(depth,fragCoord,0).x; + const bool sky = (z >= SKY_DEPTH); + if(sky) + return; + + const vec3 norm = normalFetch(gbufNormal, fragCoord); + const vec3 wpos = worldPos(z, fragCoord, screenSize); + const float edge = 0.9; + + float wMax = 0; + for(int i=pointQueueSize; i>0;) { + --i; + const Surf s = pointQueue[i]; + const float w = calculteWeight(s,wpos,norm); + wMax = max(wMax,w); + if(wMax >= edge) + break; + } + + imageStore(dbgImage, fragCoord, vec4(wMax/edge)); + + if(wMax >= edge) + return; + uint w = floatBitsToUint(wMax/edge) & 0xFFFF0000; + uint b = uint(w) | uint(gl_LocalInvocationIndex); + atomicMin(fragVote, b); + } + +void surfAlloc(ivec2 fragCoord, const ivec2 screenSize) { + if(gl_LocalInvocationIndex!=0) + return; + + if(pointQueueSize>=pointQueue.length()) { + return; + } + + const uint vote = fragVote; + fragVote = 0xFFFFFFFF; + + if((vote & 0x0000FFFF)==0x0000FFFF) + return; + + const int i = pointQueueSize; + pointQueueSize++; + + const uint id = vote & 0xFFFF; + fragCoord.x += int(id % gl_WorkGroupSize.x); + fragCoord.y += int(id / gl_WorkGroupSize.x); + + const float z = texelFetch(depth, fragCoord, 0).x; + const vec3 wpos = worldPos(z, fragCoord, screenSize); + const vec3 norm = normalFetch(gbufNormal, fragCoord); + const float sz = max(pixelToWorld(DefaultCoverage, z), 1); + + Surf s; + s.pos = vec4(wpos, sz); + s.norm = norm; + pointQueue[i] = s; + } + +void storeSurfels() { + const uint laneID = gl_LocalInvocationIndex; + + if(laneID==0) + fragVote = atomicAdd(glob.count.x, pointQueueSize); + barrier(); + + if(laneID Date: Tue, 2 Jun 2026 23:03:08 +0200 Subject: [PATCH 10/52] tile-based surfels in progress --- shader/lighting/surfels/surf_tiled.comp | 56 +++++++++++++++---------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index f58b1a72f..dd4794677 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -7,8 +7,9 @@ layout(local_size_x = 16, local_size_y = 16) in; const ivec2 TileSize = ivec2(128); -const int DefaultCoverage = 100; +const float DefaultCoverage = 128 * 1.414 * 1.2; const float NormalBias = 0.0015; +const uint Salt = 0x9D; layout(std140, push_constant) uniform Push { vec3 originLwc; @@ -27,8 +28,9 @@ layout(binding = 11, rgba8) uniform image2D dbgImage; // struct Surf { - vec4 pos; // pos, size - vec3 norm; + vec4 pos; // pos, size + vec3 norm; + ivec2 fragCoord; //TODO: remove }; shared Surf pointQueue[64]; shared int pointQueueSize; @@ -56,18 +58,25 @@ float pixelToWorld(float pixelRadius, float z) { return worldRadius; } - -float calculteWeight(const Surf s, const vec3 wpos, const vec3 norm) { +float calculteWeight(const Surf s, const vec3 wpos, const vec3 norm, ivec2 fragCoord) { + // Irradiance Caching Algorithm. Greg Ward; Dolby Canada + // https://cgg.mff.cuni.cz/~jaroslav/papers/2008-irradiance_caching_class/03-greg-ic.pdf vec3 ldir = wpos - s.pos.xyz; float dist = length(ldir); float dotN = dot(norm, s.norm.xyz); - float eGeom = dist/s.pos.w + sqrt(max(2 - 2*dotN, 0)); - //float eOccl = step(-0.1, dot(normalize(ldir), s.norm.xyz)); // allow small occlusion - float eOccl = dot(normalize(ldir), s.norm.xyz)*0.5+0.5; // allow small occlusion -//return eOccl; - float w = (1.0*eOccl)/max(eGeom, 0.001) - 0.0001; - return w; + //float fd = 1.0; //max(0, 1.0 - dist/s.pos.w); fd = fd*fd; // smooth factor, to limit surfel radius + + float eGeom = dist/s.pos.w + sqrt(max(1 - 1*dotN, 0)); + // float eOccl = dot(normalize(ldir), s.norm.xyz)*0.5+0.5; // allow small occlusion + float eOccl = dot((ldir/dist), 0.5*(s.norm.xyz+norm))*0.5+0.5; // allow small occlusion + + //vec2 ds = vec2(fragCoord - s.fragCoord)/(TileSize.x*1.0); + //float wPix = 1.0; //max(1.0 - dot(ds,ds), 0); + + // return eOccl; + // return (1.0*eOccl)/max(eGeom, 0.001) - 0.001; + return (1.0*eOccl)/max(eGeom, 0.001) - 1.0; } void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { @@ -82,24 +91,26 @@ void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { const vec3 norm = normalFetch(gbufNormal, fragCoord); const vec3 wpos = worldPos(z, fragCoord, screenSize); - const float edge = 0.9; + const float edge = 0.2; - float wMax = 0; + float wMax = 0; // wangHashNoise(fragCoord,0)*0.01; for(int i=pointQueueSize; i>0;) { --i; const Surf s = pointQueue[i]; - const float w = calculteWeight(s,wpos,norm); + const float w = calculteWeight(s,wpos,norm,fragCoord); + // w = max(w,0); wMax = max(wMax,w); - if(wMax >= edge) + if(wMax > edge) break; } - imageStore(dbgImage, fragCoord, vec4(wMax/edge)); + imageStore(dbgImage, fragCoord, vec4(wMax-edge)); - if(wMax >= edge) + if(wMax > edge) return; + uint w = floatBitsToUint(wMax/edge) & 0xFFFF0000; - uint b = uint(w) | uint(gl_LocalInvocationIndex); + uint b = uint(w) | uint(gl_LocalInvocationIndex) ^ Salt; atomicMin(fragVote, b); } @@ -120,18 +131,19 @@ void surfAlloc(ivec2 fragCoord, const ivec2 screenSize) { const int i = pointQueueSize; pointQueueSize++; - const uint id = vote & 0xFFFF; + const uint id = (vote & 0xFFFF) ^ Salt; fragCoord.x += int(id % gl_WorkGroupSize.x); fragCoord.y += int(id / gl_WorkGroupSize.x); const float z = texelFetch(depth, fragCoord, 0).x; const vec3 wpos = worldPos(z, fragCoord, screenSize); const vec3 norm = normalFetch(gbufNormal, fragCoord); - const float sz = max(pixelToWorld(DefaultCoverage, z), 1); + const float sz = max(pixelToWorld(DefaultCoverage, z), 25); Surf s; - s.pos = vec4(wpos, sz); - s.norm = norm; + s.pos = vec4(wpos, sz); + s.norm = norm; + s.fragCoord = fragCoord; pointQueue[i] = s; } From b01bf0cda33c759ffccca67fec7a21c58551b3ac Mon Sep 17 00:00:00 2001 From: Try Date: Fri, 5 Jun 2026 02:11:44 +0200 Subject: [PATCH 11/52] bvh of surfels --- game/graphics/renderer.cpp | 23 ++- game/graphics/renderer.h | 2 + game/graphics/shaders.cpp | 1 + game/graphics/shaders.h | 2 +- shader/CMakeLists.txt | 1 + shader/lighting/surfels/surf_bvh.comp | 195 +++++++++++++++++++++++ shader/lighting/surfels/surf_common.glsl | 7 +- shader/lighting/surfels/surf_tiled.comp | 7 +- 8 files changed, 230 insertions(+), 8 deletions(-) create mode 100644 shader/lighting/surfels/surf_bvh.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 704ea5cd3..aac280b6e 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -580,7 +580,8 @@ void Renderer::dbgDraw(Tempest::Painter& p) { //tex.push_back(&textureCast(shadowMap[1])); //tex.push_back(&textureCast(shadowMap[0])); //tex.push_back(&textureCast(vsm.pageData)); - tex.push_back(&textureCast(swrt.outputImage)); + //tex.push_back(&textureCast(swrt.outputImage)); + tex.push_back(&textureCast(surf.dbgImage)); static int size = 400; int left = 10; @@ -1946,19 +1947,22 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor return; const uint32_t hashGridSize = 4'194'304; // SHaRC docimentation recommends 2^22 - static uint32_t maxSurfels = 8192; - static int32_t tileSize = 64; + const uint32_t maxSurfels = surf.maxSurfels; + static int32_t tileSize = 128; cmd.setDebugMarker("Surfels"); auto& scene = wview.sceneGlobals(); auto& surfels = usesSsboInit(surf.surfels, shaders.surfVote.sizeofBuffer(4, surf.maxSurfels)); auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); + auto& hashGrid = usesSsboInit(surf.hashGrid, hashGridSize); auto& pdfTree = usesImage2d (surf.pdfTree, TextureFormat::R32F, zbuffer.size(), true); auto& posTree = usesImage2d (surf.posTree, TextureFormat::RGBA32F, zbuffer.size(), true); auto& normTree = usesImage2d (surf.normTree, TextureFormat::RGBA16, zbuffer.size(), true); auto& surfList = usesSsboInit(surf.surfList, surf.maxSurfels*sizeof(uint32_t)); + auto& surfBvh = usesSsbo (surf.surfBvh, shaders.surfBvh.sizeofBuffer(5, 2*surf.maxSurfels)); + auto tc = tileCount(zbuffer.size().toPoint()+IVec2(tileSize), tileSize); auto& surfCnts = usesImage2d (surf.surfCnts, TextureFormat::R32U, tc); auto& surfBins = usesImage2d (surf.surfBins, TextureFormat::R32U, tc); @@ -2113,6 +2117,19 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatch(tc); } + static bool bvh = true; + if(bvh) { + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, surfBvh); + + cmd.setPipeline(shaders.surfBvh); + cmd.dispatch(1); + } + static bool binning = false; if(binning) { struct Push { diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index 49db29c0d..ba1980469 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -221,6 +221,8 @@ class Renderer final { Tempest::StorageImage surfCnts, surfBins; Tempest::StorageBuffer surfList; + Tempest::StorageBuffer surfBvh; + Tempest::StorageImage dbgImage; } surf; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index cf58fc3bb..1867549da 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -267,6 +267,7 @@ void Shaders::compileShaders() { surfApply = computeShader("surf_apply.comp.sprv"); surfTiled = computeShader("surf_tiled.comp.sprv"); + surfBvh = computeShader("surf_bvh.comp.sprv"); } if(Shaders::isVsmSupported()) { diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 80f7392c2..6a3008ab8 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -91,7 +91,7 @@ class Shaders { Tempest::ComputePipeline surfAdaptive, surfMip, surfScatter; Tempest::ComputePipeline surfBinClear, surfBinning, surfBinAlloc; Tempest::ComputePipeline surfApply; - Tempest::ComputePipeline surfTiled; + Tempest::ComputePipeline surfTiled, surfBvh; // Epipolar Tempest::ComputePipeline fogEpipolarVsm; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 7a707e27e..c29e48e1f 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -327,6 +327,7 @@ add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) add_shader(surf_tiled.comp lighting/surfels/surf_tiled.comp) +add_shader(surf_bvh.comp lighting/surfels/surf_bvh.comp) # Pathtracing add_shader(pathtrace.frag lighting/pt/pathtrace.frag -DRAY_QUERY -DRAY_QUERY_AT) diff --git a/shader/lighting/surfels/surf_bvh.comp b/shader/lighting/surfels/surf_bvh.comp new file mode 100644 index 000000000..cb2765d2b --- /dev/null +++ b/shader/lighting/surfels/surf_bvh.comp @@ -0,0 +1,195 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 256) in; + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + +const uint BVH_NullNode = 0x00000000; +const uint BVH_BoxNode = 0x10000000; +const uint BVH_DataNode = 0x20000000; + +struct BVHNode { + ivec4 bboxA; + ivec4 bboxB; + uint ptrA; + uint ptrB; + uint skipA; + uint skipB; + }; + +struct Task { + ivec4 bbox; + uint begin; + uint end; + uint bvhPtr; + }; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + uint maxSurfels; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; + +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5, std430) buffer SB1 { BVHNode bvh[]; }; + +shared uint splitLeft; +shared uint iteratorL, iteratorR; +shared ivec4 bboxA; +shared ivec4 bboxB; + +shared Task stack[32]; +shared uint stackPtr; + +shared uint bvhSize; + +uint toBitHint(uint num) { + return num>1 ? BVH_BoxNode : BVH_DataNode; + } + +void pushTask(ivec4 bbox, uint bvhPtr, uint begin, uint end) { + Task t; + t.bbox = bbox; + t.begin = begin; + t.end = end; + t.bvhPtr = bvhPtr; + + stack[stackPtr] = t; + ++stackPtr; + } + +uint findSplit(uint bvhPtr, uint begin, uint end, ivec2 bboxMin, ivec2 bboxMax) { + const uint laneID = gl_LocalInvocationIndex; + + splitLeft = begin; + iteratorL = begin; + iteratorR = end-1; + bboxA = ivec4(bboxMax, 0, 0); + bboxB = ivec4(bboxMax, 0, 0); + barrier(); + + int splitX = (bboxMin.x + bboxMax.x)/2; + int splitY = (bboxMin.y + bboxMax.y)/2; + + if(bboxMax.x-bboxMin.x < bboxMax.y-bboxMin.y) + splitX = 0x7FFFFFFF; else + splitY = 0x7FFFFFFF; + + for(uint i=begin+laneID; i=splitLeft) + break; + Surfel si = surfels[i]; + bool left = (si.fragCoord.x 1) { + findSplit(ptr, t.begin, t.end, t.bbox.xy, t.bbox.zw); + } else { + //TODO: real leaf node + if(laneID==0) { + BVHNode node; + node.bboxA = ivec4(0); + node.bboxB = ivec4(0); + node.ptrA = t.begin; + node.ptrB = t.end; + node.skipA = 0; + node.skipB = 0; + bvh[ptr] = node; + } + } + + return true; + } + +void main() { + stackPtr = 0; + bvhSize = 1; + barrier(); + + findSplit(0, 0, count.x, ivec2(0), textureSize(depth, 0)); + barrier(); + + while(true) { + const bool done = nextTask(); + barrier(); + + if(!done) + break; + } + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 09931bb34..23c0930b8 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -8,8 +8,11 @@ const float SKY_DEPTH = 0.999995; const float SURFEL_CELL = 64;//SURFEL_FOOTPRINT/sqrt(2); struct Surfel { - vec3 pos; - uint norm; + vec3 pos; + uint norm; + ivec2 fragCoord; + float radius; + int radiusPix; }; uint octahedral_8(in vec3 nor) { diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index dd4794677..97448fee6 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -159,8 +159,11 @@ void storeSurfels() { const Surf tmp = pointQueue[laneID]; Surfel sx; - sx.pos = tmp.pos.xyz; - sx.norm = encodeNormal(tmp.norm); + sx.pos = tmp.pos.xyz; + sx.norm = encodeNormal(tmp.norm); + sx.fragCoord = tmp.fragCoord; + sx.radius = tmp.pos.w; + sx.radiusPix = 128; //TODO glob.surfels[ptr] = sx; } } From c5721c95ac7853a01a9101f9c8433892d141d9e1 Mon Sep 17 00:00:00 2001 From: Try Date: Fri, 5 Jun 2026 22:24:47 +0200 Subject: [PATCH 12/52] bvh in progress --- game/graphics/renderer.cpp | 15 +++++ game/graphics/shaders.cpp | 5 +- game/graphics/shaders.h | 2 +- shader/CMakeLists.txt | 1 + shader/lighting/surfels/surf_bvh.comp | 61 +++++++++-------- shader/lighting/surfels/surf_bvh_sample.comp | 69 ++++++++++++++++++++ 6 files changed, 119 insertions(+), 34 deletions(-) create mode 100644 shader/lighting/surfels/surf_bvh_sample.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index aac280b6e..f17468aab 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -2130,6 +2130,21 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatch(1); } + static bool traverse = true; + if(traverse) { + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, surfBvh); + // + cmd.setBinding(11, dbgImage); + + cmd.setPipeline(shaders.surfBvhSample); + cmd.dispatchThreads(zbuffer.size()); + } + static bool binning = false; if(binning) { struct Push { diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 1867549da..222655a52 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -266,8 +266,9 @@ void Shaders::compileShaders() { surfApply = computeShader("surf_apply.comp.sprv"); - surfTiled = computeShader("surf_tiled.comp.sprv"); - surfBvh = computeShader("surf_bvh.comp.sprv"); + surfTiled = computeShader("surf_tiled.comp.sprv"); + surfBvh = computeShader("surf_bvh.comp.sprv"); + surfBvhSample = computeShader("surf_bvh_sample.comp.sprv"); } if(Shaders::isVsmSupported()) { diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 6a3008ab8..f6ededed3 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -91,7 +91,7 @@ class Shaders { Tempest::ComputePipeline surfAdaptive, surfMip, surfScatter; Tempest::ComputePipeline surfBinClear, surfBinning, surfBinAlloc; Tempest::ComputePipeline surfApply; - Tempest::ComputePipeline surfTiled, surfBvh; + Tempest::ComputePipeline surfTiled, surfBvh, surfBvhSample; // Epipolar Tempest::ComputePipeline fogEpipolarVsm; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index c29e48e1f..100b41d7e 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -328,6 +328,7 @@ add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) add_shader(surf_tiled.comp lighting/surfels/surf_tiled.comp) add_shader(surf_bvh.comp lighting/surfels/surf_bvh.comp) +add_shader(surf_bvh_sample.comp lighting/surfels/surf_bvh_sample.comp) # Pathtracing add_shader(pathtrace.frag lighting/pt/pathtrace.frag -DRAY_QUERY -DRAY_QUERY_AT) diff --git a/shader/lighting/surfels/surf_bvh.comp b/shader/lighting/surfels/surf_bvh.comp index cb2765d2b..24d29916c 100644 --- a/shader/lighting/surfels/surf_bvh.comp +++ b/shader/lighting/surfels/surf_bvh.comp @@ -13,12 +13,10 @@ const uint BVH_BoxNode = 0x10000000; const uint BVH_DataNode = 0x20000000; struct BVHNode { - ivec4 bboxA; - ivec4 bboxB; - uint ptrA; - uint ptrB; - uint skipA; - uint skipB; + ivec4 bbox; + uint ptrNext; + uint ptrMiss; + ivec2 padd0; }; struct Task { @@ -26,6 +24,7 @@ struct Task { uint begin; uint end; uint bvhPtr; + uint ptrMiss; }; layout(std140, push_constant) uniform Push { @@ -56,18 +55,19 @@ uint toBitHint(uint num) { return num>1 ? BVH_BoxNode : BVH_DataNode; } -void pushTask(ivec4 bbox, uint bvhPtr, uint begin, uint end) { +void pushTask(ivec4 bbox, uint bvhPtr, uint ptrMiss, uint begin, uint end) { Task t; - t.bbox = bbox; - t.begin = begin; - t.end = end; - t.bvhPtr = bvhPtr; + t.bbox = bbox; + t.begin = begin; + t.end = end; + t.bvhPtr = bvhPtr; + t.ptrMiss = ptrMiss; stack[stackPtr] = t; ++stackPtr; } -uint findSplit(uint bvhPtr, uint begin, uint end, ivec2 bboxMin, ivec2 bboxMax) { +uint findSplit(uint bvhPtr, uint ptrMiss, uint begin, uint end, ivec2 bboxMin, ivec2 bboxMax) { const uint laneID = gl_LocalInvocationIndex; splitLeft = begin; @@ -127,17 +127,18 @@ uint findSplit(uint bvhPtr, uint begin, uint end, ivec2 bboxMin, ivec2 bboxMax) if(laneID==0) { const uint alloc = atomicAdd(bvhSize, 2); + const uint ptrA = (alloc+0) | toBitHint(splitLeft-begin); + const uint ptrB = (alloc+1) | toBitHint(end-splitLeft); + BVHNode node; - node.bboxA = bboxA; - node.bboxB = bboxB; - node.ptrA = (alloc+0) | toBitHint(splitLeft-begin); - node.ptrB = (alloc+1) | toBitHint(end-splitLeft); - node.skipA = node.ptrB; - node.skipB = 0; + node.bbox = ivec4(bboxMin, bboxMax); + node.ptrNext = ptrA; + node.ptrMiss = ptrMiss; + node.padd0 = ivec2(0); bvh[bvhPtr] = node; - pushTask(bboxA, node.ptrA, begin, splitLeft); - pushTask(bboxB, node.ptrB, splitLeft, end); + pushTask(bboxA, ptrA, ptrB, begin, splitLeft); + pushTask(bboxB, ptrB, ptrMiss, splitLeft, end); } memoryBarrierBuffer(); @@ -147,7 +148,7 @@ uint findSplit(uint bvhPtr, uint begin, uint end, ivec2 bboxMin, ivec2 bboxMax) bool nextTask() { const uint laneID = gl_LocalInvocationIndex; if(stackPtr==0) - return false; + return true; Task t = stack[stackPtr-1]; barrier(); @@ -159,22 +160,20 @@ bool nextTask() { const uint ptr = t.bvhPtr & 0x0FFFFFFF; if(stackPtr+2 < stack.length() && t.end - t.begin > 1) { - findSplit(ptr, t.begin, t.end, t.bbox.xy, t.bbox.zw); + findSplit(ptr, t.ptrMiss, t.begin, t.end, t.bbox.xy, t.bbox.zw); } else { //TODO: real leaf node if(laneID==0) { BVHNode node; - node.bboxA = ivec4(0); - node.bboxB = ivec4(0); - node.ptrA = t.begin; - node.ptrB = t.end; - node.skipA = 0; - node.skipB = 0; + node.bbox = ivec4(0); + node.ptrNext = t.ptrMiss; + node.ptrMiss = t.ptrMiss; + node.padd0 = ivec2(t.begin, t.end); bvh[ptr] = node; } } - return true; + return false; } void main() { @@ -182,14 +181,14 @@ void main() { bvhSize = 1; barrier(); - findSplit(0, 0, count.x, ivec2(0), textureSize(depth, 0)); + findSplit(0, 0xFFFFFFFF, 0, count.x, ivec2(0), textureSize(depth, 0)); barrier(); while(true) { const bool done = nextTask(); barrier(); - if(!done) + if(done) break; } } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_bvh_sample.comp b/shader/lighting/surfels/surf_bvh_sample.comp new file mode 100644 index 000000000..df0f24463 --- /dev/null +++ b/shader/lighting/surfels/surf_bvh_sample.comp @@ -0,0 +1,69 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 8, local_size_y = 8) in; + +const uint BVH_NullNode = 0x00000000; +const uint BVH_BoxNode = 0x10000000; +const uint BVH_DataNode = 0x20000000; + +struct BVHNode { + ivec4 bbox; + uint ptrNext; + uint ptrMiss; + ivec2 padd0; + }; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + uint maxSurfels; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; + +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; +layout(binding = 4, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5, std430) readonly buffer SB1 { BVHNode bvh[]; }; +// +layout(binding = 11, rgba8) uniform image2D dbgImage; + +bool intersect(ivec2 fragCoord, ivec4 bbox) { + return bbox.x <= fragCoord.x && fragCoord.x Date: Sun, 7 Jun 2026 01:53:30 +0200 Subject: [PATCH 13/52] surfels binning and weight function --- game/graphics/renderer.cpp | 8 +-- shader/lighting/surfels/surf_apply.comp | 56 ++++++++------------ shader/lighting/surfels/surf_binning.comp | 7 +-- shader/lighting/surfels/surf_bvh_sample.comp | 50 +++++++++++++++-- shader/lighting/surfels/surf_common.glsl | 30 +++++++++++ shader/lighting/surfels/surf_dbg.frag | 2 +- shader/lighting/surfels/surf_dbg.vert | 2 +- shader/lighting/surfels/surf_tiled.comp | 38 ++++--------- 8 files changed, 115 insertions(+), 78 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index f17468aab..13e19961a 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -2117,7 +2117,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatch(tc); } - static bool bvh = true; + static bool bvh = false; if(bvh) { cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); @@ -2130,7 +2130,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatch(1); } - static bool traverse = true; + static bool traverse = false; if(traverse) { cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); @@ -2145,7 +2145,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatchThreads(zbuffer.size()); } - static bool binning = false; + static bool binning = true; if(binning) { struct Push { int32_t tileSize; @@ -2179,7 +2179,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor //binning = false; } - static bool apply = false; + static bool apply = true; if(apply) { struct Push { Vec3 originLwc; diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp index 6b34d7bd9..0510a2607 100644 --- a/shader/lighting/surfels/surf_apply.comp +++ b/shader/lighting/surfels/surf_apply.comp @@ -29,7 +29,6 @@ const uint MaxSurfInCache = 64; shared uint surfCount; shared vec4 surfelsPos [MaxSurfInCache]; shared vec4 surfelsNorm[MaxSurfInCache]; -shared vec2 surfelsScr [MaxSurfInCache]; vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { const mat4 inv = scene.viewProjectLwcInv; @@ -38,40 +37,31 @@ vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { return pos.xyz/pos.w + originLwc; } -float pixelToWorld(float pixelRadius, float z) { - z = linearDepth(z, scene.clipInfo); - float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; - float worldRadius = (clipRadius * z) / scene.project[1][1]; - return worldRadius; - } - void pullTile(ivec2 tileId) { const uint laneID = gl_LocalInvocationIndex; const uint cnt = imageLoad(surfCnts, tileId).x; const uint ptr = imageLoad(surfBins, tileId).x; - const int pixelRadius = 16; - for(uint i=laneID; i=MaxSurfInCache) - return; + ivec2 bboxMin = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy); + ivec2 bboxMax = bboxMin + ivec2(gl_WorkGroupSize.xy); + for(uint i=laneID; i=MaxSurfInCache) + return; surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); - surfelsNorm[id] = vec4(decodeNormal(s.norm), wRadius); - surfelsScr [id] = vec2((pos.xy*0.5+0.5) * vec2(scene.screenRes)); + surfelsNorm[id] = vec4(decodeNormal(s.norm), s.radius); } } @@ -93,6 +83,10 @@ void main() { pullTile(t+ivec2(1,1)); barrier(); + if(surfCount>MaxSurfInCache) + surfCount = MaxSurfInCache; + barrier(); + if(!valid || sky) return; @@ -102,22 +96,14 @@ void main() { vec4 clr = vec4(0); float maxW = 0; for(int i=0; imaxW) { maxW = w; //clr = dbg; } + if(w <= 0) + continue; clr += vec4(dbg*w, w); } @@ -126,5 +112,5 @@ void main() { // imageStore(dbgImage, fragCoord, vec4(surfCount/255.0)); // imageStore(dbgImage, fragCoord, vec4(maxW)); - imageStore(dbgImage, fragCoord, vec4(clr.rgb,1)); + imageStore(dbgImage, fragCoord, vec4(clr.rgb, surfCount/100.0)); } diff --git a/shader/lighting/surfels/surf_binning.comp b/shader/lighting/surfels/surf_binning.comp index 9dbfe6518..6dbf04a88 100644 --- a/shader/lighting/surfels/surf_binning.comp +++ b/shader/lighting/surfels/surf_binning.comp @@ -24,13 +24,10 @@ void main() { return; const Surfel p = surfels[surfelId]; - const vec4 pos4 = scene.viewProject * vec4(p.pos, 1.0); - - const vec3 pos = pos4.xyz/pos4.w; - ivec2 ipos = ivec2((pos.xy*0.5+0.5) * vec2(scene.screenRes))+tileSize/2; + const ivec2 ipos = p.fragCoord; ivec2 sz = imageSize(surfCnts); - ivec2 tile = clamp(ipos/tileSize, ivec2(0), sz); + ivec2 tile = clamp((ipos+tileSize/2)/tileSize, ivec2(0), sz); const uint lptr = imageAtomicAdd(surfCnts, tile, 1); if(allocPass>0) { diff --git a/shader/lighting/surfels/surf_bvh_sample.comp b/shader/lighting/surfels/surf_bvh_sample.comp index df0f24463..4d0cf0c67 100644 --- a/shader/lighting/surfels/surf_bvh_sample.comp +++ b/shader/lighting/surfels/surf_bvh_sample.comp @@ -33,12 +33,32 @@ layout(binding = 5, std430) readonly buffer SB1 { BVHNode bvh[]; }; // layout(binding = 11, rgba8) uniform image2D dbgImage; +vec4 color = vec4(0); + +vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { + const mat4 inv = scene.viewProjectLwcInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return (pos.xyz)/pos.w + originLwc; + } + +float calculteWeight(const Surfel s, const vec3 wpos, const vec3 norm) { + return calculteWeight(s.pos.xyz, decodeNormal(s.norm), s.radius, wpos, norm); + } + +void shade(const Surfel s, const vec3 wpos, const vec3 norm, const vec3 clr) { + float w = calculteWeight(s, wpos, norm); + if(w<=0) + return; + color += vec4(clr*w, w); + } + bool intersect(ivec2 fragCoord, ivec4 bbox) { return bbox.x <= fragCoord.x && fragCoord.x= SKY_DEPTH); + if(sky) + return; + + const vec3 norm = normalFetch(gbufNormal, fragCoord); + const vec3 wpos = worldPos(z, fragCoord, screenSize); + + const uint v = traverse(fragCoord, wpos, norm); + + if(color.w>0) + color.rgb /= color.w; - const uint v = traverse(fragCoord); - imageStore(dbgImage, fragCoord, vec4(v/255.0)); + //imageStore(dbgImage, fragCoord, vec4(v/255.0)); + imageStore(dbgImage, fragCoord, vec4(color.rgb, v/255.0)); } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 23c0930b8..5f3afc34f 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -91,4 +91,34 @@ uint surfHash(vec3 pos, float cellSize, uint inorm) { #endif } +float calculteWeight(const vec3 spos, const vec3 snorm, float radius, const vec3 wpos, const vec3 wnorm) { + // An Approximate Global Illumination System for Computer Generated Films + // https://www.tabellion.org/et/paper/siggraph_2004_gi_for_films.pdf + // https://cgg.mff.cuni.cz/~jaroslav/papers/2008-irradiance_caching_class/03-greg-ic.pdf + vec3 ldir = wpos - spos; + float dist = length(ldir); + float dotN = dot(wnorm, snorm); + + dist = max(dist, 0.0001); + + float ePos = dist/radius; + float eNorm = sqrt(max(1 - 1*dotN, 0)) / sqrt(1.0 - cos(M_PI/3.0)); // Eq. 4 + float w = 1.0 - max(ePos, eNorm); // Eq. 2 + + float eOccl = dot((ldir/dist), 0.5*(snorm+wnorm))*0.5+0.5; // allow small occlusion + return w*eOccl; + } + +vec3 surfDebugColor(Surfel s, uint sId) { + ivec3 p = ivec3(s.pos/10); + uint h = pcgHash(p.x + pcgHash(p.y + pcgHash(p.z))); + return debugColors[h%debugColors.length()]; + } + +vec3 surfDebugColor(vec3 pos, uint sId) { + ivec3 p = ivec3(pos/10); + uint h = pcgHash(p.x + pcgHash(p.y + pcgHash(p.z))); + return debugColors[h%debugColors.length()]; + } + #endif \ No newline at end of file diff --git a/shader/lighting/surfels/surf_dbg.frag b/shader/lighting/surfels/surf_dbg.frag index 354c01cb4..39fd9c4e3 100644 --- a/shader/lighting/surfels/surf_dbg.frag +++ b/shader/lighting/surfels/surf_dbg.frag @@ -43,7 +43,7 @@ void main(void) { if(length(delta) > radius) ;//discard; - vec3 clr = debugColors[instanceIndex % debugColors.length()] * (1.0-qDist); + vec3 clr = surfDebugColor(p, instanceIndex) * (1.0-qDist); outColor = vec4(clr,1.0); // outColor = vec4(1,0,0,1.0); } diff --git a/shader/lighting/surfels/surf_dbg.vert b/shader/lighting/surfels/surf_dbg.vert index e5b87ff90..d0842a004 100644 --- a/shader/lighting/surfels/surf_dbg.vert +++ b/shader/lighting/surfels/surf_dbg.vert @@ -78,5 +78,5 @@ void main() { const vec3 wpos = p.pos; const vec3 ipos = hasGridPos(wpos, sz); const uint inorm = octahedral_8(normal); - instanceIndex = surfHash(ipos, sz, inorm); + instanceIndex = surfelId; //surfHash(ipos, sz, inorm); } diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index 97448fee6..d67503bec 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -7,7 +7,7 @@ layout(local_size_x = 16, local_size_y = 16) in; const ivec2 TileSize = ivec2(128); -const float DefaultCoverage = 128 * 1.414 * 1.2; +const int DefaultCoverage = 128; const float NormalBias = 0.0015; const uint Salt = 0x9D; @@ -53,30 +53,13 @@ vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { float pixelToWorld(float pixelRadius, float z) { z = linearDepth(z, scene.clipInfo); - float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; + float clipRadius = (2.0 * pixelRadius) * min(scene.screenResInv.x, scene.screenResInv.y); float worldRadius = (clipRadius * z) / scene.project[1][1]; return worldRadius; } -float calculteWeight(const Surf s, const vec3 wpos, const vec3 norm, ivec2 fragCoord) { - // Irradiance Caching Algorithm. Greg Ward; Dolby Canada - // https://cgg.mff.cuni.cz/~jaroslav/papers/2008-irradiance_caching_class/03-greg-ic.pdf - vec3 ldir = wpos - s.pos.xyz; - float dist = length(ldir); - float dotN = dot(norm, s.norm.xyz); - - //float fd = 1.0; //max(0, 1.0 - dist/s.pos.w); fd = fd*fd; // smooth factor, to limit surfel radius - - float eGeom = dist/s.pos.w + sqrt(max(1 - 1*dotN, 0)); - // float eOccl = dot(normalize(ldir), s.norm.xyz)*0.5+0.5; // allow small occlusion - float eOccl = dot((ldir/dist), 0.5*(s.norm.xyz+norm))*0.5+0.5; // allow small occlusion - - //vec2 ds = vec2(fragCoord - s.fragCoord)/(TileSize.x*1.0); - //float wPix = 1.0; //max(1.0 - dot(ds,ds), 0); - - // return eOccl; - // return (1.0*eOccl)/max(eGeom, 0.001) - 0.001; - return (1.0*eOccl)/max(eGeom, 0.001) - 1.0; +float calculteWeight(const Surf s, const vec3 wpos, const vec3 norm) { + return calculteWeight(s.pos.xyz, s.norm, s.pos.w, wpos, norm); } void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { @@ -91,13 +74,13 @@ void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { const vec3 norm = normalFetch(gbufNormal, fragCoord); const vec3 wpos = worldPos(z, fragCoord, screenSize); - const float edge = 0.2; + const float edge = 0.1; - float wMax = 0; // wangHashNoise(fragCoord,0)*0.01; + float wMax = 0; for(int i=pointQueueSize; i>0;) { --i; const Surf s = pointQueue[i]; - const float w = calculteWeight(s,wpos,norm,fragCoord); + const float w = calculteWeight(s,wpos,norm); // w = max(w,0); wMax = max(wMax,w); if(wMax > edge) @@ -138,7 +121,7 @@ void surfAlloc(ivec2 fragCoord, const ivec2 screenSize) { const float z = texelFetch(depth, fragCoord, 0).x; const vec3 wpos = worldPos(z, fragCoord, screenSize); const vec3 norm = normalFetch(gbufNormal, fragCoord); - const float sz = max(pixelToWorld(DefaultCoverage, z), 25); + const float sz = max(pixelToWorld(DefaultCoverage, z), 0); Surf s; s.pos = vec4(wpos, sz); @@ -163,14 +146,15 @@ void storeSurfels() { sx.norm = encodeNormal(tmp.norm); sx.fragCoord = tmp.fragCoord; sx.radius = tmp.pos.w; - sx.radiusPix = 128; //TODO + sx.radiusPix = DefaultCoverage; //TODO glob.surfels[ptr] = sx; } } void main() { - if(!(gl_WorkGroupID.x<2 && gl_WorkGroupID.y<2)) + if(gl_WorkGroupID.xy!=uvec2(5,6)) ;//return; + pointQueueSize = 0; fragVote = 0xFFFFFFFF; barrier(); From 6c04c9212430bd13bcfc3dd321a9b7c5ad40ac2d Mon Sep 17 00:00:00 2001 From: Try Date: Sun, 7 Jun 2026 14:40:06 +0200 Subject: [PATCH 14/52] surfels in progress --- shader/lighting/surfels/surf_tiled.comp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index d67503bec..87492273b 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -53,9 +53,13 @@ vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { float pixelToWorld(float pixelRadius, float z) { z = linearDepth(z, scene.clipInfo); - float clipRadius = (2.0 * pixelRadius) * min(scene.screenResInv.x, scene.screenResInv.y); - float worldRadius = (clipRadius * z) / scene.project[1][1]; - return worldRadius; + + float clipRadiusX = (2.0 * pixelRadius) * scene.screenResInv.x; + float clipRadiusY = (2.0 * pixelRadius) * scene.screenResInv.y; + + float worldRadiusX = (clipRadiusX * z) / scene.project[0][0]; + float worldRadiusY = (clipRadiusY * z) / scene.project[1][1]; + return min(worldRadiusX, worldRadiusY); } float calculteWeight(const Surf s, const vec3 wpos, const vec3 norm) { @@ -74,7 +78,7 @@ void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { const vec3 norm = normalFetch(gbufNormal, fragCoord); const vec3 wpos = worldPos(z, fragCoord, screenSize); - const float edge = 0.1; + const float edge = 0.01; float wMax = 0; for(int i=pointQueueSize; i>0;) { From 6c779d8b883fe70f3f9c9d2572d6d94f001f87b5 Mon Sep 17 00:00:00 2001 From: Try Date: Sun, 7 Jun 2026 22:50:02 +0200 Subject: [PATCH 15/52] surfel pathtrace initial --- game/graphics/renderer.cpp | 42 +++- game/graphics/renderer.h | 2 + game/graphics/shaders.cpp | 3 + game/graphics/shaders.h | 3 +- shader/CMakeLists.txt | 2 + shader/lighting/ambient_light.frag | 35 ++- shader/lighting/surfels/surf_apply.comp | 23 +- shader/lighting/surfels/surf_common.glsl | 2 + shader/lighting/surfels/surf_pathtrace.comp | 261 ++++++++++++++++++++ shader/lighting/surfels/surf_tiled.comp | 13 +- 10 files changed, 347 insertions(+), 39 deletions(-) create mode 100644 shader/lighting/surfels/surf_pathtrace.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 13e19961a..cc0952652 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -331,7 +331,7 @@ bool Renderer::requiresTlas() const { if(!Gothic::options().doRayQuery) return false; - if(settings.giEnabled || settings.pathTraceEnabled) + if(settings.giEnabled || settings.giSurfelsEnabled || settings.pathTraceEnabled) return true; if(!(settings.rtsmEnabled || settings.vsmEnabled)) return true; @@ -581,7 +581,8 @@ void Renderer::dbgDraw(Tempest::Painter& p) { //tex.push_back(&textureCast(shadowMap[0])); //tex.push_back(&textureCast(vsm.pageData)); //tex.push_back(&textureCast(swrt.outputImage)); - tex.push_back(&textureCast(surf.dbgImage)); + //tex.push_back(&textureCast(surf.dbgImage)); + tex.push_back(&textureCast(surf.irrImage)); static int size = 400; int left = 10; @@ -1946,14 +1947,18 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor if(!enable) return; + if(!settings.giSurfelsEnabled) + return; + const uint32_t hashGridSize = 4'194'304; // SHaRC docimentation recommends 2^22 const uint32_t maxSurfels = surf.maxSurfels; - static int32_t tileSize = 128; + static int32_t tileSize = 256; cmd.setDebugMarker("Surfels"); auto& scene = wview.sceneGlobals(); auto& surfels = usesSsboInit(surf.surfels, shaders.surfVote.sizeofBuffer(4, surf.maxSurfels)); auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); + auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::R11G11B10UF, zbuffer.size()); auto& hashGrid = usesSsboInit(surf.hashGrid, hashGridSize); auto& pdfTree = usesImage2d (surf.pdfTree, TextureFormat::R32F, zbuffer.size(), true); @@ -2179,6 +2184,23 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor //binning = false; } + static bool rays = true; + if(rays) { + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, surfels); + cmd.setBinding(2, sky.viewCldLut); + // + cmd.setBinding(6, scene.rtScene.tlas); + cmd.setBinding(7, Sampler::trillinear()); + cmd.setBinding(8, scene.rtScene.tex); + cmd.setBinding(9, scene.rtScene.vbo); + cmd.setBinding(10,scene.rtScene.ibo); + cmd.setBinding(11,scene.rtScene.rtDesc); + + cmd.setPipeline(shaders.surfPathtrace); + cmd.dispatchThreads(maxSurfels); + } + static bool apply = true; if(apply) { struct Push { @@ -2197,8 +2219,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setBinding(5, surfList); cmd.setBinding(6, surfCnts); cmd.setBinding(7, surfBins); - // - cmd.setBinding(11, dbgImage); + cmd.setBinding(8, irrImage); cmd.setPipeline(shaders.surfApply); cmd.dispatchThreads(zbuffer.size()); @@ -2559,10 +2580,17 @@ void Renderer::drawAmbient(Encoder& cmd, const WorldView& view) { cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); cmd.setBinding(2, gbufNormal, Sampler::nearest()); cmd.setBinding(3, sky.irradianceLut); - if(settings.zCloudShadowScale) { + if(settings.giSurfelsEnabled) { + auto& ao = (settings.zCloudShadowScale ? textureCast(ssao.ssaoBlur) : Resources::fallbackBlack()); + cmd.setBinding(4, ao, Sampler::nearest(ClampMode::ClampToEdge)); + cmd.setBinding(5, surf.irrImage, Sampler::nearest(ClampMode::ClampToEdge)); + cmd.setPipeline(shaders.ambientLightSurf); + } + else if(settings.zCloudShadowScale) { cmd.setBinding(4, ssao.ssaoBlur, Sampler::nearest(ClampMode::ClampToEdge)); cmd.setPipeline(shaders.ambientLightSsao); - } else { + } + else { cmd.setPipeline(shaders.ambientLight); } cmd.draw(nullptr, 0, 3); diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index ba1980469..885538a30 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -121,6 +121,7 @@ class Renderer final { bool zFogRadial = false; bool giEnabled = false; + bool giSurfelsEnabled = true; //TESTING bool aaEnabled = false; float zVidBrightness = 0.5; @@ -218,6 +219,7 @@ class Renderer final { Tempest::StorageImage posTree; Tempest::StorageImage normTree; + Tempest::StorageImage irrImage; Tempest::StorageImage surfCnts, surfBins; Tempest::StorageBuffer surfList; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 222655a52..cd68965ea 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -75,6 +75,7 @@ void Shaders::compileShaders() { ambientLight = ambientLightShader("ambient_light"); ambientLightSsao = ambientLightShader("ambient_light_ssao"); + ambientLightSurf = ambientLightShader("ambient_light_surf"); irradiance = computeShader("irradiance.comp.sprv"); cloudsLut = computeShader("clouds_lut.comp.sprv"); @@ -264,6 +265,8 @@ void Shaders::compileShaders() { surfBinClear = computeShader("surf_bin_clear.comp.sprv"); surfBinAlloc = computeShader("surf_bin_alloc.comp.sprv"); + surfPathtrace = computeShader("surf_pathtrace.comp.sprv"); + surfApply = computeShader("surf_apply.comp.sprv"); surfTiled = computeShader("surf_tiled.comp.sprv"); diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index f6ededed3..fc421c38a 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -30,7 +30,7 @@ class Shaders { Tempest::RenderPipeline lights, lightsRq, lightsVsm; Tempest::RenderPipeline directLight, directLightSh, directLightRq; - Tempest::RenderPipeline ambientLight, ambientLightSsao; + Tempest::RenderPipeline ambientLight, ambientLightSsao, ambientLightSurf; Tempest::ComputePipeline copyBuf; Tempest::ComputePipeline copyImg; @@ -92,6 +92,7 @@ class Shaders { Tempest::ComputePipeline surfBinClear, surfBinning, surfBinAlloc; Tempest::ComputePipeline surfApply; Tempest::ComputePipeline surfTiled, surfBvh, surfBvhSample; + Tempest::ComputePipeline surfPathtrace; // Epipolar Tempest::ComputePipeline fogEpipolarVsm; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 100b41d7e..f4751aa6b 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -217,6 +217,7 @@ add_shader(direct_light_vsm.frag virtual_shadow/vsm_direct_light.frag) add_shader(ambient_light.frag lighting/ambient_light.frag) add_shader(ambient_light_ssao.frag lighting/ambient_light.frag -DSSAO) +add_shader(ambient_light_surf.frag lighting/ambient_light.frag -DSSAO -DSURFEL_GI) add_shader(light.vert lighting/light.vert) add_shader(light.frag lighting/light.frag) @@ -329,6 +330,7 @@ add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) add_shader(surf_tiled.comp lighting/surfels/surf_tiled.comp) add_shader(surf_bvh.comp lighting/surfels/surf_bvh.comp) add_shader(surf_bvh_sample.comp lighting/surfels/surf_bvh_sample.comp) +add_shader(surf_pathtrace.comp lighting/surfels/surf_pathtrace.comp) # Pathtracing add_shader(pathtrace.frag lighting/pt/pathtrace.frag -DRAY_QUERY -DRAY_QUERY_AT) diff --git a/shader/lighting/ambient_light.frag b/shader/lighting/ambient_light.frag index f9630e477..cabcc98b1 100644 --- a/shader/lighting/ambient_light.frag +++ b/shader/lighting/ambient_light.frag @@ -17,6 +17,9 @@ layout(binding = 3) uniform texture2D irradiance; #if defined(SSAO) layout(binding = 4) uniform sampler2D ssao; #endif +#if defined(SURFEL_GI) +layout(binding = 5) uniform sampler2D surfGi; +#endif layout(location = 0) out vec4 outColor; @@ -29,9 +32,6 @@ float textureSsao() { return 1; } #endif vec3 skyIrradiance(vec3 n) { -#if 0 - return scene.ambient * Fd_LambertInv; -#else ivec3 d; d.x = n.x>=0 ? 1 : 0; d.y = n.y>=0 ? 1 : 0; @@ -45,13 +45,28 @@ vec3 skyIrradiance(vec3 n) { ret += texelFetch(irradiance, ivec2(2,d.z), 0).rgb * n.z; return ret; -#endif } float grayscale(vec3 color) { return dot(color, vec3(0.2125, 0.7154, 0.0721)); } +vec3 luminance(vec3 norm) { +#if defined(SURFEL_GI) + vec3 ambient = textureLod(surfGi, uv, 0).rgb; + return ambient; +#else + vec3 ambient = scene.ambient; + vec3 sky = skyIrradiance(norm); + + vec3 ret = vec3(0); + ret += ambient; + ret += sky*0.8; + ret += (norm.y*0.25+0.75) * NightAmbient * Fd_Lambert; + return ret; +#endif + } + void main() { const ivec2 fragCoord = ivec2(gl_FragCoord.xy); @@ -62,18 +77,12 @@ void main() { const vec3 linear = textureAlbedo(diff); const float ao = textureSsao(); - vec3 ambient = scene.ambient; - vec3 sky = skyIrradiance(norm); - - vec3 luminance = vec3(0); - luminance += ambient; - luminance += sky*0.8; - luminance += (norm.y*0.25+0.75) * NightAmbient * Fd_Lambert; - vec3 color = linear; - color *= luminance; + color *= luminance(norm); color *= ao; +#if !defined(SURFEL_GI) // preexposed already color *= scene.exposure; +#endif outColor = vec4(color, 1); // outColor = vec4(vec3(ao), 0); diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp index 0510a2607..248e3d53b 100644 --- a/shader/lighting/surfels/surf_apply.comp +++ b/shader/lighting/surfels/surf_apply.comp @@ -22,10 +22,9 @@ layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; layout(binding = 5, std430) buffer SB1 { uint surfelList[]; }; layout(binding = 6, r32ui) uniform uimage2D surfCnts; layout(binding = 7, r32ui) uniform uimage2D surfBins; +layout(binding = 8, r11f_g11f_b10f) uniform image2D irradiance; -layout(binding = 11, rgba8) uniform image2D dbgImage; - -const uint MaxSurfInCache = 64; +const uint MaxSurfInCache = 128; shared uint surfCount; shared vec4 surfelsPos [MaxSurfInCache]; shared vec4 surfelsNorm[MaxSurfInCache]; @@ -83,8 +82,8 @@ void main() { pullTile(t+ivec2(1,1)); barrier(); - if(surfCount>MaxSurfInCache) - surfCount = MaxSurfInCache; + if(gl_LocalInvocationIndex==0) + surfCount = min(surfCount, MaxSurfInCache); barrier(); if(!valid || sky) @@ -96,21 +95,21 @@ void main() { vec4 clr = vec4(0); float maxW = 0; for(int i=0; imaxW) { + float w = calculteWeight(surfelsPos[i].xyz, surfelsNorm[i].xyz, surfelsNorm[i].w, wpos, norm); + uint surfelId = floatBitsToUint(surfelsPos[i].w); + vec3 color = surfels[surfelId].irradiance; + if(w>maxW) maxW = w; - //clr = dbg; - } if(w <= 0) continue; - clr += vec4(dbg*w, w); + clr += vec4(color*w, w); } if(clr.a>0) clr.rgb /= clr.a; + clr.rgb *= scene.exposure; // imageStore(dbgImage, fragCoord, vec4(surfCount/255.0)); // imageStore(dbgImage, fragCoord, vec4(maxW)); - imageStore(dbgImage, fragCoord, vec4(clr.rgb, surfCount/100.0)); + imageStore(irradiance, fragCoord, vec4(clr.rgb, surfCount/100.0)); } diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 5f3afc34f..92983a6d6 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -13,6 +13,8 @@ struct Surfel { ivec2 fragCoord; float radius; int radiusPix; + vec3 irradiance; + uint padd0; }; uint octahedral_8(in vec3 nor) { diff --git a/shader/lighting/surfels/surf_pathtrace.comp b/shader/lighting/surfels/surf_pathtrace.comp new file mode 100644 index 000000000..b32234207 --- /dev/null +++ b/shader/lighting/surfels/surf_pathtrace.comp @@ -0,0 +1,261 @@ +#version 460 + +#define LIGHTING 1 +#define RAY_QUERY +#define RAY_QUERY_AT + +#include "lighting/rt/rt_common.glsl" +#include "lighting/surfels/surf_common.glsl" +#include "lighting/tonemapping.glsl" + +#include "scene.glsl" +#include "common.glsl" + +const float TMax = 1e30f; + +struct HitResolve { + vec4 diff; + vec3 norm; + float rayT; + bool water; + }; + +layout(local_size_x = 64) in; + +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 2) uniform sampler2D skyLUT; + +uint srand(uvec2 fragCoord, uint seed) { + return uint(uint(fragCoord.x) * uint(1973) + uint(fragCoord.y) * uint(9277) + uint(seed) * uint(26699)) | uint(1); + } + +float randf(inout uint state) { + return float(wangHash(state)) / 4294967296.0; + } + +mat3 toTangent(vec3 norm) { + mat3 tangent; + // Compute a tangent frame and rotate the half vector to world space + vec3 up = abs(norm.z) < 0.999f ? vec3(0.0f, 0.0f, 1.0f) : vec3(1.0f, 0.0f, 0.0f); + tangent[0] = normalize(cross(up, norm)); + tangent[1] = cross(norm, tangent[0]); + tangent[2] = norm; + return tangent; + } + +float computeTextureLOD(float dist, vec3 dir, vec3 norm) { + dist /= 500.0; + float mip = 0; + mip += log2(dist); + mip -= log2(abs(dot(dir, norm))); + return mip; + } + +vec3 randCosWeightedHemisphereDirection(const mat3 tbn, inout uint rngState) { + vec2 rv2 = vec2(randf(rngState), randf(rngState)); + + float ra = sqrt(rv2.y); + float rx = ra*cos(6.2831*rv2.x); + float ry = ra*sin(6.2831*rv2.x); + float rz = sqrt( 1.0-rv2.y ); + vec3 rr = vec3( rx*tbn[0] + ry*tbn[1] + rz*tbn[2] ); + + return normalize(rr); + } + +vec3 randCosWeightedHemisphereDirection(const vec3 n, inout uint rngState) { + vec2 rv2 = vec2(randf(rngState), randf(rngState)); + + vec3 uu = normalize( cross( n, vec3(0.0,1.0,1.0) ) ); + vec3 vv = normalize( cross( uu, n ) ); + + float ra = sqrt(rv2.y); + float rx = ra*cos(6.2831*rv2.x); + float ry = ra*sin(6.2831*rv2.x); + float rz = sqrt( 1.0-rv2.y ); + vec3 rr = vec3( rx*uu + ry*vv + rz*n ); + + return normalize(rr); + } + +float rayQueryProceedShadow(const vec3 rayOrigin, const vec3 rayDirection, inout uint rngState) { + // CullBack due to vegetation + uint flags = gl_RayFlagsSkipAABBEXT | gl_RayFlagsCullBackFacingTrianglesEXT; + float tMin = 1; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, topLevelAS, flags, CM_ShadowCaster, + rayOrigin, tMin, rayDirection, 500*100); + rayQueryProceedAlphaTest(rayQuery); + // rayQueryProceedAlphaTest(rayQuery, rngState); + if(rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) + return 1; + return 0; + } + +HitResolve rayQueryProceedPrimary(const vec3 rayOrigin, const vec3 rayDirection, float mipOverride, inout uint rngState) { + // CullBack due to vegetation + uint flags = gl_RayFlagsSkipAABBEXT | gl_RayFlagsCullBackFacingTrianglesEXT; + float tMin = 2; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, topLevelAS, flags, 0xFF, + rayOrigin, tMin, rayDirection, 500*100); + rayQueryProceedAlphaTest(rayQuery); + // rayQueryProceedAlphaTest(rayQuery, rngState); + if(rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) { + HitResolve ret; + ret.rayT = TMax; + return ret; + } + + const HitDesc hit = pullCommitedHitDesc(rayQuery); + + const float rayT = rayQueryGetIntersectionTEXT(rayQuery, true); + const bool face = !(rayQueryGetIntersectionFrontFaceEXT(rayQuery, true)); //NOTE: not working on vegetation + + const uint id = hit.instanceId; + const uvec3 index = pullTrinagleIds(id,hit.primitiveId); + + const vec2 uv0 = pullTexcoord(id,index.x); + const vec2 uv1 = pullTexcoord(id,index.y); + const vec2 uv2 = pullTexcoord(id,index.z); + + const vec3 nr0 = pullNormal(id,index.x); + const vec3 nr1 = pullNormal(id,index.y); + const vec3 nr2 = pullNormal(id,index.z); + + const vec3 b = hit.baryCoord; + const vec2 uv = (b.x*uv0 + b.y*uv1 + b.z*uv2); + vec3 norm = (b.x*nr0 + b.y*nr1 + b.z*nr2); + + const mat3x3 matrix = mat3x3(rayQueryGetIntersectionObjectToWorldEXT(rayQuery, true)); + norm = normalize(matrix*norm); + + const float mip = mipOverride>=0 ? mipOverride : computeTextureLOD(rayT,rayDirection,norm); + const vec4 diff = textureLod(sampler2D(textures[nonuniformEXT(id)], smp),uv,mip); + + HitResolve ret; + ret.diff = diff; + ret.norm = norm; + ret.rayT = face ? -rayT : rayT; + ret.water = hit.water; + return ret; + } + +float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shadowed, float softAngle, inout uint rngState) { +#if defined(SOFT_SHADOW) + vec3 shRay = randomizeRay(rayDirection, 0.5*M_PI/180.0, rngState); +#else + vec3 shRay = rayDirection; +#endif + + float lamb = max(dot(norm, rayDirection), 0); + if(!shadowed || lamb==0) + return lamb; + + float shadow = rayQueryProceedShadow(rayOrigin, shRay, rngState); + // float shadow = shadowFactor(rayOrigin); + return (lamb * shadow); + } + +vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout uint rngState) { + const int numBounces = 5; + + vec3 thruput = vec3(1); + vec3 color = vec3(0); + bool underWater = (scene.underWater!=0); + float depth = 0; + + for(int bounce=0;; ++bounce) { + if(dot(thruput*scene.GSunIntensity*scene.exposure, vec3(0.2126, 0.7152, 0.0722)) < 0.01) + break; + + if(bounce>=numBounces) { + // return 0.5*vec4(1,0,1,depth)*scene.GSunIntensity; + // rescale to 100% thruput + vec3 scale = 1.0-thruput; + if(scale.r>0.01 && scale.g>0.01 && scale.b>0.01) + return vec4(color/scale, depth); + return vec4(color, depth); + } + + HitResolve hit = rayQueryProceedPrimary(rayOrigin, rayDirection, (bounce==0 ? 0 : -1), rngState); + if(bounce==0) + depth = abs(hit.rayT); + + if(hit.rayT<0) { + hit.rayT = abs(hit.rayT); // backfaces are fine for PT + hit.norm = -hit.norm; + } + + if(hit.rayT==TMax) { + vec3 sky = textureSkyLUT(skyLUT, vec3(0,RPlanet+max(rayOrigin.y*0.01,0),0), rayDirection, scene.sunDir) * scene.GSunIntensity; + color += thruput*sky; + color += thruput*(vec3(0.3, 0.26, 1)*0.15); //HACK for the night sky + break; + } + + if(underWater) { + const float depth = hit.rayT / 5000.0; // 50 meters + const vec3 transmittance = exp(-depth * vec3(4,2,1) * 1.25); + thruput *= transmittance; + } + + if(hit.water) { + const float ior = (underWater ? IorAir : IorWater); + const vec3 refl = reflect(rayDirection, hit.norm); + const float f = fresnel(refl,hit.norm,ior); + const bool path = (f>randf(rngState)); + + rayOrigin = (rayOrigin + rayDirection * hit.rayT); + rayDirection = path ? refl : refract(rayDirection, hit.norm, ior); + underWater = path ? underWater : !underWater; + thruput *= WaterAlbedo; + continue; + } + + rayOrigin = (rayOrigin + rayDirection * hit.rayT); + rayDirection = randCosWeightedHemisphereDirection(hit.norm, rngState); + thruput *= textureAlbedo(hit.diff.rgb); + //thruput *= vec3(0.85); //snow + //thruput *= vec3(0.04); // asphalt + //if(bounce>0) + // thruput *= groundAlbedo; + //if(bounce>0) + // thruput *= textureAlbedo(hit.diff.rgb); + + vec3 direct = vec3(0); + direct += sampleDirectLight(hit.norm, rayOrigin, scene.sunDir, true, 0.54*M_PI/180.0, rngState) * scene.sunColor; + color += thruput*direct*Fd_Lambert; + } + + return vec4(color, depth); + } + +void main() { + const uint numPaths = 16; + const uint surfelId = gl_GlobalInvocationID.x; + if(surfelId>=count.x) + return; + + uint rngState = 0; //srand(uvec2(0,0), scene.tickCount32); + + const Surfel p = surfels[surfelId]; + const mat3 tbn = toTangent(decodeNormal(p.norm)); + + vec3 irradiance = vec3(0); + float hHit = 0; // harmonic mean + for(int i=0; i0;) { @@ -146,11 +146,12 @@ void storeSurfels() { const Surf tmp = pointQueue[laneID]; Surfel sx; - sx.pos = tmp.pos.xyz; - sx.norm = encodeNormal(tmp.norm); - sx.fragCoord = tmp.fragCoord; - sx.radius = tmp.pos.w; - sx.radiusPix = DefaultCoverage; //TODO + sx.pos = tmp.pos.xyz; + sx.norm = encodeNormal(tmp.norm); + sx.fragCoord = tmp.fragCoord; + sx.radius = tmp.pos.w; + sx.radiusPix = DefaultCoverage; //TODO + sx.irradiance = surfDebugColor(tmp.pos.xyz, ptr); glob.surfels[ptr] = sx; } } From ccbe2456ac0d20aaff8c4dad7d109de98021d6a9 Mon Sep 17 00:00:00 2001 From: Try Date: Sun, 7 Jun 2026 23:28:34 +0200 Subject: [PATCH 16/52] cleanup --- game/graphics/renderer.h | 5 - game/graphics/shaders.cpp | 14 +- game/graphics/shaders.h | 6 +- shader/CMakeLists.txt | 12 +- shader/lighting/surfels/irr_alloc.comp | 140 -------------------- shader/lighting/surfels/irr_mip.comp | 34 ----- shader/lighting/surfels/irr_scatter.comp | 101 -------------- shader/lighting/surfels/surf_adaptive.comp | 52 -------- shader/lighting/surfels/surf_alloc.comp | 60 --------- shader/lighting/surfels/surf_bin_alloc.comp | 2 +- shader/lighting/surfels/surf_init.comp | 2 +- shader/lighting/surfels/surf_mip.comp | 64 --------- shader/lighting/surfels/surf_scatter.comp | 113 ---------------- shader/lighting/surfels/surf_vote.comp | 96 -------------- 14 files changed, 8 insertions(+), 693 deletions(-) delete mode 100644 shader/lighting/surfels/irr_alloc.comp delete mode 100644 shader/lighting/surfels/irr_mip.comp delete mode 100644 shader/lighting/surfels/irr_scatter.comp delete mode 100644 shader/lighting/surfels/surf_adaptive.comp delete mode 100644 shader/lighting/surfels/surf_alloc.comp delete mode 100644 shader/lighting/surfels/surf_mip.comp delete mode 100644 shader/lighting/surfels/surf_scatter.comp delete mode 100644 shader/lighting/surfels/surf_vote.comp diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index 885538a30..ea3679788 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -213,11 +213,6 @@ class Renderer final { struct { const uint32_t maxSurfels = 16*1024; Tempest::StorageBuffer surfels; - Tempest::StorageBuffer hashGrid; - Tempest::StorageImage pdfTree; - - Tempest::StorageImage posTree; - Tempest::StorageImage normTree; Tempest::StorageImage irrImage; Tempest::StorageImage surfCnts, surfBins; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index cd68965ea..0072c4c6c 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -249,17 +249,8 @@ void Shaders::compileShaders() { auto fs = device.shader(sh.data,sh.len); surfDbg = device.pipeline(Triangles,state,vs,fs); - surfInit = computeShader("surf_init.comp.sprv"); - surfVote = computeShader("surf_vote.comp.sprv"); - surfAlloc = computeShader("surf_alloc.comp.sprv"); - - irrAlloc = computeShader("irr_alloc.comp.sprv"); - irrMip = computeShader("irr_mip.comp.sprv"); - irrScatter = computeShader("irr_scatter.comp.sprv"); - - surfAdaptive = computeShader("surf_adaptive.comp.sprv"); - surfMip = computeShader("surf_mip.comp.sprv"); - surfScatter = computeShader("surf_scatter.comp.sprv"); + surfInit = computeShader("surf_init.comp.sprv"); + surfTiled = computeShader("surf_tiled.comp.sprv"); surfBinning = computeShader("surf_binning.comp.sprv"); surfBinClear = computeShader("surf_bin_clear.comp.sprv"); @@ -269,7 +260,6 @@ void Shaders::compileShaders() { surfApply = computeShader("surf_apply.comp.sprv"); - surfTiled = computeShader("surf_tiled.comp.sprv"); surfBvh = computeShader("surf_bvh.comp.sprv"); surfBvhSample = computeShader("surf_bvh_sample.comp.sprv"); } diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index fc421c38a..e5531d0f1 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -86,12 +86,10 @@ class Shaders { // GI-Surf Tempest::RenderPipeline surfDbg; - Tempest::ComputePipeline surfInit, surfVote, surfAlloc; - Tempest::ComputePipeline irrAlloc, irrMip, irrScatter; - Tempest::ComputePipeline surfAdaptive, surfMip, surfScatter; + Tempest::ComputePipeline surfInit, surfTiled; Tempest::ComputePipeline surfBinClear, surfBinning, surfBinAlloc; Tempest::ComputePipeline surfApply; - Tempest::ComputePipeline surfTiled, surfBvh, surfBvhSample; + Tempest::ComputePipeline surfBvh, surfBvhSample; Tempest::ComputePipeline surfPathtrace; // Epipolar diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index f4751aa6b..967a8b112 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -313,21 +313,13 @@ add_shader(surf_dbg.vert lighting/surfels/surf_dbg.vert) add_shader(surf_dbg.frag lighting/surfels/surf_dbg.frag) add_shader(surf_init.comp lighting/surfels/surf_init.comp) -add_shader(surf_vote.comp lighting/surfels/surf_vote.comp) -add_shader(surf_alloc.comp lighting/surfels/surf_alloc.comp) -add_shader(irr_alloc.comp lighting/surfels/irr_alloc.comp) -add_shader(irr_mip.comp lighting/surfels/irr_mip.comp) -add_shader(irr_scatter.comp lighting/surfels/irr_scatter.comp) - -add_shader(surf_adaptive.comp lighting/surfels/surf_adaptive.comp) -add_shader(surf_mip.comp lighting/surfels/surf_mip.comp) -add_shader(surf_scatter.comp lighting/surfels/surf_scatter.comp) +add_shader(surf_tiled.comp lighting/surfels/surf_tiled.comp) + add_shader(surf_binning.comp lighting/surfels/surf_binning.comp) add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) -add_shader(surf_tiled.comp lighting/surfels/surf_tiled.comp) add_shader(surf_bvh.comp lighting/surfels/surf_bvh.comp) add_shader(surf_bvh_sample.comp lighting/surfels/surf_bvh_sample.comp) add_shader(surf_pathtrace.comp lighting/surfels/surf_pathtrace.comp) diff --git a/shader/lighting/surfels/irr_alloc.comp b/shader/lighting/surfels/irr_alloc.comp deleted file mode 100644 index 54f470b49..000000000 --- a/shader/lighting/surfels/irr_alloc.comp +++ /dev/null @@ -1,140 +0,0 @@ -#version 450 - -#include "lighting/surfels/surf_common.glsl" -#include "scene.glsl" -#include "common.glsl" - -layout(local_size_x = 16, local_size_y = 16) in; - -layout(std140, push_constant) uniform Push { - vec3 originLwc; - }; -layout(binding = 0, std140) uniform UboScene { - SceneDesc scene; - }; - -layout(binding = 1) uniform sampler2D gbufDiffuse; -layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform sampler2D depth; -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; -// -layout(binding = 6, r32f) uniform image2D pdfTree; -// -layout(binding = 11, rgba8) uniform image2D dbgImage; - - -ivec2 fragCoord; -ivec2 screenSize; - -vec3 worldPos(float z) { - const mat4 inv = scene.viewProjectLwcInv; - const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; - const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); - return pos.xyz/pos.w + originLwc; - } - -float wangHashNoise(uvec2 uv, uint s) { - uint seed = (uv.x*1664525u + uv.y) + s; - uint hash = wangHash(seed); - float value = float(hash) / (4294967296.0); - return value; - } - -float readZ(in vec2 posf) { - return textureLod(depth, posf.xy*0.5+vec2(0.5), 0).r; - } - -vec3 unproject(ivec2 hit, float z) { - const vec2 inPos = vec2(2*hit+ivec2(1,1))/vec2(screenSize)-vec2(1,1); - const vec3 at = vec3(inPos.xy, z); - const vec3 pos = projectiveUnproject(scene.projectInv, at); - return pos; - } - -vec3 reconstructNormal(const ivec2 at) { - const vec3 norm = normalFetch(gbufNormal, at); - const vec3 nx = mat3(scene.view) * norm; - return nx; - } - -float pixelToWorld(float pixelRadius, float z) { - z = linearDepth(z, scene.clipInfo); - float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; - float worldRadius = (clipRadius * z) / scene.project[1][1]; - return worldRadius; - } - -vec4 hitPass(ivec2 fragCoord, float h0, const vec3 pos0, float z0, const vec3 norm) { - if(z0==1.0) - return vec4(0); - - int step = 32; - float rI = pixelToWorld(step, z0); // ideally, sholud be harmonic mean of ray hits - - float wInv = 10; - - float c = cos(h0), s = sin(h0); - ivec2 hit = fragCoord + ivec2(round(vec2(c,s)*step)); - hit = clamp(hit, ivec2(0), screenSize-1); - - const vec3 norm1 = reconstructNormal(hit); - - const float z1 = texelFetch(depth, hit, 0).r; - const vec3 pos1 = unproject(hit, z1); - - const vec3 dp = pos1-pos0; - const float lenDp = length(dp); - if(lenDp>rI*2) - ;//return vec4(0,0,1,1); - - // Making_Radiance_and_Irradiance_Caching_Practical_A.pdf - // part 3, Weighting Function - const float wDist = (lenDp)/max(rI*2.0, 1); - const float wAng = sqrt(max(1.0 - dot(norm,norm1),0)); - wInv = wDist*0 + wAng*1; - - const float wOcclusion = 1;//max(0, dot(dp/lenDp, norm1)); - - //return vec4(wDist-1); - float ret = 1.0/max(wInv,0.01); - return vec4(max(1.0 - ret, 0)); - - //const float selfOcclusionTerm = abs(dot(dp/lenDp, norm)); - //const float wErr = lenDp/rI + dot(norm, dp/lenDp); - //return vec4(1.0/(0.01+wErr)); - } - -void main() { - screenSize = ivec2(textureSize(depth,0)); - fragCoord = ivec2(gl_GlobalInvocationID.xy); - - const bool valid = all(lessThan(fragCoord, screenSize)); - const vec2 inPos = vec2(2*fragCoord+ivec2(1,1))/vec2(screenSize)-vec2(1,1); - - const float z0 = readZ(inPos.xy); - const vec3 pos0 = unproject(fragCoord,z0); - - const vec3 norm = valid ? reconstructNormal(fragCoord) : vec3(0); - const float f0 = M_PI*2.0*wangHashNoise(uvec2(fragCoord), 0); - - vec4 hit = hitPass(fragCoord,f0,pos0,z0,norm); - - if(z0<0.9999) - atomicAdd(count.y, 1); - - imageStore(pdfTree, ivec2(gl_GlobalInvocationID.xy), vec4(hit.x+0.001)); - // imageStore(pdfTree, ivec2(gl_GlobalInvocationID.xy), vec4(1)); - - imageStore(dbgImage, ivec2(gl_GlobalInvocationID.xy), hit); - - if(false && z0<0.9999 && gl_LocalInvocationIndex==0) { - // dummy for now - const uint id = atomicAdd(count.x, 1); - if(id>=surfels.length()) - return; - Surfel sx; - sx.pos = worldPos(z0); - sx.norm = texelFetch(gbufNormal, fragCoord, 0).r; - surfels[id] = sx; - } - } diff --git a/shader/lighting/surfels/irr_mip.comp b/shader/lighting/surfels/irr_mip.comp deleted file mode 100644 index 594981638..000000000 --- a/shader/lighting/surfels/irr_mip.comp +++ /dev/null @@ -1,34 +0,0 @@ -#version 450 - -layout(local_size_x = 8, local_size_y = 8) in; - -layout(binding = 0, r32f) uniform readonly image2D srcMip; -layout(binding = 1, r32f) uniform writeonly image2D dstMip; - -void main() { - ivec2 dstCoord = ivec2(gl_GlobalInvocationID.xy); - ivec2 dstSize = imageSize(dstMip); - ivec2 srcSize = imageSize(srcMip); - - if(dstCoord.x >= dstSize.x || dstCoord.y >= dstSize.y) - return; - - ivec2 coord0 = dstCoord * 2; - ivec2 coord1 = coord0+2; - - // bottom-right corner might have 3x3 footprint in npot image - if(dstCoord.x+1==dstSize.x) - coord1.x = srcSize.x; - if(dstCoord.y+1==dstSize.y) - coord1.y = srcSize.y; - - float ret = 0; - for(int i=coord0.x; i=sz.x || at.y>=sz.y) - return 0; - return texelFetch(pdfTree, at, mip).x; - } - -void sampleTree(ivec2 coord0, ivec2 coord1, int mip, inout float index, inout ivec2 p) { - for(int i=coord0.x; i0;) { - --i; - - ivec2 srcSize = textureSize(pdfTree, i+0); - ivec2 dstSize = textureSize(pdfTree, i+1); - - ivec2 coord0 = p*2; - ivec2 coord1 = coord0+2; - if(p.x+1==dstSize.x) - coord1.x = srcSize.x; - if(p.y+1==dstSize.y) - coord1.y = srcSize.y; - p *= 2; - sampleTree(coord0, coord1, i, index, p); - } - - return p; - } - -void main() { - const uint index = gl_GlobalInvocationID.x; - const int mipCount = textureQueryLevels(pdfTree); - const float maxV = texelFetch(pdfTree, ivec2(0), mipCount-1).x; - const uint maxN = count.y; - if(index>=maxN || index>=maxSurfels) - return; - - const ivec2 at = find(index/float(maxSurfels), maxV); - - if(at.x<0) - return; //error - - const uint id = atomicAdd(count.x, 1); - if(id>=surfels.length()) - return; - - const ivec2 screenSize = ivec2(textureSize(depth,0)); - const float z = texelFetch(depth, at, 0).x; - if(z==1.0) - return; - - Surfel sx; - sx.pos = worldPos(z, at, screenSize); - sx.norm = texelFetch(gbufNormal, at, 0).r; - surfels[id] = sx; - } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_adaptive.comp b/shader/lighting/surfels/surf_adaptive.comp deleted file mode 100644 index bb6d5c432..000000000 --- a/shader/lighting/surfels/surf_adaptive.comp +++ /dev/null @@ -1,52 +0,0 @@ -#version 450 - -#include "lighting/surfels/surf_common.glsl" -#include "scene.glsl" -#include "common.glsl" - -layout(local_size_x = 16, local_size_y = 16) in; - -layout(std140, push_constant) uniform Push { - vec3 originLwc; - }; -layout(binding = 0, std140) uniform UboScene { - SceneDesc scene; - }; - -layout(binding = 1) uniform sampler2D gbufDiffuse; -layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform sampler2D depth; -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 5, rgba32f) uniform image2D posTree; -layout(binding = 6, rgba16) uniform image2D normTree; -layout(binding = 7, r32f) uniform image2D pdfTree; -// -layout(binding = 11, rgba8) uniform image2D dbgImage; - -vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { - const mat4 inv = scene.viewProjectLwcInv; - const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; - const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); - return pos.xyz/pos.w + originLwc; - } - -void main() { - const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); - const ivec2 screenSize = ivec2(textureSize(depth,0)); - const bool valid = all(lessThan(fragCoord, screenSize)); - - if(!valid) - return; - - const float z = texelFetch(depth,fragCoord,0).x; - const bool sky = (z >= SKY_DEPTH); - if(!sky) - atomicAdd(count.y, 1); - - const vec3 norm = sky ? vec3(0) : normalFetch(gbufNormal,fragCoord); - const vec3 wpos = sky ? vec3(0) : worldPos(z, fragCoord, screenSize); - - imageStore(posTree, fragCoord, vec4(wpos,sky ? 0 : 1)); - imageStore(normTree, fragCoord, vec4(norm*0.5+0.5,0)); - imageStore(pdfTree, fragCoord, vec4(sky ? 0 : 0.005)); - } diff --git a/shader/lighting/surfels/surf_alloc.comp b/shader/lighting/surfels/surf_alloc.comp deleted file mode 100644 index 5c292abb5..000000000 --- a/shader/lighting/surfels/surf_alloc.comp +++ /dev/null @@ -1,60 +0,0 @@ -#version 450 - -#include "lighting/surfels/surf_common.glsl" -#include "scene.glsl" -#include "common.glsl" - -const float fov = 67.5f*M_PI/180.0; -const float cellSize = 25; - -layout(local_size_x = 64) in; - -layout(std140, push_constant) uniform Push { - vec3 originLwc; - }; -layout(binding = 0, std140) uniform UboScene { - SceneDesc scene; - }; - -layout(binding = 1) uniform sampler2D gbufDiffuse; -layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform sampler2D depth; -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; - -vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { - const mat4 inv = scene.viewProjectLwcInv; - const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; - const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); - return pos.xyz/pos.w + originLwc; - } - -ivec2 unpackSurfId(uint pkg, ivec2 screenSize) { - pkg &= 0x0FFFFFF; - return ivec2(pkg%screenSize.x, pkg/screenSize.x); - } - -void main() { - const uint hKey = gl_GlobalInvocationID.x; - if(hKey >= hashGrid.length()) - return; - - const uint sId = hashGrid[hKey]; - if(sId==0xFFFFFFFF) - return; - - const ivec2 screenSize = ivec2(textureSize(depth,0)); - const ivec2 fragCoord = unpackSurfId(sId, screenSize); - - const uint id = atomicAdd(count.x, 1); - if(id>=surfels.length()) - return; - - const float z = texelFetch(depth, fragCoord, 0).x; - const vec3 pos = worldPos(z, fragCoord, screenSize); - - Surfel sx; - sx.pos = pos; - sx.norm = texelFetch(gbufNormal, fragCoord, 0).r; - surfels[id] = sx; - } diff --git a/shader/lighting/surfels/surf_bin_alloc.comp b/shader/lighting/surfels/surf_bin_alloc.comp index b1c4391f5..52a8c1039 100644 --- a/shader/lighting/surfels/surf_bin_alloc.comp +++ b/shader/lighting/surfels/surf_bin_alloc.comp @@ -13,7 +13,7 @@ void main() { return; const uint v = imageLoad(surfCnts, tile).x; - const uint ptr = atomicAdd(count.z, v); + const uint ptr = atomicAdd(count.w, v); imageStore(surfCnts, tile, uvec4(0)); imageStore(surfBins, tile, uvec4(ptr)); diff --git a/shader/lighting/surfels/surf_init.comp b/shader/lighting/surfels/surf_init.comp index 569057913..74ecc6fe1 100644 --- a/shader/lighting/surfels/surf_init.comp +++ b/shader/lighting/surfels/surf_init.comp @@ -7,7 +7,7 @@ layout(binding = 4, std430) buffer SB0 { uvec4 count; }; void main() { if(gl_GlobalInvocationID.xy==ivec2(0)) - count = uvec4(0); + count = uvec4(0,1,1,0); /* const uint hKey = gl_GlobalInvocationID.x; if(hKey >= hashGrid.length()) diff --git a/shader/lighting/surfels/surf_mip.comp b/shader/lighting/surfels/surf_mip.comp deleted file mode 100644 index 699c81754..000000000 --- a/shader/lighting/surfels/surf_mip.comp +++ /dev/null @@ -1,64 +0,0 @@ -#version 450 - -layout(local_size_x = 8, local_size_y = 8) in; - -layout(binding = 0, rgba32f) uniform readonly image2D srcPos; -layout(binding = 1, rgba16) uniform readonly image2D srcNorm; -layout(binding = 2, r32f) uniform readonly image2D srcPdf; -layout(binding = 3, rgba32f) uniform writeonly image2D dstPos; -layout(binding = 4, rgba16) uniform writeonly image2D dstNorm; -layout(binding = 5, r32f) uniform writeonly image2D dstPdf; - -float samplePass(bool avgPass, ivec2 coord0, ivec2 coord1, inout vec4 avgPos, inout vec3 avgNormal) { - float normErr = 0, posErr = 0, parentErr = 0; - - for(int i=coord0.x; i= dstSize.x || dstCoord.y >= dstSize.y) - return; - - ivec2 coord0 = dstCoord * 2; - ivec2 coord1 = coord0+2; - - // bottom-right corner might have 3x3 footprint in npot image - if(dstCoord.x+1==dstSize.x) - coord1.x = srcSize.x; - if(dstCoord.y+1==dstSize.y) - coord1.y = srcSize.y; - - vec4 pos = vec4(0); - vec3 norm = vec3(0); - samplePass(true, coord0, coord1, pos, norm); - - float cnt = pos.w; - pos.xyz /= max(cnt,1); - norm = normalize(norm); - - const float err = cnt>0 ? samplePass(false, coord0, coord1, pos, norm) : 0; - - imageStore(dstPos, dstCoord, vec4(pos)); - imageStore(dstNorm, dstCoord, vec4(norm*0.5+0.5,0)); - imageStore(dstPdf, dstCoord, vec4(err)); - } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_scatter.comp b/shader/lighting/surfels/surf_scatter.comp deleted file mode 100644 index 9dba2c15c..000000000 --- a/shader/lighting/surfels/surf_scatter.comp +++ /dev/null @@ -1,113 +0,0 @@ -#version 450 - -#include "lighting/surfels/surf_common.glsl" -#include "scene.glsl" -#include "common.glsl" - -layout(local_size_x = 64) in; - -layout(std140, push_constant) uniform Push { - vec3 originLwc; - uint maxSurfels; - }; -layout(binding = 0, std140) uniform UboScene { - SceneDesc scene; - }; - -layout(binding = 1) uniform sampler2D gbufDiffuse; -layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform sampler2D depth; -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 5) uniform sampler2D pdfTree; - -vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { - const mat4 inv = scene.viewProjectLwcInv; - const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; - const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); - return pos.xyz/pos.w + originLwc; - } - -uint pdfFetch(in usampler2D pdfTree, ivec2 at, int mip) { - const ivec2 sz = textureSize(pdfTree, mip); - if(at.x>=sz.x || at.y>=sz.y) - return 0; - return texelFetch(pdfTree, at, mip).x; - } - -void sampleTree(ivec2 coord0, ivec2 coord1, int mip, inout float index, inout ivec2 p) { - float vSum = 0; - for(int i=coord0.x; i0) { - p = ivec2(i,r); - index /= v; - return; - } - index = index-v; - } - } - } - -ivec2 find(float index) { - const int mipCount = textureQueryLevels(pdfTree); - - ivec2 p = ivec2(0); - for(int i=mipCount-1; i>0;) { - --i; - - ivec2 srcSize = textureSize(pdfTree, i+0); - ivec2 dstSize = textureSize(pdfTree, i+1); - - ivec2 coord0 = p*2; - ivec2 coord1 = coord0+2; - if(p.x+1==dstSize.x) - coord1.x = srcSize.x; - if(p.y+1==dstSize.y) - coord1.y = srcSize.y; - p *= 2; - sampleTree(coord0, coord1, i, index, p); - } - - return p; - } - -void main() { - const uint index = gl_GlobalInvocationID.x; - const int mipCount = textureQueryLevels(pdfTree); - const uint maxN = count.y; - if(index>=maxN || index>=maxSurfels) - return; - - const ivec2 at = find(index/float(maxSurfels)); - - if(at.x<0) - return; //error - - const uint id = atomicAdd(count.x, 1); - if(id>=surfels.length()) - return; - - const ivec2 screenSize = ivec2(textureSize(depth,0)); - const float z = texelFetch(depth, at, 0).x; - if(z==1.0) - return; - - Surfel sx; - sx.pos = worldPos(z, at, screenSize); - sx.norm = texelFetch(gbufNormal, at, 0).r; - surfels[id] = sx; - } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_vote.comp b/shader/lighting/surfels/surf_vote.comp deleted file mode 100644 index 808f74e38..000000000 --- a/shader/lighting/surfels/surf_vote.comp +++ /dev/null @@ -1,96 +0,0 @@ -#version 450 - -#include "lighting/surfels/surf_common.glsl" -#include "scene.glsl" -#include "common.glsl" - -const float fov = 67.5f*M_PI/180.0; - -layout(local_size_x = 16, local_size_y = 16) in; - -layout(std140, push_constant) uniform Push { - vec3 originLwc; - }; -layout(binding = 0, std140) uniform UboScene { - SceneDesc scene; - }; - -layout(binding = 1) uniform sampler2D gbufDiffuse; -layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform sampler2D depth; -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; - -layout(binding = 11, rgba8) uniform image2D dbgImage; - -shared uint vote; -void makeVote(ivec2 at) { - atomicMin(vote, (at.x + at.y*gl_WorkGroupSize.x)); - } - -vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { - const mat4 inv = scene.viewProjectLwcInv; - const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; - const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); - return pos.xyz/pos.w + originLwc; - } - -uint packSurfId(float dist, ivec2 fragCoord, ivec2 screenSize) { - uint lo = (fragCoord.x + fragCoord.y*screenSize.x) & 0x0FFFFFF; - uint up = min(uint(dist * 0xFF), 0xFF) << 24; - return up | lo; - } - -vec3 hasGridPos(vec3 wpos, float cellSize) { - wpos = wpos / cellSize; - return round(wpos); - } - -float surfDist(vec3 hpos, vec3 pos, float cellSize) { - vec3 p = (pos/cellSize - hpos); - p *= 2/sqrt(2.0); - return dot(p,p); //quad distance - } - -float surfDist(vec3 hpos, vec3 pos, float cellSize, uint inorm, vec3 norm) { - vec3 p = (pos/cellSize - hpos); - p *= 2/sqrt(2.0); - float ed = length(p); // distance - - vec3 n = i_octahedral_8(inorm); - float en = sqrt(max(1.0 - dot(n,norm),0.0)); - return ed+en; - } - -void main() { - const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); - const ivec2 screenSize = ivec2(textureSize(depth,0)); - const bool valid = all(lessThan(fragCoord, screenSize)); - - if(!valid) - return; - - const float z = texelFetch(depth,fragCoord,0).x; - const vec3 norm = normalFetch(gbufNormal,fragCoord); - if(z >= SKY_DEPTH) - return; - - const float ld = max(linearDepth(z, scene.clipInfo), 10); - const float sz = computeCellSize(ld, fov, textureSize(depth,0), SURFEL_CELL); - - const vec3 wpos = worldPos(z, fragCoord, screenSize); - const vec3 ipos = hasGridPos(wpos, sz); - const uint inorm = octahedral_8(norm); - - const float dist = surfDist(ipos, wpos, sz, inorm, norm); - const uint hKey = surfHash(ipos, sz, inorm) % hashGrid.length(); - - if(dist>0.9) - return; - - const uint sId = packSurfId(dist, fragCoord, screenSize); - atomicMin(hashGrid[hKey], sId); - - imageStore(dbgImage, fragCoord, vec4(debugColors[hKey%debugColors.length()], 1.0)); - } - From dd973513513b29c42b4c2389f5820b51d151c409 Mon Sep 17 00:00:00 2001 From: Try Date: Mon, 8 Jun 2026 00:07:21 +0200 Subject: [PATCH 17/52] cleanup --- game/graphics/renderer.cpp | 138 +------------------- shader/lighting/surfels/surf_pathtrace.comp | 5 +- shader/lighting/surfels/surf_tiled.comp | 8 +- 3 files changed, 11 insertions(+), 140 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index cc0952652..9f48dc815 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1950,20 +1950,14 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor if(!settings.giSurfelsEnabled) return; - const uint32_t hashGridSize = 4'194'304; // SHaRC docimentation recommends 2^22 - const uint32_t maxSurfels = surf.maxSurfels; - static int32_t tileSize = 256; + const uint32_t maxSurfels = surf.maxSurfels; + static int32_t tileSize = 256; cmd.setDebugMarker("Surfels"); auto& scene = wview.sceneGlobals(); - auto& surfels = usesSsboInit(surf.surfels, shaders.surfVote.sizeofBuffer(4, surf.maxSurfels)); + auto& surfels = usesSsboInit(surf.surfels, shaders.surfTiled.sizeofBuffer(4, surf.maxSurfels)); auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::R11G11B10UF, zbuffer.size()); - - auto& hashGrid = usesSsboInit(surf.hashGrid, hashGridSize); - auto& pdfTree = usesImage2d (surf.pdfTree, TextureFormat::R32F, zbuffer.size(), true); - auto& posTree = usesImage2d (surf.posTree, TextureFormat::RGBA32F, zbuffer.size(), true); - auto& normTree = usesImage2d (surf.normTree, TextureFormat::RGBA16, zbuffer.size(), true); auto& surfList = usesSsboInit(surf.surfList, surf.maxSurfels*sizeof(uint32_t)); auto& surfBvh = usesSsbo (surf.surfBvh, shaders.surfBvh.sizeofBuffer(5, 2*surf.maxSurfels)); @@ -1973,130 +1967,6 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor auto& surfBins = usesImage2d (surf.surfBins, TextureFormat::R32U, tc); static bool alloc = true; - if(false && alloc) { - struct Push { - Vec3 originLwc; - } push; - push.originLwc = scene.originLwc; - - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); - cmd.setBinding(4, surfels); - cmd.setBinding(5, hashGrid); - // - cmd.setBinding(11, dbgImage); - - cmd.setPipeline(shaders.surfInit); - cmd.dispatchThreads(hashGridSize); - - cmd.setPipeline(shaders.surfVote); - cmd.dispatchThreads(sceneDepth.size()); - - cmd.setPipeline(shaders.surfAlloc); - cmd.dispatchThreads(hashGridSize); - //alloc = false; - } - - if(false && alloc) { - struct Push { - Vec3 originLwc; - uint32_t maxSurfels; - } push = {}; - push.originLwc = scene.originLwc; - push.maxSurfels = maxSurfels; - - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); - cmd.setBinding(4, surfels); - cmd.setBinding(5, hashGrid); - cmd.setBinding(6, pdfTree); - // - cmd.setBinding(11, dbgImage); - - cmd.setPipeline(shaders.surfInit); - cmd.dispatchThreads(hashGridSize); //for sake of zeroing counters - - cmd.setPipeline(shaders.irrAlloc); - cmd.dispatchThreads(sceneDepth.size()); - - uint32_t w = uint32_t(pdfTree.w()), h = uint32_t(pdfTree.h()); - cmd.setPipeline(shaders.irrMip); - for(uint32_t i=1; i(w/2, 1); - h = std::max(h/2, 1); - cmd.dispatchThreads(w,h); - } - - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); - cmd.setBinding(4, surfels); - cmd.setBinding(5, hashGrid); - cmd.setBinding(6, pdfTree); - cmd.setPipeline(shaders.irrScatter); - cmd.dispatchThreads(maxSurfels); - } - - if(false && alloc) { - struct Push { - Vec3 originLwc; - uint32_t maxSurfels; - } push = {}; - push.originLwc = scene.originLwc; - push.maxSurfels = maxSurfels; - - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); - cmd.setBinding(4, surfels); - cmd.setBinding(5, posTree); - cmd.setBinding(6, normTree); - cmd.setBinding(7, pdfTree); - // - cmd.setBinding(11, dbgImage); - - cmd.setPipeline(shaders.surfInit); - cmd.dispatchThreads(1); //for sake of zeroing counters - - cmd.setPipeline(shaders.surfAdaptive); - cmd.dispatchThreads(sceneDepth.size()); - // - cmd.setPipeline(shaders.surfMip); - for(uint32_t i=1; i(uint32_t(sceneDepth.w()) >> i, 1); - uint32_t h = std::max(uint32_t(sceneDepth.h()) >> i, 1); - cmd.dispatchThreads(w,h); - } - // - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); - cmd.setBinding(4, surfels); - cmd.setBinding(5, pdfTree); - cmd.setPipeline(shaders.surfScatter); - cmd.dispatchThreads(maxSurfels); - } - if(true && alloc) { struct Push { Vec3 originLwc; @@ -2507,7 +2377,7 @@ void Renderer::drawRayQueryDbg(Tempest::Encoder& cmd, co } void Renderer::drawSurfelsDbg(Encoder& cmd, const WorldView& wview) { - static bool enable = true; + static bool enable = false; if(!enable) return; diff --git a/shader/lighting/surfels/surf_pathtrace.comp b/shader/lighting/surfels/surf_pathtrace.comp index b32234207..f0bbe6d43 100644 --- a/shader/lighting/surfels/surf_pathtrace.comp +++ b/shader/lighting/surfels/surf_pathtrace.comp @@ -250,8 +250,9 @@ void main() { vec3 irradiance = vec3(0); float hHit = 0; // harmonic mean for(int i=0; i Date: Mon, 8 Jun 2026 02:12:55 +0200 Subject: [PATCH 18/52] random generation lib --- game/graphics/renderer.cpp | 2 +- shader/lighting/pt/pathtrace_common.glsl | 101 ++++++++++++++++ shader/lighting/surfels/surf_bin_alloc.comp | 1 + shader/lighting/surfels/surf_pathtrace.comp | 127 ++------------------ shader/random.glsl | 56 +++++++++ 5 files changed, 166 insertions(+), 121 deletions(-) create mode 100644 shader/lighting/pt/pathtrace_common.glsl create mode 100644 shader/random.glsl diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 9f48dc815..34beec6dc 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1958,7 +1958,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor auto& surfels = usesSsboInit(surf.surfels, shaders.surfTiled.sizeofBuffer(4, surf.maxSurfels)); auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::R11G11B10UF, zbuffer.size()); - auto& surfList = usesSsboInit(surf.surfList, surf.maxSurfels*sizeof(uint32_t)); + auto& surfList = usesSsbo (surf.surfList, surf.maxSurfels*sizeof(uint32_t)); auto& surfBvh = usesSsbo (surf.surfBvh, shaders.surfBvh.sizeofBuffer(5, 2*surf.maxSurfels)); diff --git a/shader/lighting/pt/pathtrace_common.glsl b/shader/lighting/pt/pathtrace_common.glsl new file mode 100644 index 000000000..55228d506 --- /dev/null +++ b/shader/lighting/pt/pathtrace_common.glsl @@ -0,0 +1,101 @@ +#ifndef PATHTRACE_COMMON_GLSL +#define PATHTRACE_COMMON_GLSL + +#include "random.glsl" + +const float TMax = 1e30f; + +struct HitResolve { + vec4 diff; + vec3 norm; + float rayT; + bool water; + }; + +float rayPathTextureLOD(float dist, vec3 dir, vec3 norm) { + dist /= 500.0; + float mip = 0; + mip += log2(dist); + mip -= log2(abs(dot(dir, norm))); + return mip; + } + +void rayQueryProceedAlphaTest(in rayQueryEXT rayQuery, inout random rng) { + while(rayQueryProceedEXT(rayQuery)) { + const uint type = rayQueryGetIntersectionTypeEXT(rayQuery,false); + if(type==gl_RayQueryCandidateIntersectionTriangleEXT) { + const vec4 d = resolveHit(rayQuery); + // const bool opaqueHit = (d.a>0.5); + const bool opaqueHit = (d.a > randf(rng)); + if(opaqueHit) + rayQueryConfirmIntersectionEXT(rayQuery); + } + } + } + +float rayQueryProceedShadow(const vec3 rayOrigin, const vec3 rayDirection, inout random rngState) { + // CullBack due to vegetation + uint flags = gl_RayFlagsSkipAABBEXT | gl_RayFlagsCullBackFacingTrianglesEXT; + float tMin = 1; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, topLevelAS, flags, CM_ShadowCaster, + rayOrigin, tMin, rayDirection, 500*100); + rayQueryProceedAlphaTest(rayQuery); + // rayQueryProceedAlphaTest(rayQuery, rngState); + if(rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) + return 1; + return 0; + } + +HitResolve rayQueryProceedPrimary(const vec3 rayOrigin, const vec3 rayDirection, float mipOverride, inout random rngState) { + // CullBack due to vegetation + uint flags = gl_RayFlagsSkipAABBEXT | gl_RayFlagsCullBackFacingTrianglesEXT; + float tMin = 2; + + rayQueryEXT rayQuery; + rayQueryInitializeEXT(rayQuery, topLevelAS, flags, 0xFF, + rayOrigin, tMin, rayDirection, 500*100); + rayQueryProceedAlphaTest(rayQuery); + // rayQueryProceedAlphaTest(rayQuery, rngState); + if(rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) { + HitResolve ret; + ret.rayT = TMax; + return ret; + } + + const HitDesc hit = pullCommitedHitDesc(rayQuery); + + const float rayT = rayQueryGetIntersectionTEXT(rayQuery, true); + const bool face = !(rayQueryGetIntersectionFrontFaceEXT(rayQuery, true)); //NOTE: not working on vegetation + + const uint id = hit.instanceId; + const uvec3 index = pullTrinagleIds(id,hit.primitiveId); + + const vec2 uv0 = pullTexcoord(id,index.x); + const vec2 uv1 = pullTexcoord(id,index.y); + const vec2 uv2 = pullTexcoord(id,index.z); + + const vec3 nr0 = pullNormal(id,index.x); + const vec3 nr1 = pullNormal(id,index.y); + const vec3 nr2 = pullNormal(id,index.z); + + const vec3 b = hit.baryCoord; + const vec2 uv = (b.x*uv0 + b.y*uv1 + b.z*uv2); + vec3 norm = (b.x*nr0 + b.y*nr1 + b.z*nr2); + + const mat3x3 matrix = mat3x3(rayQueryGetIntersectionObjectToWorldEXT(rayQuery, true)); + norm = normalize(matrix*norm); + + const float mip = mipOverride>=0 ? mipOverride : rayPathTextureLOD(rayT,rayDirection,norm); + const vec4 diff = textureLod(sampler2D(textures[nonuniformEXT(id)], smp),uv,mip); + + HitResolve ret; + ret.diff = diff; + ret.norm = norm; + ret.rayT = face ? -rayT : rayT; + ret.water = hit.water; + return ret; + } + +#endif \ No newline at end of file diff --git a/shader/lighting/surfels/surf_bin_alloc.comp b/shader/lighting/surfels/surf_bin_alloc.comp index 52a8c1039..481555720 100644 --- a/shader/lighting/surfels/surf_bin_alloc.comp +++ b/shader/lighting/surfels/surf_bin_alloc.comp @@ -5,6 +5,7 @@ layout(local_size_x = 8, local_size_y = 8) in; layout(binding = 1, std430) buffer SB0 { uvec4 count; }; layout(binding = 2, r32ui) uniform uimage2D surfCnts; layout(binding = 3, r32ui) uniform uimage2D surfBins; +layout(binding = 4, std430) readonly buffer SB1 { uint surfelIds[]; }; void main() { const ivec2 tile = ivec2(gl_GlobalInvocationID.xy); diff --git a/shader/lighting/surfels/surf_pathtrace.comp b/shader/lighting/surfels/surf_pathtrace.comp index f0bbe6d43..d893615a9 100644 --- a/shader/lighting/surfels/surf_pathtrace.comp +++ b/shader/lighting/surfels/surf_pathtrace.comp @@ -5,20 +5,13 @@ #define RAY_QUERY_AT #include "lighting/rt/rt_common.glsl" +#include "lighting/pt/pathtrace_common.glsl" #include "lighting/surfels/surf_common.glsl" #include "lighting/tonemapping.glsl" #include "scene.glsl" #include "common.glsl" - -const float TMax = 1e30f; - -struct HitResolve { - vec4 diff; - vec3 norm; - float rayT; - bool water; - }; +#include "random.glsl" layout(local_size_x = 64) in; @@ -28,14 +21,6 @@ layout(binding = 0, std140) uniform UboScene { layout(binding = 1, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; layout(binding = 2) uniform sampler2D skyLUT; -uint srand(uvec2 fragCoord, uint seed) { - return uint(uint(fragCoord.x) * uint(1973) + uint(fragCoord.y) * uint(9277) + uint(seed) * uint(26699)) | uint(1); - } - -float randf(inout uint state) { - return float(wangHash(state)) / 4294967296.0; - } - mat3 toTangent(vec3 norm) { mat3 tangent; // Compute a tangent frame and rotate the half vector to world space @@ -46,107 +31,7 @@ mat3 toTangent(vec3 norm) { return tangent; } -float computeTextureLOD(float dist, vec3 dir, vec3 norm) { - dist /= 500.0; - float mip = 0; - mip += log2(dist); - mip -= log2(abs(dot(dir, norm))); - return mip; - } - -vec3 randCosWeightedHemisphereDirection(const mat3 tbn, inout uint rngState) { - vec2 rv2 = vec2(randf(rngState), randf(rngState)); - - float ra = sqrt(rv2.y); - float rx = ra*cos(6.2831*rv2.x); - float ry = ra*sin(6.2831*rv2.x); - float rz = sqrt( 1.0-rv2.y ); - vec3 rr = vec3( rx*tbn[0] + ry*tbn[1] + rz*tbn[2] ); - - return normalize(rr); - } - -vec3 randCosWeightedHemisphereDirection(const vec3 n, inout uint rngState) { - vec2 rv2 = vec2(randf(rngState), randf(rngState)); - - vec3 uu = normalize( cross( n, vec3(0.0,1.0,1.0) ) ); - vec3 vv = normalize( cross( uu, n ) ); - - float ra = sqrt(rv2.y); - float rx = ra*cos(6.2831*rv2.x); - float ry = ra*sin(6.2831*rv2.x); - float rz = sqrt( 1.0-rv2.y ); - vec3 rr = vec3( rx*uu + ry*vv + rz*n ); - - return normalize(rr); - } - -float rayQueryProceedShadow(const vec3 rayOrigin, const vec3 rayDirection, inout uint rngState) { - // CullBack due to vegetation - uint flags = gl_RayFlagsSkipAABBEXT | gl_RayFlagsCullBackFacingTrianglesEXT; - float tMin = 1; - - rayQueryEXT rayQuery; - rayQueryInitializeEXT(rayQuery, topLevelAS, flags, CM_ShadowCaster, - rayOrigin, tMin, rayDirection, 500*100); - rayQueryProceedAlphaTest(rayQuery); - // rayQueryProceedAlphaTest(rayQuery, rngState); - if(rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) - return 1; - return 0; - } - -HitResolve rayQueryProceedPrimary(const vec3 rayOrigin, const vec3 rayDirection, float mipOverride, inout uint rngState) { - // CullBack due to vegetation - uint flags = gl_RayFlagsSkipAABBEXT | gl_RayFlagsCullBackFacingTrianglesEXT; - float tMin = 2; - - rayQueryEXT rayQuery; - rayQueryInitializeEXT(rayQuery, topLevelAS, flags, 0xFF, - rayOrigin, tMin, rayDirection, 500*100); - rayQueryProceedAlphaTest(rayQuery); - // rayQueryProceedAlphaTest(rayQuery, rngState); - if(rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) { - HitResolve ret; - ret.rayT = TMax; - return ret; - } - - const HitDesc hit = pullCommitedHitDesc(rayQuery); - - const float rayT = rayQueryGetIntersectionTEXT(rayQuery, true); - const bool face = !(rayQueryGetIntersectionFrontFaceEXT(rayQuery, true)); //NOTE: not working on vegetation - - const uint id = hit.instanceId; - const uvec3 index = pullTrinagleIds(id,hit.primitiveId); - - const vec2 uv0 = pullTexcoord(id,index.x); - const vec2 uv1 = pullTexcoord(id,index.y); - const vec2 uv2 = pullTexcoord(id,index.z); - - const vec3 nr0 = pullNormal(id,index.x); - const vec3 nr1 = pullNormal(id,index.y); - const vec3 nr2 = pullNormal(id,index.z); - - const vec3 b = hit.baryCoord; - const vec2 uv = (b.x*uv0 + b.y*uv1 + b.z*uv2); - vec3 norm = (b.x*nr0 + b.y*nr1 + b.z*nr2); - - const mat3x3 matrix = mat3x3(rayQueryGetIntersectionObjectToWorldEXT(rayQuery, true)); - norm = normalize(matrix*norm); - - const float mip = mipOverride>=0 ? mipOverride : computeTextureLOD(rayT,rayDirection,norm); - const vec4 diff = textureLod(sampler2D(textures[nonuniformEXT(id)], smp),uv,mip); - - HitResolve ret; - ret.diff = diff; - ret.norm = norm; - ret.rayT = face ? -rayT : rayT; - ret.water = hit.water; - return ret; - } - -float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shadowed, float softAngle, inout uint rngState) { +float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shadowed, float softAngle, inout random rngState) { #if defined(SOFT_SHADOW) vec3 shRay = randomizeRay(rayDirection, 0.5*M_PI/180.0, rngState); #else @@ -162,7 +47,7 @@ float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shado return (lamb * shadow); } -vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout uint rngState) { +vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout random rngState) { const int numBounces = 5; vec3 thruput = vec3(1); @@ -199,6 +84,7 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout uint rngState) { break; } + /* if(underWater) { const float depth = hit.rayT / 5000.0; // 50 meters const vec3 transmittance = exp(-depth * vec3(4,2,1) * 1.25); @@ -217,6 +103,7 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout uint rngState) { thruput *= WaterAlbedo; continue; } + */ rayOrigin = (rayOrigin + rayDirection * hit.rayT); rayDirection = randCosWeightedHemisphereDirection(hit.norm, rngState); @@ -242,7 +129,7 @@ void main() { if(surfelId>=count.x) return; - uint rngState = 0; //srand(uvec2(0,0), scene.tickCount32); + random rngState = random(0); const Surfel p = surfels[surfelId]; const mat3 tbn = toTangent(decodeNormal(p.norm)); diff --git a/shader/random.glsl b/shader/random.glsl new file mode 100644 index 000000000..cfd041fc1 --- /dev/null +++ b/shader/random.glsl @@ -0,0 +1,56 @@ +#ifndef RANDOM_GLSL +#define RANDOM_GLSL + +#include "common.glsl" + +struct random { + uint state; + }; + +random srand(uvec2 fragCoord, uint seed) { + random r; + r.state = uint(uint(fragCoord.x) * uint(1973) + uint(fragCoord.y) * uint(9277) + uint(seed) * uint(26699)) | uint(1); + return r; + } + +float randf(inout random r) { + return float(wangHash(r.state)) / 4294967296.0; + } + +vec3 randVec3(inout random rng) { + float z = randf(rng) * 2.0 - 1.0; + float a = randf(rng) * 2.0 * M_PI; + float r = sqrt(1.0f - z * z); + float x = r * cos(a); + float y = r * sin(a); + return vec3(x, y, z); + } + +vec3 randCosWeightedHemisphereDirection(const vec3 n, inout random rng) { + vec2 rv2 = vec2(randf(rng), randf(rng)); + + vec3 uu = normalize( cross( n, vec3(0.0,1.0,1.0) ) ); + vec3 vv = normalize( cross( uu, n ) ); + + float ra = sqrt(rv2.y); + float rx = ra*cos(6.2831*rv2.x); + float ry = ra*sin(6.2831*rv2.x); + float rz = sqrt( 1.0-rv2.y ); + vec3 rr = vec3( rx*uu + ry*vv + rz*n ); + + return normalize(rr); + } + +vec3 randCosWeightedHemisphereDirection(const mat3 tbn, inout random rng) { + vec2 rv2 = vec2(randf(rng), randf(rng)); + + float ra = sqrt(rv2.y); + float rx = ra*cos(6.2831*rv2.x); + float ry = ra*sin(6.2831*rv2.x); + float rz = sqrt( 1.0-rv2.y ); + vec3 rr = vec3( rx*tbn[0] + ry*tbn[1] + rz*tbn[2] ); + + return normalize(rr); + } + +#endif \ No newline at end of file From a28a2a0360e25ed040ecc065bbd4a9f4f0882d2a Mon Sep 17 00:00:00 2001 From: Try Date: Mon, 8 Jun 2026 21:23:56 +0200 Subject: [PATCH 19/52] optimize surfel pt --- game/graphics/renderer.cpp | 3 +- shader/lighting/surfels/surf_apply.comp | 11 ++++-- shader/lighting/surfels/surf_bin_clear.comp | 2 +- shader/lighting/surfels/surf_binning.comp | 2 +- shader/lighting/surfels/surf_dbg.frag | 3 +- shader/lighting/surfels/surf_pathtrace.comp | 44 +++++++++++++++------ shader/lighting/surfels/surf_tiled.comp | 2 +- 7 files changed, 45 insertions(+), 22 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 34beec6dc..77304b1bc 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -2068,7 +2068,8 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setBinding(11,scene.rtScene.rtDesc); cmd.setPipeline(shaders.surfPathtrace); - cmd.dispatchThreads(maxSurfels); + //cmd.dispatchThreads(maxSurfels); + cmd.dispatchIndirect(surfels, 0); } static bool apply = true; diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp index 248e3d53b..d0aac5864 100644 --- a/shader/lighting/surfels/surf_apply.comp +++ b/shader/lighting/surfels/surf_apply.comp @@ -28,6 +28,7 @@ const uint MaxSurfInCache = 128; shared uint surfCount; shared vec4 surfelsPos [MaxSurfInCache]; shared vec4 surfelsNorm[MaxSurfInCache]; +shared vec4 surfelsIrr [MaxSurfInCache]; vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { const mat4 inv = scene.viewProjectLwcInv; @@ -61,6 +62,7 @@ void pullTile(ivec2 tileId) { return; surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); surfelsNorm[id] = vec4(decodeNormal(s.norm), s.radius); + surfelsIrr [id] = vec4(s.irradiance, 0); } } @@ -86,8 +88,10 @@ void main() { surfCount = min(surfCount, MaxSurfInCache); barrier(); - if(!valid || sky) + if(!valid || sky) { + imageStore(irradiance, fragCoord, vec4(0)); return; + } const vec3 wpos = worldPos(z, fragCoord, screenSize); const vec3 norm = normalFetch(gbufNormal,fragCoord); @@ -95,9 +99,8 @@ void main() { vec4 clr = vec4(0); float maxW = 0; for(int i=0; imaxW) maxW = w; if(w <= 0) diff --git a/shader/lighting/surfels/surf_bin_clear.comp b/shader/lighting/surfels/surf_bin_clear.comp index c73c298b8..1109e9bfb 100644 --- a/shader/lighting/surfels/surf_bin_clear.comp +++ b/shader/lighting/surfels/surf_bin_clear.comp @@ -8,7 +8,7 @@ layout(binding = 3, r32ui) uniform uimage2D surfBins; void main() { if(gl_GlobalInvocationID.xy==uvec2(0)) - count.z = 0; + count.w = 0; const ivec2 tile = ivec2(gl_GlobalInvocationID.xy); const ivec2 sz = imageSize(surfBins); diff --git a/shader/lighting/surfels/surf_binning.comp b/shader/lighting/surfels/surf_binning.comp index 6dbf04a88..d29eb0b80 100644 --- a/shader/lighting/surfels/surf_binning.comp +++ b/shader/lighting/surfels/surf_binning.comp @@ -34,4 +34,4 @@ void main() { const uint ptr = imageLoad(surfBins, tile).x + lptr; surfelIds[ptr] = surfelId; } - } \ No newline at end of file + } diff --git a/shader/lighting/surfels/surf_dbg.frag b/shader/lighting/surfels/surf_dbg.frag index 39fd9c4e3..027d34f04 100644 --- a/shader/lighting/surfels/surf_dbg.frag +++ b/shader/lighting/surfels/surf_dbg.frag @@ -43,7 +43,8 @@ void main(void) { if(length(delta) > radius) ;//discard; - vec3 clr = surfDebugColor(p, instanceIndex) * (1.0-qDist); + // vec3 clr = surfDebugColor(p, instanceIndex) * (1.0-qDist); + vec3 clr = p.irradiance * (1.0-qDist) * scene.exposure; outColor = vec4(clr,1.0); // outColor = vec4(1,0,0,1.0); } diff --git a/shader/lighting/surfels/surf_pathtrace.comp b/shader/lighting/surfels/surf_pathtrace.comp index d893615a9..f89053eb0 100644 --- a/shader/lighting/surfels/surf_pathtrace.comp +++ b/shader/lighting/surfels/surf_pathtrace.comp @@ -15,6 +15,8 @@ layout(local_size_x = 64) in; +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; @@ -62,9 +64,11 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout random rngState) { if(bounce>=numBounces) { // return 0.5*vec4(1,0,1,depth)*scene.GSunIntensity; // rescale to 100% thruput + /* vec3 scale = 1.0-thruput; if(scale.r>0.01 && scale.g>0.01 && scale.b>0.01) return vec4(color/scale, depth); + */ return vec4(color, depth); } @@ -107,7 +111,7 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout random rngState) { rayOrigin = (rayOrigin + rayDirection * hit.rayT); rayDirection = randCosWeightedHemisphereDirection(hit.norm, rngState); - thruput *= textureAlbedo(hit.diff.rgb); + thruput *= min(textureAlbedo(hit.diff.rgb), 0.95); //thruput *= vec3(0.85); //snow //thruput *= vec3(0.04); // asphalt //if(bounce>0) @@ -123,9 +127,22 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout random rngState) { return vec4(color, depth); } +shared vec4 reduction[NumThreads]; + +void reduceIrr() { + uint laneID = gl_LocalInvocationIndex; + + for(uint stride = NumThreads/2; stride > 0; stride >>= 1) { + if(laneID < stride) { + reduction[laneID] += reduction[laneID + stride]; + } + barrier(); + } + } + void main() { - const uint numPaths = 16; - const uint surfelId = gl_GlobalInvocationID.x; + const uint numPaths = NumThreads; + const uint surfelId = gl_WorkGroupID.x; //gl_GlobalInvocationID.x; if(surfelId>=count.x) return; @@ -134,16 +151,17 @@ void main() { const Surfel p = surfels[surfelId]; const mat3 tbn = toTangent(decodeNormal(p.norm)); - vec3 irradiance = vec3(0); - float hHit = 0; // harmonic mean - for(int i=0; i Date: Mon, 8 Jun 2026 22:34:55 +0200 Subject: [PATCH 20/52] pt adjustment --- shader/lighting/pt/pathtrace.frag | 153 ++++-------------------------- 1 file changed, 17 insertions(+), 136 deletions(-) diff --git a/shader/lighting/pt/pathtrace.frag b/shader/lighting/pt/pathtrace.frag index 312ad5157..2c4190260 100644 --- a/shader/lighting/pt/pathtrace.frag +++ b/shader/lighting/pt/pathtrace.frag @@ -5,14 +5,14 @@ #define RAY_QUERY_AT #define SOFT_SHADOW +// #define RESCALE #include "lighting/rt/rt_common.glsl" +#include "lighting/pt/pathtrace_common.glsl" #include "lighting/tonemapping.glsl" #include "scene.glsl" #include "common.glsl" -//const float probeRayDistance = 200*100; // Lumen rt-probe uses 200-meters range -const float TMax = 1e30f; const vec3 groundAlbedo = vec3(0.3f); // testing layout(location = 0) in vec2 inUV; @@ -28,38 +28,6 @@ layout(binding = 2) uniform texture2D irradiance; layout(binding = 3) uniform sampler2D skyLUT; layout(binding = 4) uniform sampler2D textureSm1; -uint srand(uvec2 fragCoord, uint seed) { - return uint(uint(fragCoord.x) * uint(1973) + uint(fragCoord.y) * uint(9277) + uint(seed) * uint(26699)) | uint(1); - } - -float randf(inout uint state) { - return float(wangHash(state)) / 4294967296.0; - } - -vec3 randVec3(inout uint state) { - float z = randf(state) * 2.0 - 1.0; - float a = randf(state) * 2.0 * M_PI; - float r = sqrt(1.0f - z * z); - float x = r * cos(a); - float y = r * sin(a); - return vec3(x, y, z); - } - -vec3 randCosWeightedHemisphereDirection(const vec3 n, inout uint rngState) { - vec2 rv2 = vec2(randf(rngState), randf(rngState)); - - vec3 uu = normalize( cross( n, vec3(0.0,1.0,1.0) ) ); - vec3 vv = normalize( cross( uu, n ) ); - - float ra = sqrt(rv2.y); - float rx = ra*cos(6.2831*rv2.x); - float ry = ra*sin(6.2831*rv2.x); - float rz = sqrt( 1.0-rv2.y ); - vec3 rr = vec3( rx*uu + ry*vv + rz*n ); - - return normalize(rr); - } - vec3 skyIrradiance(vec3 n) { ivec3 d; d.x = n.x>=0 ? 1 : 0; @@ -94,50 +62,8 @@ float shadowFactor(vec3 pos) { return calcShadow(shPos.xyz/shPos.w); } -void rayQueryProceedAlphaTest(in rayQueryEXT rayQuery, inout uint rngState) { - while(rayQueryProceedEXT(rayQuery)) { - const uint type = rayQueryGetIntersectionTypeEXT(rayQuery,false); - if(type==gl_RayQueryCandidateIntersectionTriangleEXT) { - const vec4 d = resolveHit(rayQuery); - // const bool opaqueHit = (d.a>0.5); - const bool opaqueHit = (d.a > randf(rngState)); - if(opaqueHit) - rayQueryConfirmIntersectionEXT(rayQuery); - } - } - } -float rayQueryProceedShadow(const vec3 rayOrigin, const vec3 rayDirection, inout uint rngState) { - // CullBack due to vegetation - uint flags = gl_RayFlagsSkipAABBEXT | gl_RayFlagsCullBackFacingTrianglesEXT; - float tMin = 1; - - rayQueryEXT rayQuery; - rayQueryInitializeEXT(rayQuery, topLevelAS, flags, CM_ShadowCaster, - rayOrigin, tMin, rayDirection, 500*100); - rayQueryProceedAlphaTest(rayQuery); - // rayQueryProceedAlphaTest(rayQuery, rngState); - if(rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) - return 1; - return 0; - } - -float computeTextureLOD(float dist, vec3 dir, vec3 norm) { - dist /= 500.0; - float mip = 0; - mip += log2(dist); - mip -= log2(abs(dot(dir, norm))); - return mip; - } - -struct HitResolve { - vec4 diff; - vec3 norm; - float rayT; - bool water; - }; - -vec3 randomizeRay(vec3 ray, float angle, inout uint rngState) { +vec3 randomizeRay(vec3 ray, float angle, inout random rngState) { // https://www.shadertoy.com/view/3sfBWs const vec2 blueNoiseInDisk[64] = vec2[64]( vec2(0.478712,0.875764), @@ -207,7 +133,7 @@ vec3 randomizeRay(vec3 ray, float angle, inout uint rngState) { ); // get a blue noise sample position - vec2 samplePos = blueNoiseInDisk[wangHash(rngState)%blueNoiseInDisk.length()]; + vec2 samplePos = blueNoiseInDisk[wangHash(rngState.state)%blueNoiseInDisk.length()]; samplePos *= tan(angle); vec3 r = normalize(vec3(0,0,1) + vec3(samplePos,0)); @@ -218,57 +144,7 @@ vec3 randomizeRay(vec3 ray, float angle, inout uint rngState) { return vec3( r.x*uu + r.y*vv + r.z*ray ); } -HitResolve rayQueryProceedPrimary(const vec3 rayOrigin, const vec3 rayDirection, float mipOverride, inout uint rngState) { - // CullBack due to vegetation - uint flags = gl_RayFlagsSkipAABBEXT | gl_RayFlagsCullBackFacingTrianglesEXT; - float tMin = 2; - - rayQueryEXT rayQuery; - rayQueryInitializeEXT(rayQuery, topLevelAS, flags, 0xFF, - rayOrigin, tMin, rayDirection, 500*100); - rayQueryProceedAlphaTest(rayQuery); - // rayQueryProceedAlphaTest(rayQuery, rngState); - if(rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) { - HitResolve ret; - ret.rayT = TMax; - return ret; - } - - const HitDesc hit = pullCommitedHitDesc(rayQuery); - - const float rayT = rayQueryGetIntersectionTEXT(rayQuery, true); - const bool face = !(rayQueryGetIntersectionFrontFaceEXT(rayQuery, true)); //NOTE: not working on vegetation - - const uint id = hit.instanceId; - const uvec3 index = pullTrinagleIds(id,hit.primitiveId); - - const vec2 uv0 = pullTexcoord(id,index.x); - const vec2 uv1 = pullTexcoord(id,index.y); - const vec2 uv2 = pullTexcoord(id,index.z); - - const vec3 nr0 = pullNormal(id,index.x); - const vec3 nr1 = pullNormal(id,index.y); - const vec3 nr2 = pullNormal(id,index.z); - - const vec3 b = hit.baryCoord; - const vec2 uv = (b.x*uv0 + b.y*uv1 + b.z*uv2); - vec3 norm = (b.x*nr0 + b.y*nr1 + b.z*nr2); - - const mat3x3 matrix = mat3x3(rayQueryGetIntersectionObjectToWorldEXT(rayQuery, true)); - norm = normalize(matrix*norm); - - const float mip = mipOverride>=0 ? mipOverride : computeTextureLOD(rayT,rayDirection,norm); - const vec4 diff = textureLod(sampler2D(textures[nonuniformEXT(id)], smp),uv,mip); - - HitResolve ret; - ret.diff = diff; - ret.norm = norm; - ret.rayT = face ? -rayT : rayT; - ret.water = hit.water; - return ret; - } - -float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shadowed, float softAngle, inout uint rngState) { +float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shadowed, float softAngle, inout random rngState) { #if defined(SOFT_SHADOW) vec3 shRay = randomizeRay(rayDirection, 0.5*M_PI/180.0, rngState); #else @@ -287,11 +163,11 @@ float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shado vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection) { const int numBounces = 5; - uint rngState = srand(uvec2(gl_FragCoord.xy), scene.tickCount32); - vec3 thruput = vec3(1); - vec3 color = vec3(0); - bool underWater = (scene.underWater!=0); - float depth = 0; + random rngState = srand(uvec2(gl_FragCoord.xy), scene.tickCount32); + vec3 thruput = vec3(1); + vec3 color = vec3(0); + bool underWater = (scene.underWater!=0); + float depth = 0; for(int bounce=0;; ++bounce) { if(dot(thruput*scene.GSunIntensity*scene.exposure, vec3(0.2126, 0.7152, 0.0722)) < 0.01) @@ -299,10 +175,12 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection) { if(bounce>=numBounces) { // return 0.5*vec4(1,0,1,depth)*scene.GSunIntensity; +#if defined(RESCALE) // rescale to 100% thruput vec3 scale = 1.0-thruput; if(scale.r>0.01 && scale.g>0.01 && scale.b>0.01) return vec4(color/scale, depth); +#endif return vec4(color, depth); } @@ -343,7 +221,10 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection) { rayOrigin = (rayOrigin + rayDirection * hit.rayT); rayDirection = randCosWeightedHemisphereDirection(hit.norm, rngState); - thruput *= textureAlbedo(hit.diff.rgb); + vec3 albedo = textureAlbedo(hit.diff.rgb); + if(bounce>0) + albedo = min(albedo, 0.95); + thruput *= albedo; //thruput *= vec3(0.85); //snow //thruput *= vec3(0.04); // asphalt //if(bounce>0) @@ -388,7 +269,7 @@ vec2 halton(uint index) { } void main() { - const vec2 subpixel = (halton(srand(uvec2(gl_FragCoord.xy),frameId))-0.5) * scene.screenResInv; + const vec2 subpixel = (halton(srand(uvec2(gl_FragCoord.xy),frameId).state)-0.5) * scene.screenResInv; const mat4 inv = scene.viewProjectInv; const vec2 uv = inUV + subpixel; From f22630b41eedd6e882ca4c7c3f7b1bad0c6aa500 Mon Sep 17 00:00:00 2001 From: Try Date: Wed, 10 Jun 2026 01:19:25 +0200 Subject: [PATCH 21/52] refactor --- shader/lighting/pt/pathtrace.frag | 6 +++--- shader/lighting/pt/pathtrace_common.glsl | 6 +++--- shader/lighting/rt_dbg/hash_dbg.frag | 2 +- shader/lighting/surfels/surf_apply.comp | 6 +++++- shader/lighting/surfels/surf_common.glsl | 4 +++- shader/lighting/surfels/surf_dbg.frag | 2 +- shader/lighting/surfels/surf_pathtrace.comp | 16 +++++++++------- shader/lighting/surfels/surf_tiled.comp | 18 +++++++++++++++++- shader/random.glsl | 14 +++++++------- 9 files changed, 49 insertions(+), 25 deletions(-) diff --git a/shader/lighting/pt/pathtrace.frag b/shader/lighting/pt/pathtrace.frag index 2c4190260..ce0220662 100644 --- a/shader/lighting/pt/pathtrace.frag +++ b/shader/lighting/pt/pathtrace.frag @@ -63,7 +63,7 @@ float shadowFactor(vec3 pos) { } -vec3 randomizeRay(vec3 ray, float angle, inout random rngState) { +vec3 randomizeRay(vec3 ray, float angle, inout Random rngState) { // https://www.shadertoy.com/view/3sfBWs const vec2 blueNoiseInDisk[64] = vec2[64]( vec2(0.478712,0.875764), @@ -144,7 +144,7 @@ vec3 randomizeRay(vec3 ray, float angle, inout random rngState) { return vec3( r.x*uu + r.y*vv + r.z*ray ); } -float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shadowed, float softAngle, inout random rngState) { +float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shadowed, float softAngle, inout Random rngState) { #if defined(SOFT_SHADOW) vec3 shRay = randomizeRay(rayDirection, 0.5*M_PI/180.0, rngState); #else @@ -163,7 +163,7 @@ float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shado vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection) { const int numBounces = 5; - random rngState = srand(uvec2(gl_FragCoord.xy), scene.tickCount32); + Random rngState = srand(uvec2(gl_FragCoord.xy), scene.tickCount32); vec3 thruput = vec3(1); vec3 color = vec3(0); bool underWater = (scene.underWater!=0); diff --git a/shader/lighting/pt/pathtrace_common.glsl b/shader/lighting/pt/pathtrace_common.glsl index 55228d506..7a537a4bd 100644 --- a/shader/lighting/pt/pathtrace_common.glsl +++ b/shader/lighting/pt/pathtrace_common.glsl @@ -20,7 +20,7 @@ float rayPathTextureLOD(float dist, vec3 dir, vec3 norm) { return mip; } -void rayQueryProceedAlphaTest(in rayQueryEXT rayQuery, inout random rng) { +void rayQueryProceedAlphaTest(in rayQueryEXT rayQuery, inout Random rng) { while(rayQueryProceedEXT(rayQuery)) { const uint type = rayQueryGetIntersectionTypeEXT(rayQuery,false); if(type==gl_RayQueryCandidateIntersectionTriangleEXT) { @@ -33,7 +33,7 @@ void rayQueryProceedAlphaTest(in rayQueryEXT rayQuery, inout random rng) { } } -float rayQueryProceedShadow(const vec3 rayOrigin, const vec3 rayDirection, inout random rngState) { +float rayQueryProceedShadow(const vec3 rayOrigin, const vec3 rayDirection, inout Random rngState) { // CullBack due to vegetation uint flags = gl_RayFlagsSkipAABBEXT | gl_RayFlagsCullBackFacingTrianglesEXT; float tMin = 1; @@ -48,7 +48,7 @@ float rayQueryProceedShadow(const vec3 rayOrigin, const vec3 rayDirection, inout return 0; } -HitResolve rayQueryProceedPrimary(const vec3 rayOrigin, const vec3 rayDirection, float mipOverride, inout random rngState) { +HitResolve rayQueryProceedPrimary(const vec3 rayOrigin, const vec3 rayDirection, float mipOverride, inout Random rngState) { // CullBack due to vegetation uint flags = gl_RayFlagsSkipAABBEXT | gl_RayFlagsCullBackFacingTrianglesEXT; float tMin = 2; diff --git a/shader/lighting/rt_dbg/hash_dbg.frag b/shader/lighting/rt_dbg/hash_dbg.frag index 482f0d4d7..1d44e7e9d 100644 --- a/shader/lighting/rt_dbg/hash_dbg.frag +++ b/shader/lighting/rt_dbg/hash_dbg.frag @@ -68,7 +68,7 @@ void main(void) { // float sz = computeCellSize(lD, fov, textureSize(depth,0), 16, cellSize); // float sz = computeCellSize(lD, fov, textureSize(depth,0), 2, 1); - float sz = computeCellSize(lD, fov, textureSize(depth,0), SURFEL_CELL); + float sz = computeCellSize(lD, fov, textureSize(depth,0), 16); vec3 wpos = pos.xyz/pos.w + originLwc; ivec3 ipos = hasGridPos(wpos, sz); diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp index d0aac5864..c0be498be 100644 --- a/shader/lighting/surfels/surf_apply.comp +++ b/shader/lighting/surfels/surf_apply.comp @@ -24,7 +24,7 @@ layout(binding = 6, r32ui) uniform uimage2D surfCnts; layout(binding = 7, r32ui) uniform uimage2D surfBins; layout(binding = 8, r11f_g11f_b10f) uniform image2D irradiance; -const uint MaxSurfInCache = 128; +const uint MaxSurfInCache = 256; shared uint surfCount; shared vec4 surfelsPos [MaxSurfInCache]; shared vec4 surfelsNorm[MaxSurfInCache]; @@ -92,6 +92,10 @@ void main() { imageStore(irradiance, fragCoord, vec4(0)); return; } + if(surfCount >= MaxSurfInCache) { + imageStore(irradiance, fragCoord, vec4(1,1,0,0)); + return; + } const vec3 wpos = worldPos(z, fragCoord, screenSize); const vec3 norm = normalFetch(gbufNormal,fragCoord); diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 92983a6d6..a86cb3b10 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -104,10 +104,12 @@ float calculteWeight(const vec3 spos, const vec3 snorm, float radius, const vec3 dist = max(dist, 0.0001); float ePos = dist/radius; - float eNorm = sqrt(max(1 - 1*dotN, 0)) / sqrt(1.0 - cos(M_PI/3.0)); // Eq. 4 + float eNorm = sqrt(max(1 - 1*dotN, 0)) / sqrt(1.0 - cos(M_PI/6.0)); // Eq. 4 float w = 1.0 - max(ePos, eNorm); // Eq. 2 float eOccl = dot((ldir/dist), 0.5*(snorm+wnorm))*0.5+0.5; // allow small occlusion + //float eOccl = 1.0 - clamp(-dot(ldir, wnorm), 0, 1)*0.5; // allow small occlusion + //float eOccl = (dot(ldir, snorm) > 0.1*dist) ? 0.1 : 1; return w*eOccl; } diff --git a/shader/lighting/surfels/surf_dbg.frag b/shader/lighting/surfels/surf_dbg.frag index 027d34f04..0e4eb75b6 100644 --- a/shader/lighting/surfels/surf_dbg.frag +++ b/shader/lighting/surfels/surf_dbg.frag @@ -44,7 +44,7 @@ void main(void) { ;//discard; // vec3 clr = surfDebugColor(p, instanceIndex) * (1.0-qDist); - vec3 clr = p.irradiance * (1.0-qDist) * scene.exposure; + vec3 clr = 3.0 * p.irradiance * (1.0-qDist) * scene.exposure; outColor = vec4(clr,1.0); // outColor = vec4(1,0,0,1.0); } diff --git a/shader/lighting/surfels/surf_pathtrace.comp b/shader/lighting/surfels/surf_pathtrace.comp index f89053eb0..2a1338c1f 100644 --- a/shader/lighting/surfels/surf_pathtrace.comp +++ b/shader/lighting/surfels/surf_pathtrace.comp @@ -33,7 +33,7 @@ mat3 toTangent(vec3 norm) { return tangent; } -float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shadowed, float softAngle, inout random rngState) { +float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shadowed, float softAngle, inout Random rngState) { #if defined(SOFT_SHADOW) vec3 shRay = randomizeRay(rayDirection, 0.5*M_PI/180.0, rngState); #else @@ -49,7 +49,7 @@ float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shado return (lamb * shadow); } -vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout random rngState) { +vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout Random rngState) { const int numBounces = 5; vec3 thruput = vec3(1); @@ -141,12 +141,13 @@ void reduceIrr() { } void main() { - const uint numPaths = NumThreads; - const uint surfelId = gl_WorkGroupID.x; //gl_GlobalInvocationID.x; + const float eps = 0.001; + const uint numPaths = NumThreads; + const uint surfelId = gl_WorkGroupID.x; //gl_GlobalInvocationID.x; if(surfelId>=count.x) return; - random rngState = random(0); + Random rngState = Random(0); const Surfel p = surfels[surfelId]; const mat3 tbn = toTangent(decodeNormal(p.norm)); @@ -155,13 +156,14 @@ void main() { const vec3 ray = tbn * sampleHemisphereCos(i,numPaths,0).xzy; const vec4 pt = pathtrace(p.pos, ray, rngState); - reduction[i] = vec4(pt.rgb, 1.0/pt.a); + reduction[i] = vec4(pt.rgb, 1.0/max(pt.a, eps)); barrier(); reduceIrr(); if(gl_LocalInvocationIndex==0) { + // const float hitMean = float(numPaths)/max(reduction[0].a, eps); //harmonic mean + // surfels[surfelId].radius = min(surfels[surfelId].radius, hitMean); surfels[surfelId].irradiance = (reduction[0].rgb/float(numPaths)); - //float hHit = 1.0/max(reduction[0].a, 0.00001); //harmonic mean } } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index b24a27e6c..cab326e55 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -66,6 +66,11 @@ float calculteWeight(const Surf s, const vec3 wpos, const vec3 norm) { return calculteWeight(s.pos.xyz, s.norm, s.pos.w, wpos, norm); } +float seedNoise(vec3 wpos, float z, const ivec2 screenSize) { + uvec3 p = uvec3(wpos/32); + return (pcgHash(p.x + pcgHash(p.y + pcgHash(p.z)))/4294967296.0)*0.1;; + } + void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { const bool valid = all(lessThan(fragCoord, screenSize)); if(!valid) @@ -80,7 +85,8 @@ void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); const float edge = 0.2; - float wMax = 0; + uvec3 p = uvec3(wpos/10); + float wMax = seedNoise(wpos, z, screenSize)*0.1; for(int i=pointQueueSize; i>0;) { --i; const Surf s = pointQueue[i]; @@ -177,6 +183,16 @@ void main() { surfAlloc(ivec2(x,y), screenSize); barrier(); } +#if 0 + for(int y=coord0.y; y Date: Thu, 11 Jun 2026 02:01:46 +0200 Subject: [PATCH 22/52] surfel reuse initial --- game/graphics/renderer.cpp | 156 ++++++++++------------ game/graphics/renderer.h | 6 +- game/graphics/shaders.cpp | 1 + game/graphics/shaders.h | 2 +- shader/CMakeLists.txt | 1 + shader/lighting/rt_dbg/hash_dbg.frag | 22 +-- shader/lighting/surfels/surf_alloc.comp | 68 ++++++++++ shader/lighting/surfels/surf_apply.comp | 11 +- shader/lighting/surfels/surf_binning.comp | 45 +++++-- shader/lighting/surfels/surf_common.glsl | 24 +--- shader/lighting/surfels/surf_dbg.vert | 8 +- shader/lighting/surfels/surf_init.comp | 16 +-- shader/lighting/surfels/surf_tiled.comp | 156 ++++++++++++++++------ 13 files changed, 316 insertions(+), 200 deletions(-) create mode 100644 shader/lighting/surfels/surf_alloc.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 77304b1bc..302d9b801 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1951,36 +1951,46 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor return; const uint32_t maxSurfels = surf.maxSurfels; - static int32_t tileSize = 256; + static int32_t tileSize = 128; cmd.setDebugMarker("Surfels"); - auto& scene = wview.sceneGlobals(); - auto& surfels = usesSsboInit(surf.surfels, shaders.surfTiled.sizeofBuffer(4, surf.maxSurfels)); - auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); - auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::R11G11B10UF, zbuffer.size()); - auto& surfList = usesSsbo (surf.surfList, surf.maxSurfels*sizeof(uint32_t)); + auto& scene = wview.sceneGlobals(); + auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); + auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::R11G11B10UF, zbuffer.size()); - auto& surfBvh = usesSsbo (surf.surfBvh, shaders.surfBvh.sizeofBuffer(5, 2*surf.maxSurfels)); + auto& surfels = usesSsboInit(surf.surfels, shaders.surfTiled.sizeofBuffer(4, surf.maxSurfels)); + auto& surfList = usesSsbo (surf.surfList, 16*surf.maxSurfels*sizeof(uint32_t)); + auto& surfAlloc = usesSsbo (surf.surfAlloc, shaders.surfTiled.sizeofBuffer(8, surf.maxSurfels)); - auto tc = tileCount(zbuffer.size().toPoint()+IVec2(tileSize), tileSize); - auto& surfCnts = usesImage2d (surf.surfCnts, TextureFormat::R32U, tc); - auto& surfBins = usesImage2d (surf.surfBins, TextureFormat::R32U, tc); + auto binCount = tileCount(zbuffer.size().toPoint()+IVec2(tileSize), tileSize); + auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); + auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); - static bool alloc = true; - if(true && alloc) { - struct Push { - Vec3 originLwc; - uint32_t maxSurfels; - } push = {}; - push.originLwc = scene.originLwc; - push.maxSurfels = maxSurfels; + static bool binning = true; + if(binning) { + // prev-frame + binSurfels(cmd, wview, tileSize, false); + } + + struct Push { + Vec3 originLwc; + uint32_t tileSize; + } push = {}; + push.originLwc = scene.originLwc; + push.tileSize = uint32_t(tileSize); + static bool alloc = true; + if(alloc) { cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); cmd.setBinding(2, gbufNormal, Sampler::nearest()); cmd.setBinding(3, zbuffer, Sampler::nearest()); cmd.setBinding(4, surfels); + cmd.setBinding(5, surfList); + cmd.setBinding(6, surfCnts); + cmd.setBinding(7, surfBins); + cmd.setBinding(8, surfAlloc); // cmd.setBinding(11, dbgImage); @@ -1990,68 +2000,16 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor const auto tc = tileCount(zbuffer.size(), 128); cmd.setPipeline(shaders.surfTiled); cmd.dispatch(tc); - } - - static bool bvh = false; - if(bvh) { - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); - cmd.setBinding(4, surfels); - cmd.setBinding(5, surfBvh); - - cmd.setPipeline(shaders.surfBvh); - cmd.dispatch(1); - } - static bool traverse = false; - if(traverse) { - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); - cmd.setBinding(4, surfels); - cmd.setBinding(5, surfBvh); - // - cmd.setBinding(11, dbgImage); + cmd.setPipeline(shaders.surfAlloc); + cmd.dispatchThreads(maxSurfels); - cmd.setPipeline(shaders.surfBvhSample); - cmd.dispatchThreads(zbuffer.size()); + //alloc = false; } - static bool binning = true; if(binning) { - struct Push { - int32_t tileSize; - int32_t allocPass; - } push = {}; - push.tileSize = tileSize; - - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, surfels); - cmd.setBinding(2, surfCnts); - cmd.setBinding(3, surfBins); - cmd.setBinding(4, surfList); - cmd.setBinding(4, surfList); - - cmd.setPipeline(shaders.surfBinClear); - cmd.dispatchThreads(surfBins.size()); - - push.allocPass = 0; - cmd.setPushData(push); - cmd.setPipeline(shaders.surfBinning); - cmd.dispatchThreads(maxSurfels); - - cmd.setPipeline(shaders.surfBinAlloc); - cmd.dispatchThreads(surfBins.size()); - - push.allocPass = 1; - cmd.setPushData(push); - cmd.setPipeline(shaders.surfBinning); - cmd.dispatchThreads(maxSurfels); - //binning = false; + // current frame + binSurfels(cmd, wview, tileSize, false); } static bool rays = true; @@ -2074,13 +2032,6 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor static bool apply = true; if(apply) { - struct Push { - Vec3 originLwc; - int32_t tileSize; - } push = {}; - push.originLwc = scene.originLwc; - push.tileSize = tileSize; - cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); @@ -2097,6 +2048,47 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor } } +void Renderer::binSurfels(Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool clearOnly) { + const uint32_t maxSurfels = surf.maxSurfels; + + auto& scene = wview.sceneGlobals(); + auto& surfels = surf.surfels; + auto& surfCnts = surf.surfCnts; + auto& surfBins = surf.surfBins; + auto& surfList = surf.surfList; + + struct Push { + int32_t tileSize; + int32_t allocPass; + } push = {}; + push.tileSize = tileSize; + + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, surfels); + cmd.setBinding(2, surfCnts); + cmd.setBinding(3, surfBins); + cmd.setBinding(4, surfList); + + cmd.setPipeline(shaders.surfBinClear); + cmd.dispatchThreads(surfBins.size()); + if(clearOnly) + return; + + push.allocPass = 0; + cmd.setPushData(push); + cmd.setPipeline(shaders.surfBinning); + cmd.dispatchThreads(maxSurfels); + + cmd.setPipeline(shaders.surfBinAlloc); + cmd.dispatchThreads(surfBins.size()); + + push.allocPass = 1; + cmd.setPushData(push); + cmd.setPipeline(shaders.surfBinning); + cmd.dispatchThreads(maxSurfels); + } + void Renderer::prepareIrradiance(Encoder& cmd, WorldView& wview) { auto& scene = wview.sceneGlobals(); diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index ea3679788..3332bfe02 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -64,7 +64,9 @@ class Renderer final { void prepareGi (Tempest::Encoder& cmd, WorldView& wview); void prepareExposure (Tempest::Encoder& cmd, WorldView& wview); void prepareEpipolar (Tempest::Encoder& cmd, WorldView& wview); + void prepareSurfels (Tempest::Encoder& cmd, WorldView& wview); + void binSurfels (Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool clearOnly); void drawHiZ (Tempest::Encoder& cmd, WorldView& view); void buildHiZ (Tempest::Encoder& cmd); @@ -216,9 +218,7 @@ class Renderer final { Tempest::StorageImage irrImage; Tempest::StorageImage surfCnts, surfBins; - Tempest::StorageBuffer surfList; - - Tempest::StorageBuffer surfBvh; + Tempest::StorageBuffer surfList, surfAlloc; Tempest::StorageImage dbgImage; } surf; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 0072c4c6c..6cb271568 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -251,6 +251,7 @@ void Shaders::compileShaders() { surfInit = computeShader("surf_init.comp.sprv"); surfTiled = computeShader("surf_tiled.comp.sprv"); + surfAlloc = computeShader("surf_alloc.comp.sprv"); surfBinning = computeShader("surf_binning.comp.sprv"); surfBinClear = computeShader("surf_bin_clear.comp.sprv"); diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index e5531d0f1..ca7ad9ef9 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -86,7 +86,7 @@ class Shaders { // GI-Surf Tempest::RenderPipeline surfDbg; - Tempest::ComputePipeline surfInit, surfTiled; + Tempest::ComputePipeline surfInit, surfTiled, surfAlloc; Tempest::ComputePipeline surfBinClear, surfBinning, surfBinAlloc; Tempest::ComputePipeline surfApply; Tempest::ComputePipeline surfBvh, surfBvhSample; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 967a8b112..01075b9da 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -314,6 +314,7 @@ add_shader(surf_dbg.frag lighting/surfels/surf_dbg.frag) add_shader(surf_init.comp lighting/surfels/surf_init.comp) add_shader(surf_tiled.comp lighting/surfels/surf_tiled.comp) +add_shader(surf_alloc.comp lighting/surfels/surf_alloc.comp) add_shader(surf_binning.comp lighting/surfels/surf_binning.comp) add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) diff --git a/shader/lighting/rt_dbg/hash_dbg.frag b/shader/lighting/rt_dbg/hash_dbg.frag index 1d44e7e9d..18e6ea211 100644 --- a/shader/lighting/rt_dbg/hash_dbg.frag +++ b/shader/lighting/rt_dbg/hash_dbg.frag @@ -36,19 +36,9 @@ float surfDist(ivec3 hpos, vec3 pos, float cellSize) { return dot(p,p); //quad distance } -float surfDist(ivec3 hpos, vec3 pos, float cellSize, uint inorm, vec3 norm) { - vec3 p = (pos/cellSize - hpos); - p *= 2/sqrt(2.0); - float ed = length(p); //quad distance - - vec3 n = i_octahedral_8(inorm); - float en = sqrt(max(1.0 - dot(n,norm),0.0)); - return ed+en; - } - -uint surfHash(ivec3 hpos, uint inorm) { +uint surfHash(ivec3 hpos) { ivec3 p = hpos; - uint hashKey = pcgHash(pcgHash(p.x + pcgHash(p.y + pcgHash(p.z))) + inorm); + uint hashKey = pcgHash(p.x + pcgHash(p.y + pcgHash(p.z))); return hashKey; } @@ -68,14 +58,12 @@ void main(void) { // float sz = computeCellSize(lD, fov, textureSize(depth,0), 16, cellSize); // float sz = computeCellSize(lD, fov, textureSize(depth,0), 2, 1); - float sz = computeCellSize(lD, fov, textureSize(depth,0), 16); + float sz = computeCellSize(lD, fov, textureSize(depth,0), 64); vec3 wpos = pos.xyz/pos.w + originLwc; ivec3 ipos = hasGridPos(wpos, sz); - uint inorm = octahedral_8(norm); - - uint h = surfHash(ipos, inorm); - float dx = surfDist(ipos, wpos, sz, inorm, norm); + uint h = surfHash(ipos); + float dx = surfDist(ipos, wpos, sz); //uint sx = computeDepthSlice(lD, 10, 100000, 32); diff --git a/shader/lighting/surfels/surf_alloc.comp b/shader/lighting/surfels/surf_alloc.comp new file mode 100644 index 000000000..3c4a434da --- /dev/null +++ b/shader/lighting/surfels/surf_alloc.comp @@ -0,0 +1,68 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 64) in; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; } surf; +layout(binding = 8, std430) buffer SB2 { uvec4 count; SurfelAlloc req[]; } alloc; + +const int DefaultCoverage = 128; + +bool projectSphere(const vec4 sphere, out vec4 aabb, out float depthMin) { + const vec3 c = (scene.view * vec4(sphere.xyz, 1)).xyz; + const float R = sphere.w; + const float znear = 10; //push.znear; + + if(c.z - R < znear) { + depthMin = 0; + aabb = vec4(0,0,1,1); + return true; + } + + float z = c.z - R; + depthMin = scene.project[3][2]/z + scene.project[2][2]; + float P00 = scene.project[0][0]; + float P11 = scene.project[1][1]; + + vec3 cr = c * R; + float czr2 = c.z * c.z - R * R; + + float vx = sqrt(c.x * c.x + czr2); + float minx = (vx * c.x - cr.z) / (vx * c.z + cr.x); + float maxx = (vx * c.x + cr.z) / (vx * c.z - cr.x); + + float vy = sqrt(c.y * c.y + czr2); + float miny = (vy * c.y - cr.z) / (vy * c.z + cr.y); + float maxy = (vy * c.y + cr.z) / (vy * c.z - cr.y); + + aabb = vec4(minx * P00, miny * P11, maxx * P00, maxy * P11); + aabb = aabb*0.5 + vec4(0.5); + return true; + } + +void main() { + const uint allocId = gl_GlobalInvocationID.x; + if(allocId>=alloc.count.x) + return; + + const uint surfelId = atomicAdd(surf.count.x,1); + const SurfelAlloc p = alloc.req[surfelId]; + + Surfel sx; + sx.pos = p.pos.xyz; + sx.norm = encodeNormal(p.norm); + sx.radius = p.pos.w; + sx.radiusPix = DefaultCoverage; //TODO: calculate dynamically + sx.irradiance = surfDebugColor(p.pos.xyz, surfelId); + + surf.surfels[surfelId] = sx; + } diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp index c0be498be..82286f610 100644 --- a/shader/lighting/surfels/surf_apply.comp +++ b/shader/lighting/surfels/surf_apply.comp @@ -18,13 +18,13 @@ layout(binding = 0, std140) uniform UboScene { layout(binding = 1) uniform sampler2D gbufDiffuse; layout(binding = 2) uniform usampler2D gbufNormal; layout(binding = 3) uniform sampler2D depth; -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 5, std430) buffer SB1 { uint surfelList[]; }; +layout(binding = 4, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5, std430) readonly buffer SB1 { uint surfelList[]; }; layout(binding = 6, r32ui) uniform uimage2D surfCnts; layout(binding = 7, r32ui) uniform uimage2D surfBins; layout(binding = 8, r11f_g11f_b10f) uniform image2D irradiance; -const uint MaxSurfInCache = 256; +const uint MaxSurfInCache = 256; //FIXME: iterate whole tile shared uint surfCount; shared vec4 surfelsPos [MaxSurfInCache]; shared vec4 surfelsNorm[MaxSurfInCache]; @@ -78,10 +78,7 @@ void main() { const bool sky = (z >= SKY_DEPTH); ivec2 t = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy)/int(tileSize); - pullTile(t+ivec2(0,0)); - pullTile(t+ivec2(1,0)); - pullTile(t+ivec2(0,1)); - pullTile(t+ivec2(1,1)); + pullTile(t); barrier(); if(gl_LocalInvocationIndex==0) diff --git a/shader/lighting/surfels/surf_binning.comp b/shader/lighting/surfels/surf_binning.comp index d29eb0b80..006f325f8 100644 --- a/shader/lighting/surfels/surf_binning.comp +++ b/shader/lighting/surfels/surf_binning.comp @@ -14,24 +14,49 @@ layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; layout(binding = 1, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 2, r32ui) uniform uimage2D surfCnts; -layout(binding = 3, r32ui) uniform uimage2D surfBins; +layout(binding = 2, r32ui) uniform uimage2D surfCnts; +layout(binding = 3, r32ui) uniform readonly uimage2D surfBins; layout(binding = 4, std430) buffer SB1 { uint surfelIds[]; }; +float pixelToWorld(float pixelRadius, float z) { + z = linearDepth(z, scene.clipInfo); + + float clipRadiusX = (2.0 * pixelRadius) * scene.screenResInv.x; + float clipRadiusY = (2.0 * pixelRadius) * scene.screenResInv.y; + + float worldRadiusX = (clipRadiusX * z) / scene.project[0][0]; + float worldRadiusY = (clipRadiusY * z) / scene.project[1][1]; + return min(worldRadiusX, worldRadiusY); + } + void main() { const uint surfelId = gl_GlobalInvocationID.x; if(surfelId>=count.x) return; - const Surfel p = surfels[surfelId]; - const ivec2 ipos = p.fragCoord; + const Surfel p = surfels[surfelId]; + const vec4 pos4 = scene.viewProject * vec4(p.pos, 1.0); + const vec2 posNdc = ((pos4.xy/pos4.w)*0.5+0.5); + const ivec2 fragCoord = ivec2(posNdc*scene.screenRes + 0.5); + + surfels[surfelId].fragCoord = fragCoord; + + ivec2 pos0 = ivec2(fragCoord-p.radiusPix)/tileSize; + ivec2 pos1 = ivec2(fragCoord+p.radiusPix)/tileSize + 1; ivec2 sz = imageSize(surfCnts); - ivec2 tile = clamp((ipos+tileSize/2)/tileSize, ivec2(0), sz); + pos0 = max(ivec2(0), pos0); + pos1 = min(sz, pos1); - const uint lptr = imageAtomicAdd(surfCnts, tile, 1); - if(allocPass>0) { - const uint ptr = imageLoad(surfBins, tile).x + lptr; - surfelIds[ptr] = surfelId; - } + for(int y=pos0.y; y=surfelIds.length()) + return; // error! + surfelIds[ptr] = surfelId; + } } diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index a86cb3b10..2d88380c3 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -3,9 +3,7 @@ #include "common.glsl" -const float SKY_DEPTH = 0.999995; -//const float SURFEL_FOOTPRINT = 64; -const float SURFEL_CELL = 64;//SURFEL_FOOTPRINT/sqrt(2); +const float SKY_DEPTH = 0.999995; struct Surfel { vec3 pos; @@ -17,21 +15,11 @@ struct Surfel { uint padd0; }; -uint octahedral_8(in vec3 nor) { - nor.xy /= ( abs( nor.x ) + abs( nor.y ) + abs( nor.z ) ); - nor.xy = (nor.z >= 0.0) ? nor.xy : (1.0-abs(nor.yx))*msign(nor.xy); - uvec2 d = uvec2(round(7.5 + nor.xy*7.5)); - return d.x|(d.y<<4u); - } - -vec3 i_octahedral_8( uint data ) { - uvec2 iv = uvec2( data, data>>4u ) & 15u; vec2 v = vec2(iv)/7.5 - 1.0; - vec3 nor = vec3(v, 1.0 - abs(v.x) - abs(v.y)); // Rune Stubbe's version, - float t = max(-nor.z,0.0); // much faster than original - nor.x += (nor.x>0.0)?-t:t; // implementation of this - nor.y += (nor.y>0.0)?-t:t; // technique - return normalize( nor ); - } +struct SurfelAlloc { + vec4 pos; // pos, size + vec3 norm; + uint padd0; + }; float computeTargetCellSize(float d, float aperture, vec2 resolution, float pixelFeatureSize) { // Equation 2: Evaluate the angular factor based on resolution aspect ratio diff --git a/shader/lighting/surfels/surf_dbg.vert b/shader/lighting/surfels/surf_dbg.vert index d0842a004..81f0c72ea 100644 --- a/shader/lighting/surfels/surf_dbg.vert +++ b/shader/lighting/surfels/surf_dbg.vert @@ -61,8 +61,6 @@ void main() { const vec4 pp = scene.viewProject * vec4(p.pos, 1.0); float pixelRadius = 5.0; - // float clipRadius = (2.0 * pixelRadius) * scene.screenResInv.y; - // float worldRadius = clipRadius * (-pp.z) / scene.project[1][1]; float worldRadius = pixelToWorld(pixelRadius, pp.z/pp.w); //radius = 5; @@ -74,9 +72,5 @@ void main() { const float fov = 67.5f*M_PI/180.0; const float ld = max(linearDepth(pp.z/pp.w, scene.clipInfo), 10); - const float sz = computeCellSize(ld, fov, textureSize(depth,0), SURFEL_CELL); - const vec3 wpos = p.pos; - const vec3 ipos = hasGridPos(wpos, sz); - const uint inorm = octahedral_8(normal); - instanceIndex = surfelId; //surfHash(ipos, sz, inorm); + instanceIndex = surfelId; } diff --git a/shader/lighting/surfels/surf_init.comp b/shader/lighting/surfels/surf_init.comp index 74ecc6fe1..20b7319ee 100644 --- a/shader/lighting/surfels/surf_init.comp +++ b/shader/lighting/surfels/surf_init.comp @@ -1,17 +1,11 @@ #version 450 -layout(local_size_x = 64) in; +layout(local_size_x = 1) in; -layout(binding = 4, std430) buffer SB0 { uvec4 count; }; -//layout(binding = 5, std430) buffer SB1 { uint hashGrid[]; }; +layout(binding = 4, std430) buffer SB0 { uvec4 count; } surf; +layout(binding = 8, std430) buffer SB2 { uvec4 count; } alloc; void main() { - if(gl_GlobalInvocationID.xy==ivec2(0)) - count = uvec4(0,1,1,0); -/* - const uint hKey = gl_GlobalInvocationID.x; - if(hKey >= hashGrid.length()) - return; - hashGrid[hKey] = 0xFFFFFFFF; - */ + surf. count = uvec4(0,1,1,0); + alloc.count = uvec4(0,1,1,0); } diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index cab326e55..c87317562 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -6,6 +6,8 @@ layout(local_size_x = 16, local_size_y = 16) in; +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + const ivec2 TileSize = ivec2(128); const int DefaultCoverage = 128; const float NormalBias = 0.0030; @@ -17,25 +19,23 @@ layout(std140, push_constant) uniform Push { layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; - layout(binding = 1) uniform sampler2D gbufDiffuse; layout(binding = 2) uniform usampler2D gbufNormal; layout(binding = 3) uniform sampler2D depth; -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; } glob; - +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; } glob; +layout(binding = 5, std430) readonly buffer SB1 { uint surfelList[]; }; +layout(binding = 6, r32ui) uniform uimage2D surfCnts; +layout(binding = 7, r32ui) uniform uimage2D surfBins; +layout(binding = 8, std430) buffer SB2 { uvec4 count; SurfelAlloc req[]; } alloc; // layout(binding = 11, rgba8) uniform image2D dbgImage; -// -struct Surf { - vec4 pos; // pos, size - vec3 norm; - ivec2 fragCoord; //TODO: remove - }; -shared Surf pointQueue[64]; -shared int pointQueueSize; +shared SurfelAlloc prevQueue [64]; +shared SurfelAlloc pointQueue[64]; +shared int pointQueueSize; +shared int prevQueueSize; -shared uint fragVote; +shared uint fragVote, reuseVote; vec3 rayOrigin(ivec2 frag, float depth, vec3 normal) { const vec2 fragCoord = ((frag.xy+0.5)*scene.screenResInv)*2.0 - vec2(1.0); @@ -62,13 +62,13 @@ float pixelToWorld(float pixelRadius, float z) { return min(worldRadiusX, worldRadiusY); } -float calculteWeight(const Surf s, const vec3 wpos, const vec3 norm) { +float calculteWeight(const SurfelAlloc s, const vec3 wpos, const vec3 norm) { return calculteWeight(s.pos.xyz, s.norm, s.pos.w, wpos, norm); } float seedNoise(vec3 wpos, float z, const ivec2 screenSize) { uvec3 p = uvec3(wpos/32); - return (pcgHash(p.x + pcgHash(p.y + pcgHash(p.z)))/4294967296.0)*0.1;; + return (pcgHash(p.x + pcgHash(p.y + pcgHash(p.z)))/4294967296.0)*0.1; } void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { @@ -89,8 +89,8 @@ void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { float wMax = seedNoise(wpos, z, screenSize)*0.1; for(int i=pointQueueSize; i>0;) { --i; - const Surf s = pointQueue[i]; - const float w = calculteWeight(s,wpos,norm); + const SurfelAlloc s = pointQueue[i]; + const float w = calculteWeight(s,wpos,norm); // w = max(w,0); wMax = max(wMax,w); if(wMax > edge) @@ -107,6 +107,52 @@ void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { atomicMin(fragVote, b); } +void reuseSurfel(ivec2 fragCoord, const ivec2 screenSize) { + const uint laneID = gl_LocalInvocationIndex; + + const uint vote = fragVote; + //reuseVote = 0x0000FFFF; + barrier(); + + if((vote & 0xFFFF0000)==0xFFFF0000) + return; + + const uint id = (vote & 0xFFFF) ^ Salt; + fragCoord.x += int(id % gl_WorkGroupSize.x); + fragCoord.y += int(id / gl_WorkGroupSize.x); + + const float z = texelFetch(depth, fragCoord, 0).x; + const vec3 norm = normalFetch(gbufNormal, fragCoord); + const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); + + if(laneID0.1) { + uint w = floatBitsToUint(wsurf) & 0xFFFF0000; + uint b = uint(w) | uint(laneID); + atomicMax(reuseVote, b); + } + } + barrier(); + + if(laneID!=0) + return; + + const uint reuseId = reuseVote & 0x0000FFFF; + if(reuseId==0x0000FFFF || pointQueueSize>=pointQueue.length()) + return; + + fragVote = 0xFFFFFFFF; + reuseVote = 0x0000FFFF; + + pointQueue[pointQueueSize] = prevQueue[reuseId]; + pointQueue[pointQueueSize].padd0 = id; + pointQueueSize++; + + prevQueue[reuseId] = prevQueue[prevQueueSize-1]; + prevQueueSize--; + } + void surfAlloc(ivec2 fragCoord, const ivec2 screenSize) { if(gl_LocalInvocationIndex!=0) return; @@ -118,12 +164,9 @@ void surfAlloc(ivec2 fragCoord, const ivec2 screenSize) { const uint vote = fragVote; fragVote = 0xFFFFFFFF; - if((vote & 0x0000FFFF)==0x0000FFFF) + if((vote & 0xFFFF0000)==0xFFFF0000) return; - const int i = pointQueueSize; - pointQueueSize++; - const uint id = (vote & 0xFFFF) ^ Salt; fragCoord.x += int(id % gl_WorkGroupSize.x); fragCoord.y += int(id / gl_WorkGroupSize.x); @@ -133,32 +176,56 @@ void surfAlloc(ivec2 fragCoord, const ivec2 screenSize) { const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); const float sz = max(pixelToWorld(DefaultCoverage, z), 0); - Surf s; - s.pos = vec4(wpos, sz); - s.norm = norm; - s.fragCoord = fragCoord; - pointQueue[i] = s; + SurfelAlloc s; + s.pos = vec4(wpos, sz); + s.norm = norm; + pointQueue[pointQueueSize] = s; + pointQueueSize++; } void storeSurfels() { const uint laneID = gl_LocalInvocationIndex; - if(laneID==0) - fragVote = atomicAdd(glob.count.x, pointQueueSize); + if(laneID==0) { + pointQueueSize = min(pointQueueSize, pointQueue.length()); + fragVote = atomicAdd(alloc.count.x, pointQueueSize); + } barrier(); if(laneID=prevQueue.length()) + return; + + SurfelAlloc s; + s.pos = vec4(sx.pos, sx.radius); + s.norm = decodeNormal(sx.norm); + prevQueue[id] = s; } } @@ -167,7 +234,13 @@ void main() { ;//return; pointQueueSize = 0; + prevQueueSize = 0; fragVote = 0xFFFFFFFF; + reuseVote = 0x0000FFFF; + barrier(); + + const ivec2 tileId = ivec2(gl_WorkGroupID.xy*TileSize)/int(TileSize); + loadTile(tileId); barrier(); const ivec2 screenSize = ivec2(textureSize(depth,0)); @@ -175,18 +248,13 @@ void main() { const ivec2 coord0 = ivec2(gl_WorkGroupID.xy) * TileSize; const ivec2 coord1 = ivec2(gl_WorkGroupID.xy) * TileSize + TileSize; +#if 1 for(int y=coord0.y; y Date: Fri, 12 Jun 2026 01:09:55 +0200 Subject: [PATCH 23/52] surfel reuse initial --- game/graphics/renderer.cpp | 13 +++--- game/graphics/renderer.h | 2 +- shader/lighting/surfels/surf_alloc.comp | 49 +++++---------------- shader/lighting/surfels/surf_binning.comp | 5 +++ shader/lighting/surfels/surf_common.glsl | 5 ++- shader/lighting/surfels/surf_init.comp | 12 +++-- shader/lighting/surfels/surf_pathtrace.comp | 2 + shader/lighting/surfels/surf_tiled.comp | 49 ++++++++++----------- 8 files changed, 63 insertions(+), 74 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 302d9b801..35175df17 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1951,6 +1951,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor return; const uint32_t maxSurfels = surf.maxSurfels; + const uint32_t maxAlloc = surf.maxSurfels * 16; static int32_t tileSize = 128; cmd.setDebugMarker("Surfels"); @@ -1958,9 +1959,10 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::R11G11B10UF, zbuffer.size()); - auto& surfels = usesSsboInit(surf.surfels, shaders.surfTiled.sizeofBuffer(4, surf.maxSurfels)); - auto& surfList = usesSsbo (surf.surfList, 16*surf.maxSurfels*sizeof(uint32_t)); - auto& surfAlloc = usesSsbo (surf.surfAlloc, shaders.surfTiled.sizeofBuffer(8, surf.maxSurfels)); + auto& surfels = usesSsboInit(surf.surfels, shaders.surfTiled.sizeofBuffer(4, maxSurfels)); + auto& surfList = usesSsbo (surf.surfList, 16*maxSurfels*sizeof(uint32_t)); + auto& surfAlloc = usesSsbo (surf.surfAlloc, shaders.surfTiled.sizeofBuffer(8, maxAlloc)); + auto& surfDedup = usesSsboInit(surf.surfDedup, (maxSurfels+32-1)/32); auto binCount = tileCount(zbuffer.size().toPoint()+IVec2(tileSize), tileSize); auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); @@ -1991,18 +1993,19 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setBinding(6, surfCnts); cmd.setBinding(7, surfBins); cmd.setBinding(8, surfAlloc); + cmd.setBinding(9, surfDedup); // cmd.setBinding(11, dbgImage); cmd.setPipeline(shaders.surfInit); - cmd.dispatchThreads(1); //for sake of zeroing counters + cmd.dispatchThreads(surfDedup.byteSize()/sizeof(uint32_t)); //for sake of zeroing counters const auto tc = tileCount(zbuffer.size(), 128); cmd.setPipeline(shaders.surfTiled); cmd.dispatch(tc); cmd.setPipeline(shaders.surfAlloc); - cmd.dispatchThreads(maxSurfels); + cmd.dispatchThreads(maxAlloc); //alloc = false; } diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index 3332bfe02..910ca8bf9 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -218,7 +218,7 @@ class Renderer final { Tempest::StorageImage irrImage; Tempest::StorageImage surfCnts, surfBins; - Tempest::StorageBuffer surfList, surfAlloc; + Tempest::StorageBuffer surfList, surfAlloc, surfDedup; Tempest::StorageImage dbgImage; } surf; diff --git a/shader/lighting/surfels/surf_alloc.comp b/shader/lighting/surfels/surf_alloc.comp index 3c4a434da..4b1361bc7 100644 --- a/shader/lighting/surfels/surf_alloc.comp +++ b/shader/lighting/surfels/surf_alloc.comp @@ -14,48 +14,23 @@ layout(binding = 0, std140) uniform UboScene { }; layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; } surf; layout(binding = 8, std430) buffer SB2 { uvec4 count; SurfelAlloc req[]; } alloc; - -const int DefaultCoverage = 128; - -bool projectSphere(const vec4 sphere, out vec4 aabb, out float depthMin) { - const vec3 c = (scene.view * vec4(sphere.xyz, 1)).xyz; - const float R = sphere.w; - const float znear = 10; //push.znear; - - if(c.z - R < znear) { - depthMin = 0; - aabb = vec4(0,0,1,1); - return true; - } - - float z = c.z - R; - depthMin = scene.project[3][2]/z + scene.project[2][2]; - float P00 = scene.project[0][0]; - float P11 = scene.project[1][1]; - - vec3 cr = c * R; - float czr2 = c.z * c.z - R * R; - - float vx = sqrt(c.x * c.x + czr2); - float minx = (vx * c.x - cr.z) / (vx * c.z + cr.x); - float maxx = (vx * c.x + cr.z) / (vx * c.z - cr.x); - - float vy = sqrt(c.y * c.y + czr2); - float miny = (vy * c.y - cr.z) / (vy * c.z + cr.y); - float maxy = (vy * c.y + cr.z) / (vy * c.z - cr.y); - - aabb = vec4(minx * P00, miny * P11, maxx * P00, maxy * P11); - aabb = aabb*0.5 + vec4(0.5); - return true; - } +layout(binding = 9, std430) buffer SB3 { uint deduplication[]; }; void main() { const uint allocId = gl_GlobalInvocationID.x; - if(allocId>=alloc.count.x) + if(allocId>=alloc.count.x || allocId>=alloc.req.length()) return; - const uint surfelId = atomicAdd(surf.count.x,1); - const SurfelAlloc p = alloc.req[surfelId]; + const SurfelAlloc p = alloc.req[allocId]; + + if(p.reuseId!=0xFFFFFFFF) { + const uint bit = (1u << (p.reuseId % 32)); + const uint prev = atomicOr(deduplication[p.reuseId/32], bit); + if((bit & prev)!=0) + return; + } + + const uint surfelId = atomicAdd(surf.count.x,1); Surfel sx; sx.pos = p.pos.xyz; diff --git a/shader/lighting/surfels/surf_binning.comp b/shader/lighting/surfels/surf_binning.comp index 006f325f8..c2424a3ae 100644 --- a/shader/lighting/surfels/surf_binning.comp +++ b/shader/lighting/surfels/surf_binning.comp @@ -29,6 +29,10 @@ float pixelToWorld(float pixelRadius, float z) { return min(worldRadiusX, worldRadiusY); } +float renewRadius(const Surfel p, float z) { + return max(pixelToWorld(DefaultCoverage, z), 0); + } + void main() { const uint surfelId = gl_GlobalInvocationID.x; if(surfelId>=count.x) @@ -40,6 +44,7 @@ void main() { const ivec2 fragCoord = ivec2(posNdc*scene.screenRes + 0.5); surfels[surfelId].fragCoord = fragCoord; + surfels[surfelId].radius = renewRadius(p, pos4.z/pos4.w); ivec2 pos0 = ivec2(fragCoord-p.radiusPix)/tileSize; ivec2 pos1 = ivec2(fragCoord+p.radiusPix)/tileSize + 1; diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 2d88380c3..89919a893 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -3,7 +3,8 @@ #include "common.glsl" -const float SKY_DEPTH = 0.999995; +const float SKY_DEPTH = 0.999995; +const int DefaultCoverage = 128; // in pixels struct Surfel { vec3 pos; @@ -18,7 +19,7 @@ struct Surfel { struct SurfelAlloc { vec4 pos; // pos, size vec3 norm; - uint padd0; + uint reuseId; }; float computeTargetCellSize(float d, float aperture, vec2 resolution, float pixelFeatureSize) { diff --git a/shader/lighting/surfels/surf_init.comp b/shader/lighting/surfels/surf_init.comp index 20b7319ee..40a2aecd4 100644 --- a/shader/lighting/surfels/surf_init.comp +++ b/shader/lighting/surfels/surf_init.comp @@ -1,11 +1,17 @@ #version 450 -layout(local_size_x = 1) in; +layout(local_size_x = 64) in; layout(binding = 4, std430) buffer SB0 { uvec4 count; } surf; layout(binding = 8, std430) buffer SB2 { uvec4 count; } alloc; +layout(binding = 9, std430) buffer SB3 { uint deduplication[]; }; void main() { - surf. count = uvec4(0,1,1,0); - alloc.count = uvec4(0,1,1,0); + if(gl_GlobalInvocationID.x==0) { + surf. count = uvec4(0,1,1,0); + alloc.count = uvec4(0,1,1,0); + } + + if(gl_GlobalInvocationID.x < deduplication.length()) + deduplication[gl_GlobalInvocationID.x] = 0; } diff --git a/shader/lighting/surfels/surf_pathtrace.comp b/shader/lighting/surfels/surf_pathtrace.comp index 2a1338c1f..a14967d80 100644 --- a/shader/lighting/surfels/surf_pathtrace.comp +++ b/shader/lighting/surfels/surf_pathtrace.comp @@ -147,6 +147,7 @@ void main() { if(surfelId>=count.x) return; + // uint hashKey = pcgHash(inorm Random rngState = Random(0); const Surfel p = surfels[surfelId]; @@ -154,6 +155,7 @@ void main() { const uint i = gl_LocalInvocationIndex; const vec3 ray = tbn * sampleHemisphereCos(i,numPaths,0).xzy; + // const vec3 ray = randCosWeightedHemisphereDirection(decodeNormal(p.norm), rngState); const vec4 pt = pathtrace(p.pos, ray, rngState); reduction[i] = vec4(pt.rgb, 1.0/max(pt.a, eps)); diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index c87317562..61ed037be 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -8,10 +8,9 @@ layout(local_size_x = 16, local_size_y = 16) in; const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; -const ivec2 TileSize = ivec2(128); -const int DefaultCoverage = 128; -const float NormalBias = 0.0030; -const uint Salt = 0x9D; +const ivec2 TileSize = ivec2(128); +const float NormalBias = 0.0030; +const uint Salt = 0x9D; layout(std140, push_constant) uniform Push { vec3 originLwc; @@ -30,7 +29,7 @@ layout(binding = 8, std430) buffer SB2 { uvec4 count; SurfelAlloc req[] // layout(binding = 11, rgba8) uniform image2D dbgImage; -shared SurfelAlloc prevQueue [64]; +shared SurfelAlloc prevQueue [256]; shared SurfelAlloc pointQueue[64]; shared int pointQueueSize; shared int prevQueueSize; @@ -146,7 +145,6 @@ void reuseSurfel(ivec2 fragCoord, const ivec2 screenSize) { reuseVote = 0x0000FFFF; pointQueue[pointQueueSize] = prevQueue[reuseId]; - pointQueue[pointQueueSize].padd0 = id; pointQueueSize++; prevQueue[reuseId] = prevQueue[prevQueueSize-1]; @@ -177,8 +175,9 @@ void surfAlloc(ivec2 fragCoord, const ivec2 screenSize) { const float sz = max(pixelToWorld(DefaultCoverage, z), 0); SurfelAlloc s; - s.pos = vec4(wpos, sz); - s.norm = norm; + s.pos = vec4(wpos, sz); + s.norm = norm; + s.reuseId = 0xFFFFFFFF; pointQueue[pointQueueSize] = s; pointQueueSize++; } @@ -194,7 +193,8 @@ void storeSurfels() { if(laneID=prevQueue.length()) - return; + for(uint i=laneID; i Date: Fri, 12 Jun 2026 02:06:15 +0200 Subject: [PATCH 24/52] improve apply pass --- shader/lighting/surfels/surf_apply.comp | 109 +++++++++--------------- 1 file changed, 42 insertions(+), 67 deletions(-) diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp index 82286f610..19b34eb48 100644 --- a/shader/lighting/surfels/surf_apply.comp +++ b/shader/lighting/surfels/surf_apply.comp @@ -24,11 +24,9 @@ layout(binding = 6, r32ui) uniform uimage2D surfCnts; layout(binding = 7, r32ui) uniform uimage2D surfBins; layout(binding = 8, r11f_g11f_b10f) uniform image2D irradiance; -const uint MaxSurfInCache = 256; //FIXME: iterate whole tile -shared uint surfCount; -shared vec4 surfelsPos [MaxSurfInCache]; -shared vec4 surfelsNorm[MaxSurfInCache]; -shared vec4 surfelsIrr [MaxSurfInCache]; +shared vec4 surfelsPos [NumThreads]; +shared vec4 surfelsNorm[NumThreads]; +shared vec4 surfelsIrr [NumThreads]; vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { const mat4 inv = scene.viewProjectLwcInv; @@ -37,83 +35,60 @@ vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { return pos.xyz/pos.w + originLwc; } -void pullTile(ivec2 tileId) { - const uint laneID = gl_LocalInvocationIndex; - - const uint cnt = imageLoad(surfCnts, tileId).x; - const uint ptr = imageLoad(surfBins, tileId).x; - - ivec2 bboxMin = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy); - ivec2 bboxMax = bboxMin + ivec2(gl_WorkGroupSize.xy); - - for(uint i=laneID; i=MaxSurfInCache) - return; - surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); - surfelsNorm[id] = vec4(decodeNormal(s.norm), s.radius); - surfelsIrr [id] = vec4(s.irradiance, 0); + clr += vec4(color*w, w); } } void main() { - surfCount = 0; - barrier(); + const uint laneID = gl_LocalInvocationIndex; const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); const ivec2 screenSize = ivec2(textureSize(depth,0)); const bool valid = all(lessThan(fragCoord, screenSize)); - const float z = valid ? texelFetch(depth,fragCoord,0).x : 0; - const bool sky = (z >= SKY_DEPTH); - - ivec2 t = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy)/int(tileSize); - pullTile(t); - barrier(); - - if(gl_LocalInvocationIndex==0) - surfCount = min(surfCount, MaxSurfInCache); - barrier(); - - if(!valid || sky) { - imageStore(irradiance, fragCoord, vec4(0)); - return; + const ivec2 tileId = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy)/int(tileSize); + const uint cnt = imageLoad(surfCnts, tileId).x; + const uint ptr = imageLoad(surfBins, tileId).x; + + const float z = valid ? texelFetch(depth,fragCoord,0).x : 1; + const vec3 wpos = worldPos(z, fragCoord, screenSize); + const vec3 norm = normalFetch(gbufNormal, fragCoord); + const bool sky = (z >= SKY_DEPTH); + + vec4 clr = vec4(0); + for(uint i=0; ; i+=NumThreads) { + if(i+laneID < cnt) { + const uint sId = surfelList[ptr+i+laneID]; + const Surfel s = surfels[sId]; + + surfelsPos [laneID] = vec4(s.pos, uintBitsToFloat(sId)); + surfelsNorm[laneID] = vec4(decodeNormal(s.norm), s.radius); + surfelsIrr [laneID] = vec4(s.irradiance, 0); + } + barrier(); + + if(!sky) { + const uint surfCount = min(cnt-i, NumThreads); + applyBatch(clr, wpos, norm, surfCount); + } + + if(i+NumThreads>=cnt) + break; + barrier(); } - if(surfCount >= MaxSurfInCache) { - imageStore(irradiance, fragCoord, vec4(1,1,0,0)); - return; - } - - const vec3 wpos = worldPos(z, fragCoord, screenSize); - const vec3 norm = normalFetch(gbufNormal,fragCoord); - vec4 clr = vec4(0); - float maxW = 0; - for(int i=0; imaxW) - maxW = w; - if(w <= 0) - continue; - clr += vec4(color*w, w); - } + if(!valid || sky) + return; if(clr.a>0) clr.rgb /= clr.a; clr.rgb *= scene.exposure; - // imageStore(dbgImage, fragCoord, vec4(surfCount/255.0)); - // imageStore(dbgImage, fragCoord, vec4(maxW)); - imageStore(irradiance, fragCoord, vec4(clr.rgb, surfCount/100.0)); + imageStore(irradiance, fragCoord, vec4(clr.rgb, clr.a)); } From a4bd10211505368bb53b53e8f9ea650ea63780e0 Mon Sep 17 00:00:00 2001 From: Try Date: Fri, 12 Jun 2026 18:28:28 +0200 Subject: [PATCH 25/52] optimization --- shader/lighting/surfels/surf_apply.comp | 19 ++++++++++++++----- shader/lighting/surfels/surf_common.glsl | 11 +++++++++++ shader/lighting/surfels/surf_tiled.comp | 14 +++++++------- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp index 19b34eb48..a621d6daa 100644 --- a/shader/lighting/surfels/surf_apply.comp +++ b/shader/lighting/surfels/surf_apply.comp @@ -27,6 +27,7 @@ layout(binding = 8, r11f_g11f_b10f) uniform image2D irradiance; shared vec4 surfelsPos [NumThreads]; shared vec4 surfelsNorm[NumThreads]; shared vec4 surfelsIrr [NumThreads]; +shared uint surfelCount; vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { const mat4 inv = scene.viewProjectLwcInv; @@ -61,21 +62,29 @@ void main() { const vec3 norm = normalFetch(gbufNormal, fragCoord); const bool sky = (z >= SKY_DEPTH); + ivec2 bboxMin = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy); + ivec2 bboxMax = bboxMin + ivec2(gl_WorkGroupSize.xy); + vec4 clr = vec4(0); for(uint i=0; ; i+=NumThreads) { + surfelCount = 0; + barrier(); + if(i+laneID < cnt) { const uint sId = surfelList[ptr+i+laneID]; const Surfel s = surfels[sId]; - surfelsPos [laneID] = vec4(s.pos, uintBitsToFloat(sId)); - surfelsNorm[laneID] = vec4(decodeNormal(s.norm), s.radius); - surfelsIrr [laneID] = vec4(s.irradiance, 0); + if(isSurfelVisible(s, bboxMin, bboxMax)) { + const uint id = atomicAdd(surfelCount, 1); + surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); + surfelsNorm[id] = vec4(decodeNormal(s.norm), s.radius); + surfelsIrr [id] = vec4(s.irradiance, 0); + } } barrier(); if(!sky) { - const uint surfCount = min(cnt-i, NumThreads); - applyBatch(clr, wpos, norm, surfCount); + applyBatch(clr, wpos, norm, surfelCount); } if(i+NumThreads>=cnt) diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 89919a893..668534d3f 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -22,6 +22,17 @@ struct SurfelAlloc { uint reuseId; }; +bool isSurfelVisible(const Surfel s, ivec2 bboxMin, ivec2 bboxMax) { + const ivec2 at = s.fragCoord; + const int radius = s.radiusPix; + + if(bboxMax.x < at.x-radius || bboxMax.y < at.y-radius) + return false; + if(at.x+radius < bboxMin.x || at.y+radius < bboxMin.y) + return false; + return true; + } + float computeTargetCellSize(float d, float aperture, vec2 resolution, float pixelFeatureSize) { // Equation 2: Evaluate the angular factor based on resolution aspect ratio float term1 = aperture / resolution.x; diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index 61ed037be..d860ca4b6 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -11,6 +11,7 @@ const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z const ivec2 TileSize = ivec2(128); const float NormalBias = 0.0030; const uint Salt = 0x9D; +const float Edge = 0.15; layout(std140, push_constant) uniform Push { vec3 originLwc; @@ -30,7 +31,7 @@ layout(binding = 8, std430) buffer SB2 { uvec4 count; SurfelAlloc req[] layout(binding = 11, rgba8) uniform image2D dbgImage; shared SurfelAlloc prevQueue [256]; -shared SurfelAlloc pointQueue[64]; +shared SurfelAlloc pointQueue[128]; shared int pointQueueSize; shared int prevQueueSize; @@ -82,7 +83,6 @@ void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { const vec3 norm = normalFetch(gbufNormal, fragCoord); const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); - const float edge = 0.2; uvec3 p = uvec3(wpos/10); float wMax = seedNoise(wpos, z, screenSize)*0.1; @@ -92,16 +92,16 @@ void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { const float w = calculteWeight(s,wpos,norm); // w = max(w,0); wMax = max(wMax,w); - if(wMax > edge) + if(wMax > Edge) break; } - imageStore(dbgImage, fragCoord, vec4(wMax-edge)); + imageStore(dbgImage, fragCoord, vec4(wMax-Edge)); - if(wMax > edge) + if(wMax > Edge) return; - uint w = floatBitsToUint(wMax/edge) & 0xFFFF0000; + uint w = floatBitsToUint(wMax/Edge) & 0xFFFF0000; uint b = uint(w) | uint(gl_LocalInvocationIndex) ^ Salt; atomicMin(fragVote, b); } @@ -126,7 +126,7 @@ void reuseSurfel(ivec2 fragCoord, const ivec2 screenSize) { if(laneID0.1) { + if(wsurf > Edge) { uint w = floatBitsToUint(wsurf) & 0xFFFF0000; uint b = uint(w) | uint(laneID); atomicMax(reuseVote, b); From 3036acb570251f8de3de472f61201ac8e3dc9513 Mon Sep 17 00:00:00 2001 From: Try Date: Sat, 13 Jun 2026 20:54:23 +0200 Subject: [PATCH 26/52] surfels in progress --- shader/common.glsl | 2 +- shader/lighting/surfels/surf_binning.comp | 9 ++++++++- shader/lighting/surfels/surf_common.glsl | 11 +++++++++-- shader/lighting/surfels/surf_pathtrace.comp | 11 ++++++----- shader/ssao/ssao.comp | 2 +- 5 files changed, 25 insertions(+), 10 deletions(-) diff --git a/shader/common.glsl b/shader/common.glsl index e9e4d9348..0b3d99feb 100644 --- a/shader/common.glsl +++ b/shader/common.glsl @@ -188,7 +188,7 @@ vec3 sampleHemisphereCos(uint i, uint numSamples, float offsetAng) { const float u = sqrt(1 - xi.x); const float u1p = sqrt(1 - u*u); const float a = M_PI*2.0*xi.y + offsetAng; - return vec3(cos(a) * u1p, xi.x, sin(a) * u1p); + return vec3(cos(a) * u1p, sin(a) * u1p, xi.x); } vec3 sampleSphere(uint i, uint numSamples, float offsetAng) { diff --git a/shader/lighting/surfels/surf_binning.comp b/shader/lighting/surfels/surf_binning.comp index c2424a3ae..6bf3c4511 100644 --- a/shader/lighting/surfels/surf_binning.comp +++ b/shader/lighting/surfels/surf_binning.comp @@ -30,7 +30,14 @@ float pixelToWorld(float pixelRadius, float z) { } float renewRadius(const Surfel p, float z) { - return max(pixelToWorld(DefaultCoverage, z), 0); + float maxR = pixelToWorld(DefaultCoverage, z); + float minR = pixelToWorld(4, z); + //return max(1, maxR); + + return max(min(p.hRayHit*0.5, maxR), minR); + + // return max(min(p.hRayHit, maxR), 1); + // return clamp(p.hRayHit, 1, maxR); } void main() { diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 668534d3f..dae00f982 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -13,7 +13,8 @@ struct Surfel { float radius; int radiusPix; vec3 irradiance; - uint padd0; + //uint padd0; + float hRayHit; }; struct SurfelAlloc { @@ -102,7 +103,7 @@ float calculteWeight(const vec3 spos, const vec3 snorm, float radius, const vec3 float dotN = dot(wnorm, snorm); dist = max(dist, 0.0001); - +#if 1 float ePos = dist/radius; float eNorm = sqrt(max(1 - 1*dotN, 0)) / sqrt(1.0 - cos(M_PI/6.0)); // Eq. 4 float w = 1.0 - max(ePos, eNorm); // Eq. 2 @@ -111,6 +112,12 @@ float calculteWeight(const vec3 spos, const vec3 snorm, float radius, const vec3 //float eOccl = 1.0 - clamp(-dot(ldir, wnorm), 0, 1)*0.5; // allow small occlusion //float eOccl = (dot(ldir, snorm) > 0.1*dist) ? 0.1 : 1; return w*eOccl; +#else + float ePos = max(dist/radius, 0.0); + float eNorm = sqrt(max(1 - 1*dotN, 0)); + float eOccl = dot((ldir/dist), 0.5*(snorm+wnorm))*0.5+0.5; // allow small occlusion + return (1.0*eOccl)/max(ePos + eNorm, 0.0001) - 1.0; +#endif } vec3 surfDebugColor(Surfel s, uint sId) { diff --git a/shader/lighting/surfels/surf_pathtrace.comp b/shader/lighting/surfels/surf_pathtrace.comp index a14967d80..34ec2eaf0 100644 --- a/shader/lighting/surfels/surf_pathtrace.comp +++ b/shader/lighting/surfels/surf_pathtrace.comp @@ -147,14 +147,14 @@ void main() { if(surfelId>=count.x) return; - // uint hashKey = pcgHash(inorm - Random rngState = Random(0); const Surfel p = surfels[surfelId]; const mat3 tbn = toTangent(decodeNormal(p.norm)); + Random rngState = Random(pcgHash(gl_LocalInvocationIndex)); + const uint i = gl_LocalInvocationIndex; - const vec3 ray = tbn * sampleHemisphereCos(i,numPaths,0).xzy; + const vec3 ray = tbn * sampleHemisphereCos(i,numPaths,0); // const vec3 ray = randCosWeightedHemisphereDirection(decodeNormal(p.norm), rngState); const vec4 pt = pathtrace(p.pos, ray, rngState); @@ -164,8 +164,9 @@ void main() { reduceIrr(); if(gl_LocalInvocationIndex==0) { - // const float hitMean = float(numPaths)/max(reduction[0].a, eps); //harmonic mean - // surfels[surfelId].radius = min(surfels[surfelId].radius, hitMean); + const float hitMean = float(numPaths)/max(reduction[0].a, eps); //harmonic mean + surfels[surfelId].hRayHit = hitMean; + // surfels[surfelId].radius = min(hitMean, p.radius); surfels[surfelId].irradiance = (reduction[0].rgb/float(numPaths)); } } \ No newline at end of file diff --git a/shader/ssao/ssao.comp b/shader/ssao/ssao.comp index 91b44d2eb..811263f63 100644 --- a/shader/ssao/ssao.comp +++ b/shader/ssao/ssao.comp @@ -138,7 +138,7 @@ void calcOcclussion(const vec3 at0, const vec3 pos0, const float f0, uint seed, for(uint i0=0; i0 Date: Sun, 14 Jun 2026 00:55:36 +0200 Subject: [PATCH 27/52] improve surfel interpolation --- shader/lighting/surfels/surf_apply.comp | 7 +- shader/lighting/surfels/surf_binning.comp | 69 ++++++++++++++------ shader/lighting/surfels/surf_bvh_sample.comp | 2 +- shader/lighting/surfels/surf_common.glsl | 15 +++-- shader/lighting/surfels/surf_pathtrace.comp | 23 +++++-- shader/lighting/surfels/surf_tiled.comp | 22 +++++-- 6 files changed, 99 insertions(+), 39 deletions(-) diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp index a621d6daa..b3c7b9580 100644 --- a/shader/lighting/surfels/surf_apply.comp +++ b/shader/lighting/surfels/surf_apply.comp @@ -23,6 +23,8 @@ layout(binding = 5, std430) readonly buffer SB1 { uint surfelList[]; }; layout(binding = 6, r32ui) uniform uimage2D surfCnts; layout(binding = 7, r32ui) uniform uimage2D surfBins; layout(binding = 8, r11f_g11f_b10f) uniform image2D irradiance; +// +layout(binding = 11, rgba8) uniform image2D dbgImage; shared vec4 surfelsPos [NumThreads]; shared vec4 surfelsNorm[NumThreads]; @@ -38,7 +40,7 @@ vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { void applyBatch(inout vec4 clr, const vec3 wpos, const vec3 norm, const uint surfCount) { for(int i=0; i=count.x) return; - const Surfel p = surfels[surfelId]; - const vec4 pos4 = scene.viewProject * vec4(p.pos, 1.0); - const vec2 posNdc = ((pos4.xy/pos4.w)*0.5+0.5); - const ivec2 fragCoord = ivec2(posNdc*scene.screenRes + 0.5); + const Surfel p = surfels[surfelId]; + const vec4 pos4 = scene.viewProject * vec4(p.pos, 1.0); + const vec2 posNdc = ((pos4.xy/pos4.w)*0.5+0.5); + const ivec2 fragCoord = ivec2(posNdc*scene.screenRes + 0.5); + const float rMin = pixelToWorld(MinCoverage, pos4.z/pos4.w); + const float rMax = pixelToWorld(DefaultCoverage, pos4.z/pos4.w); + const float radiusMean = max(rMin, min(p.radiusMean, rMax)); + const int radiusPix = DefaultCoverage; //min(worldToPixel(p.pos, p.radiusMean), DefaultCoverage); - surfels[surfelId].fragCoord = fragCoord; - surfels[surfelId].radius = renewRadius(p, pos4.z/pos4.w); + surfels[surfelId].fragCoord = fragCoord; + surfels[surfelId].radiusPix = radiusPix; + surfels[surfelId].radius = rMax; + surfels[surfelId].radiusMean = radiusMean; - ivec2 pos0 = ivec2(fragCoord-p.radiusPix)/tileSize; - ivec2 pos1 = ivec2(fragCoord+p.radiusPix)/tileSize + 1; + ivec2 pos0 = ivec2(fragCoord-radiusPix)/tileSize; + ivec2 pos1 = ivec2(fragCoord+radiusPix)/tileSize + 1; ivec2 sz = imageSize(surfCnts); pos0 = max(ivec2(0), pos0); @@ -68,7 +97,7 @@ void main() { continue; const uint ptr = imageLoad(surfBins, tile).x + lptr; if(ptr>=surfelIds.length()) - return; // error! + return; // error! Must be too little memmory for the binning surfelIds[ptr] = surfelId; } } diff --git a/shader/lighting/surfels/surf_bvh_sample.comp b/shader/lighting/surfels/surf_bvh_sample.comp index 4d0cf0c67..364b55f27 100644 --- a/shader/lighting/surfels/surf_bvh_sample.comp +++ b/shader/lighting/surfels/surf_bvh_sample.comp @@ -43,7 +43,7 @@ vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { } float calculteWeight(const Surfel s, const vec3 wpos, const vec3 norm) { - return calculteWeight(s.pos.xyz, decodeNormal(s.norm), s.radius, wpos, norm); + return calculteWeight(s.pos.xyz, decodeNormal(s.norm), s.radiusMean, s.radius, wpos, norm); } void shade(const Surfel s, const vec3 wpos, const vec3 norm, const vec3 clr) { diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index dae00f982..724e9f099 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -4,6 +4,7 @@ #include "common.glsl" const float SKY_DEPTH = 0.999995; +const int MinCoverage = 4; // in pixels const int DefaultCoverage = 128; // in pixels struct Surfel { @@ -11,10 +12,9 @@ struct Surfel { uint norm; ivec2 fragCoord; float radius; - int radiusPix; + float radiusMean; vec3 irradiance; - //uint padd0; - float hRayHit; + int radiusPix; }; struct SurfelAlloc { @@ -94,7 +94,7 @@ uint surfHash(vec3 pos, float cellSize, uint inorm) { #endif } -float calculteWeight(const vec3 spos, const vec3 snorm, float radius, const vec3 wpos, const vec3 wnorm) { +float calculteWeight(const vec3 spos, const vec3 snorm, float radius, float rMax, const vec3 wpos, const vec3 wnorm) { // An Approximate Global Illumination System for Computer Generated Films // https://www.tabellion.org/et/paper/siggraph_2004_gi_for_films.pdf // https://cgg.mff.cuni.cz/~jaroslav/papers/2008-irradiance_caching_class/03-greg-ic.pdf @@ -103,7 +103,7 @@ float calculteWeight(const vec3 spos, const vec3 snorm, float radius, const vec3 float dotN = dot(wnorm, snorm); dist = max(dist, 0.0001); -#if 1 +#if 0 float ePos = dist/radius; float eNorm = sqrt(max(1 - 1*dotN, 0)) / sqrt(1.0 - cos(M_PI/6.0)); // Eq. 4 float w = 1.0 - max(ePos, eNorm); // Eq. 2 @@ -112,6 +112,11 @@ float calculteWeight(const vec3 spos, const vec3 snorm, float radius, const vec3 //float eOccl = 1.0 - clamp(-dot(ldir, wnorm), 0, 1)*0.5; // allow small occlusion //float eOccl = (dot(ldir, snorm) > 0.1*dist) ? 0.1 : 1; return w*eOccl; +#elif 1 + float wPos = max(1.0 - dist/rMax, 0.0)*(radius/dist); + float wNorm = pow(max(dotN, 0.0), 2.0); + float wOccl = dot((ldir/dist), snorm)*0.5+0.5; // allow small occlusion + return wPos * wNorm * wOccl; #else float ePos = max(dist/radius, 0.0); float eNorm = sqrt(max(1 - 1*dotN, 0)); diff --git a/shader/lighting/surfels/surf_pathtrace.comp b/shader/lighting/surfels/surf_pathtrace.comp index 34ec2eaf0..f80913503 100644 --- a/shader/lighting/surfels/surf_pathtrace.comp +++ b/shader/lighting/surfels/surf_pathtrace.comp @@ -4,6 +4,8 @@ #define RAY_QUERY #define RAY_QUERY_AT +// #define USE_MIN_HIT_DIST + #include "lighting/rt/rt_common.glsl" #include "lighting/pt/pathtrace_common.glsl" #include "lighting/surfels/surf_common.glsl" @@ -134,7 +136,12 @@ void reduceIrr() { for(uint stride = NumThreads/2; stride > 0; stride >>= 1) { if(laneID < stride) { - reduction[laneID] += reduction[laneID + stride]; + reduction[laneID].rgb += reduction[laneID + stride].rgb; +#if defined(USE_MIN_HIT_DIST) + reduction[laneID].a = min(reduction[laneID].a, reduction[laneID + stride].a); +#else + reduction[laneID].a += reduction[laneID + stride].a; +#endif } barrier(); } @@ -158,15 +165,23 @@ void main() { // const vec3 ray = randCosWeightedHemisphereDirection(decodeNormal(p.norm), rngState); const vec4 pt = pathtrace(p.pos, ray, rngState); - reduction[i] = vec4(pt.rgb, 1.0/max(pt.a, eps)); +#if defined(USE_MIN_HIT_DIST) + reduction[i] = vec4(pt.rgb, pt.a); +#else + reduction[i] = vec4(pt.rgb, 1.0/clamp(pt.a, eps, p.radius)); +#endif barrier(); reduceIrr(); if(gl_LocalInvocationIndex==0) { +#if defined(USE_MIN_HIT_DIST) + const float hitMin = max(4, reduction[0].a); + surfels[surfelId].radiusMean = hitMin; +#else const float hitMean = float(numPaths)/max(reduction[0].a, eps); //harmonic mean - surfels[surfelId].hRayHit = hitMean; - // surfels[surfelId].radius = min(hitMean, p.radius); + surfels[surfelId].radiusMean = hitMean; +#endif surfels[surfelId].irradiance = (reduction[0].rgb/float(numPaths)); } } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index d860ca4b6..98e55e7b8 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -11,7 +11,7 @@ const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z const ivec2 TileSize = ivec2(128); const float NormalBias = 0.0030; const uint Salt = 0x9D; -const float Edge = 0.15; +const float Edge = 0.25; layout(std140, push_constant) uniform Push { vec3 originLwc; @@ -31,7 +31,11 @@ layout(binding = 8, std430) buffer SB2 { uvec4 count; SurfelAlloc req[] layout(binding = 11, rgba8) uniform image2D dbgImage; shared SurfelAlloc prevQueue [256]; +shared float prevRMax [256]; + shared SurfelAlloc pointQueue[128]; +shared float pointRMax [128]; + shared int pointQueueSize; shared int prevQueueSize; @@ -62,8 +66,8 @@ float pixelToWorld(float pixelRadius, float z) { return min(worldRadiusX, worldRadiusY); } -float calculteWeight(const SurfelAlloc s, const vec3 wpos, const vec3 norm) { - return calculteWeight(s.pos.xyz, s.norm, s.pos.w, wpos, norm); +float calculteWeight(const SurfelAlloc s, float rMax, const vec3 wpos, const vec3 norm) { + return calculteWeight(s.pos.xyz, s.norm, s.pos.w, rMax, wpos, norm); } float seedNoise(vec3 wpos, float z, const ivec2 screenSize) { @@ -85,11 +89,11 @@ void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); uvec3 p = uvec3(wpos/10); - float wMax = seedNoise(wpos, z, screenSize)*0.1; + float wMax = 0; // seedNoise(wpos, z, screenSize)*0.1; for(int i=pointQueueSize; i>0;) { --i; const SurfelAlloc s = pointQueue[i]; - const float w = calculteWeight(s,wpos,norm); + const float w = calculteWeight(s,pointRMax[i],wpos,norm); // w = max(w,0); wMax = max(wMax,w); if(wMax > Edge) @@ -125,7 +129,7 @@ void reuseSurfel(ivec2 fragCoord, const ivec2 screenSize) { const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); if(laneID Edge) { uint w = floatBitsToUint(wsurf) & 0xFFFF0000; uint b = uint(w) | uint(laneID); @@ -145,9 +149,11 @@ void reuseSurfel(ivec2 fragCoord, const ivec2 screenSize) { reuseVote = 0x0000FFFF; pointQueue[pointQueueSize] = prevQueue[reuseId]; + pointRMax [pointQueueSize] = prevRMax [reuseId]; pointQueueSize++; prevQueue[reuseId] = prevQueue[prevQueueSize-1]; + prevRMax [reuseId] = prevRMax [prevQueueSize-1]; prevQueueSize--; } @@ -175,10 +181,11 @@ void surfAlloc(ivec2 fragCoord, const ivec2 screenSize) { const float sz = max(pixelToWorld(DefaultCoverage, z), 0); SurfelAlloc s; - s.pos = vec4(wpos, sz); + s.pos = vec4(wpos, sz*0.5); s.norm = norm; s.reuseId = 0xFFFFFFFF; pointQueue[pointQueueSize] = s; + pointRMax [pointQueueSize] = sz; pointQueueSize++; } @@ -220,6 +227,7 @@ void loadTile(ivec2 tileId) { s.norm = decodeNormal(sx.norm); s.reuseId = sId; prevQueue[i] = s; + prevRMax [i] = sx.radiusMean; } } From 7b9fcceea4650f57a17041629aaaf42bc75d1d3f Mon Sep 17 00:00:00 2001 From: Try Date: Sun, 14 Jun 2026 20:00:18 +0200 Subject: [PATCH 28/52] cleanup --- game/graphics/renderer.cpp | 40 +++++++++++++++++++------------------- game/graphics/renderer.h | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 35175df17..9874f5685 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -43,12 +43,6 @@ static Size tileCount(Size sz, int s) { return sz; } -static Size tileCount(IVec2 sz, int s) { - sz.x = (sz.x+s-1)/s; - sz.y = (sz.y+s-1)/s; - return Size(sz.x,sz.y); - } - Renderer::Renderer(Tempest::Swapchain& swapchain) : swapchain(swapchain) { auto& device = Resources::device(); @@ -581,8 +575,8 @@ void Renderer::dbgDraw(Tempest::Painter& p) { //tex.push_back(&textureCast(shadowMap[0])); //tex.push_back(&textureCast(vsm.pageData)); //tex.push_back(&textureCast(swrt.outputImage)); - //tex.push_back(&textureCast(surf.dbgImage)); - tex.push_back(&textureCast(surf.irrImage)); + tex.push_back(&textureCast(surf.dbgImage)); + //tex.push_back(&textureCast(surf.irrImage)); static int size = 400; int left = 10; @@ -1950,10 +1944,11 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor if(!settings.giSurfelsEnabled) return; + // const auto maxSeed = tileCount(zbuffer.size(), 4); // 4px is smalles footprint + // const uint32_t maxSurfels = uint32_t(maxSeed.w * maxSeed.h); // surf.maxSurfels; const uint32_t maxSurfels = surf.maxSurfels; - const uint32_t maxAlloc = surf.maxSurfels * 16; + const uint32_t maxAlloc = maxSurfels * 16; static int32_t tileSize = 128; - cmd.setDebugMarker("Surfels"); auto& scene = wview.sceneGlobals(); auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); @@ -1964,14 +1959,16 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor auto& surfAlloc = usesSsbo (surf.surfAlloc, shaders.surfTiled.sizeofBuffer(8, maxAlloc)); auto& surfDedup = usesSsboInit(surf.surfDedup, (maxSurfels+32-1)/32); - auto binCount = tileCount(zbuffer.size().toPoint()+IVec2(tileSize), tileSize); + auto binCount = tileCount(zbuffer.size(), tileSize); auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); + cmd.setDebugMarker("Surfels"); static bool binning = true; if(binning) { // prev-frame - binSurfels(cmd, wview, tileSize, false); + //cmd.setDebugMarker("Surfels: binning"); + surfelsBinning(cmd, wview, tileSize); } struct Push { @@ -1981,6 +1978,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor push.originLwc = scene.originLwc; push.tileSize = uint32_t(tileSize); + //cmd.setDebugMarker("Surfels"); static bool alloc = true; if(alloc) { cmd.setPushData(push); @@ -2010,11 +2008,6 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor //alloc = false; } - if(binning) { - // current frame - binSurfels(cmd, wview, tileSize, false); - } - static bool rays = true; if(rays) { cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); @@ -2033,8 +2026,15 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatchIndirect(surfels, 0); } + if(binning) { + // current frame + //cmd.setDebugMarker("Surfels: binning"); + surfelsBinning(cmd, wview, tileSize); + } + static bool apply = true; if(apply) { + //cmd.setDebugMarker("Surfels: resolve"); cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); @@ -2045,13 +2045,15 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setBinding(6, surfCnts); cmd.setBinding(7, surfBins); cmd.setBinding(8, irrImage); + // + cmd.setBinding(11, dbgImage); cmd.setPipeline(shaders.surfApply); cmd.dispatchThreads(zbuffer.size()); } } -void Renderer::binSurfels(Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool clearOnly) { +void Renderer::surfelsBinning(Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize) { const uint32_t maxSurfels = surf.maxSurfels; auto& scene = wview.sceneGlobals(); @@ -2075,8 +2077,6 @@ void Renderer::binSurfels(Tempest::Encoder& cmd, WorldVi cmd.setPipeline(shaders.surfBinClear); cmd.dispatchThreads(surfBins.size()); - if(clearOnly) - return; push.allocPass = 0; cmd.setPushData(push); diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index 910ca8bf9..a5a2789d3 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -66,7 +66,7 @@ class Renderer final { void prepareEpipolar (Tempest::Encoder& cmd, WorldView& wview); void prepareSurfels (Tempest::Encoder& cmd, WorldView& wview); - void binSurfels (Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool clearOnly); + void surfelsBinning (Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize); void drawHiZ (Tempest::Encoder& cmd, WorldView& view); void buildHiZ (Tempest::Encoder& cmd); From 7565fc09d798dd4ca9ee3df9cc72a585c4627049 Mon Sep 17 00:00:00 2001 From: Try Date: Mon, 15 Jun 2026 00:42:27 +0200 Subject: [PATCH 29/52] remove surfel bvh --- game/graphics/shaders.cpp | 6 +- game/graphics/shaders.h | 1 - shader/CMakeLists.txt | 2 - shader/lighting/surfels/surf_bvh.comp | 194 ------------------- shader/lighting/surfels/surf_bvh_sample.comp | 109 ----------- 5 files changed, 1 insertion(+), 311 deletions(-) delete mode 100644 shader/lighting/surfels/surf_bvh.comp delete mode 100644 shader/lighting/surfels/surf_bvh_sample.comp diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 6cb271568..4b64a6a6d 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -252,17 +252,13 @@ void Shaders::compileShaders() { surfInit = computeShader("surf_init.comp.sprv"); surfTiled = computeShader("surf_tiled.comp.sprv"); surfAlloc = computeShader("surf_alloc.comp.sprv"); + surfApply = computeShader("surf_apply.comp.sprv"); surfBinning = computeShader("surf_binning.comp.sprv"); surfBinClear = computeShader("surf_bin_clear.comp.sprv"); surfBinAlloc = computeShader("surf_bin_alloc.comp.sprv"); surfPathtrace = computeShader("surf_pathtrace.comp.sprv"); - - surfApply = computeShader("surf_apply.comp.sprv"); - - surfBvh = computeShader("surf_bvh.comp.sprv"); - surfBvhSample = computeShader("surf_bvh_sample.comp.sprv"); } if(Shaders::isVsmSupported()) { diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index ca7ad9ef9..a4b0d05b2 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -89,7 +89,6 @@ class Shaders { Tempest::ComputePipeline surfInit, surfTiled, surfAlloc; Tempest::ComputePipeline surfBinClear, surfBinning, surfBinAlloc; Tempest::ComputePipeline surfApply; - Tempest::ComputePipeline surfBvh, surfBvhSample; Tempest::ComputePipeline surfPathtrace; // Epipolar diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 01075b9da..809d23160 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -321,8 +321,6 @@ add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) -add_shader(surf_bvh.comp lighting/surfels/surf_bvh.comp) -add_shader(surf_bvh_sample.comp lighting/surfels/surf_bvh_sample.comp) add_shader(surf_pathtrace.comp lighting/surfels/surf_pathtrace.comp) # Pathtracing diff --git a/shader/lighting/surfels/surf_bvh.comp b/shader/lighting/surfels/surf_bvh.comp deleted file mode 100644 index 24d29916c..000000000 --- a/shader/lighting/surfels/surf_bvh.comp +++ /dev/null @@ -1,194 +0,0 @@ -#version 450 - -#include "lighting/surfels/surf_common.glsl" -#include "scene.glsl" -#include "common.glsl" - -layout(local_size_x = 256) in; - -const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; - -const uint BVH_NullNode = 0x00000000; -const uint BVH_BoxNode = 0x10000000; -const uint BVH_DataNode = 0x20000000; - -struct BVHNode { - ivec4 bbox; - uint ptrNext; - uint ptrMiss; - ivec2 padd0; - }; - -struct Task { - ivec4 bbox; - uint begin; - uint end; - uint bvhPtr; - uint ptrMiss; - }; - -layout(std140, push_constant) uniform Push { - vec3 originLwc; - uint maxSurfels; - }; -layout(binding = 0, std140) uniform UboScene { - SceneDesc scene; - }; - -layout(binding = 1) uniform sampler2D gbufDiffuse; -layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform sampler2D depth; -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 5, std430) buffer SB1 { BVHNode bvh[]; }; - -shared uint splitLeft; -shared uint iteratorL, iteratorR; -shared ivec4 bboxA; -shared ivec4 bboxB; - -shared Task stack[32]; -shared uint stackPtr; - -shared uint bvhSize; - -uint toBitHint(uint num) { - return num>1 ? BVH_BoxNode : BVH_DataNode; - } - -void pushTask(ivec4 bbox, uint bvhPtr, uint ptrMiss, uint begin, uint end) { - Task t; - t.bbox = bbox; - t.begin = begin; - t.end = end; - t.bvhPtr = bvhPtr; - t.ptrMiss = ptrMiss; - - stack[stackPtr] = t; - ++stackPtr; - } - -uint findSplit(uint bvhPtr, uint ptrMiss, uint begin, uint end, ivec2 bboxMin, ivec2 bboxMax) { - const uint laneID = gl_LocalInvocationIndex; - - splitLeft = begin; - iteratorL = begin; - iteratorR = end-1; - bboxA = ivec4(bboxMax, 0, 0); - bboxB = ivec4(bboxMax, 0, 0); - barrier(); - - int splitX = (bboxMin.x + bboxMax.x)/2; - int splitY = (bboxMin.y + bboxMax.y)/2; - - if(bboxMax.x-bboxMin.x < bboxMax.y-bboxMin.y) - splitX = 0x7FFFFFFF; else - splitY = 0x7FFFFFFF; - - for(uint i=begin+laneID; i=splitLeft) - break; - Surfel si = surfels[i]; - bool left = (si.fragCoord.x 1) { - findSplit(ptr, t.ptrMiss, t.begin, t.end, t.bbox.xy, t.bbox.zw); - } else { - //TODO: real leaf node - if(laneID==0) { - BVHNode node; - node.bbox = ivec4(0); - node.ptrNext = t.ptrMiss; - node.ptrMiss = t.ptrMiss; - node.padd0 = ivec2(t.begin, t.end); - bvh[ptr] = node; - } - } - - return false; - } - -void main() { - stackPtr = 0; - bvhSize = 1; - barrier(); - - findSplit(0, 0xFFFFFFFF, 0, count.x, ivec2(0), textureSize(depth, 0)); - barrier(); - - while(true) { - const bool done = nextTask(); - barrier(); - - if(done) - break; - } - } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_bvh_sample.comp b/shader/lighting/surfels/surf_bvh_sample.comp deleted file mode 100644 index 364b55f27..000000000 --- a/shader/lighting/surfels/surf_bvh_sample.comp +++ /dev/null @@ -1,109 +0,0 @@ -#version 450 - -#include "lighting/surfels/surf_common.glsl" -#include "scene.glsl" -#include "common.glsl" - -layout(local_size_x = 8, local_size_y = 8) in; - -const uint BVH_NullNode = 0x00000000; -const uint BVH_BoxNode = 0x10000000; -const uint BVH_DataNode = 0x20000000; - -struct BVHNode { - ivec4 bbox; - uint ptrNext; - uint ptrMiss; - ivec2 padd0; - }; - -layout(std140, push_constant) uniform Push { - vec3 originLwc; - uint maxSurfels; - }; -layout(binding = 0, std140) uniform UboScene { - SceneDesc scene; - }; - -layout(binding = 1) uniform sampler2D gbufDiffuse; -layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform sampler2D depth; -layout(binding = 4, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 5, std430) readonly buffer SB1 { BVHNode bvh[]; }; -// -layout(binding = 11, rgba8) uniform image2D dbgImage; - -vec4 color = vec4(0); - -vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { - const mat4 inv = scene.viewProjectLwcInv; - const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; - const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); - return (pos.xyz)/pos.w + originLwc; - } - -float calculteWeight(const Surfel s, const vec3 wpos, const vec3 norm) { - return calculteWeight(s.pos.xyz, decodeNormal(s.norm), s.radiusMean, s.radius, wpos, norm); - } - -void shade(const Surfel s, const vec3 wpos, const vec3 norm, const vec3 clr) { - float w = calculteWeight(s, wpos, norm); - if(w<=0) - return; - color += vec4(clr*w, w); - } - -bool intersect(ivec2 fragCoord, ivec4 bbox) { - return bbox.x <= fragCoord.x && fragCoord.x= SKY_DEPTH); - if(sky) - return; - - const vec3 norm = normalFetch(gbufNormal, fragCoord); - const vec3 wpos = worldPos(z, fragCoord, screenSize); - - const uint v = traverse(fragCoord, wpos, norm); - - if(color.w>0) - color.rgb /= color.w; - - //imageStore(dbgImage, fragCoord, vec4(v/255.0)); - imageStore(dbgImage, fragCoord, vec4(color.rgb, v/255.0)); - } \ No newline at end of file From 781e642d284dce60a43ced82d661f006e8830293 Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 16 Jun 2026 01:26:31 +0200 Subject: [PATCH 30/52] multipass surfel allocation --- shader/lighting/surfels/surf_apply.comp | 4 +- shader/lighting/surfels/surf_tiled.comp | 87 +++++++++++++------------ 2 files changed, 47 insertions(+), 44 deletions(-) diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp index b3c7b9580..6b442e2d6 100644 --- a/shader/lighting/surfels/surf_apply.comp +++ b/shader/lighting/surfels/surf_apply.comp @@ -94,8 +94,10 @@ void main() { barrier(); } - if(!valid || sky) + if(!valid || sky) { + imageStore(dbgImage, fragCoord, vec4(1)); return; + } if(clr.a>0) clr.rgb /= clr.a; diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index 98e55e7b8..3ec765535 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -11,7 +11,7 @@ const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z const ivec2 TileSize = ivec2(128); const float NormalBias = 0.0030; const uint Salt = 0x9D; -const float Edge = 0.25; +const float Edge = 0.1; layout(std140, push_constant) uniform Push { vec3 originLwc; @@ -70,53 +70,31 @@ float calculteWeight(const SurfelAlloc s, float rMax, const vec3 wpos, const vec return calculteWeight(s.pos.xyz, s.norm, s.pos.w, rMax, wpos, norm); } -float seedNoise(vec3 wpos, float z, const ivec2 screenSize) { - uvec3 p = uvec3(wpos/32); - return (pcgHash(p.x + pcgHash(p.y + pcgHash(p.z)))/4294967296.0)*0.1; - } - -void mainTile(const ivec2 fragCoord, const ivec2 screenSize) { - const bool valid = all(lessThan(fragCoord, screenSize)); - if(!valid) - return; +void mainTile(const ivec2 fragCoord, const vec3 wpos, const vec3 norm) { + float wSum = 0; - const float z = texelFetch(depth,fragCoord,0).x; - const bool sky = (z >= SKY_DEPTH); - if(sky) - return; - - const vec3 norm = normalFetch(gbufNormal, fragCoord); - const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); - - uvec3 p = uvec3(wpos/10); - float wMax = 0; // seedNoise(wpos, z, screenSize)*0.1; for(int i=pointQueueSize; i>0;) { --i; const SurfelAlloc s = pointQueue[i]; const float w = calculteWeight(s,pointRMax[i],wpos,norm); - // w = max(w,0); - wMax = max(wMax,w); - if(wMax > Edge) + wSum = (wSum + w); + if(wSum > 1.0) break; } - imageStore(dbgImage, fragCoord, vec4(wMax-Edge)); + imageStore(dbgImage, fragCoord, vec4(wSum)); - if(wMax > Edge) + if(wSum > 1.0) return; - uint w = floatBitsToUint(wMax/Edge) & 0xFFFF0000; + uint w = floatBitsToUint(wSum) & 0xFFFF0000; uint b = uint(w) | uint(gl_LocalInvocationIndex) ^ Salt; atomicMin(fragVote, b); } -void reuseSurfel(ivec2 fragCoord, const ivec2 screenSize) { +void reuseSurfel(ivec2 fragCoord, const ivec2 screenSize, const uint vote) { const uint laneID = gl_LocalInvocationIndex; - const uint vote = fragVote; - //reuseVote = 0x0000FFFF; - barrier(); - if((vote & 0xFFFF0000)==0xFFFF0000) return; @@ -181,7 +159,7 @@ void surfAlloc(ivec2 fragCoord, const ivec2 screenSize) { const float sz = max(pixelToWorld(DefaultCoverage, z), 0); SurfelAlloc s; - s.pos = vec4(wpos, sz*0.5); + s.pos = vec4(wpos, sz*2.0); s.norm = norm; s.reuseId = 0xFFFFFFFF; pointQueue[pointQueueSize] = s; @@ -231,6 +209,38 @@ void loadTile(ivec2 tileId) { } } +void mainSubtile(const ivec2 at, const ivec2 fragCoord, const ivec2 screenSize) { + const bool valid = all(lessThan(fragCoord, screenSize)); + const float z = valid ? texelFetch(depth,fragCoord,0).x : 1.0; + const bool sky = (z >= SKY_DEPTH); + + const vec3 norm = normalFetch(gbufNormal, fragCoord); + const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); + + fragVote = 0xFFFFFFFF; + barrier(); + + for(int i=0; i<3; ++i) { + if(!sky) { + mainTile(fragCoord, wpos, norm); + } + barrier(); + + //TODO: streamline reuse-alloc loop + const uint vote = fragVote; + barrier(); + + if((vote & 0xFFFF0000)==0xFFFF0000) + return; + + reuseSurfel(at, screenSize, vote); + barrier(); + + surfAlloc(at, screenSize); + barrier(); + } + } + void main() { // if(gl_WorkGroupID.xy!=uvec2(8,5) && gl_WorkGroupID.xy!=uvec2(8,6)) // return; @@ -253,19 +263,10 @@ void main() { const ivec2 coord0 = ivec2(gl_WorkGroupID.xy) * TileSize; const ivec2 coord1 = ivec2(gl_WorkGroupID.xy) * TileSize + TileSize; -#if 1 for(int y=coord0.y; y Date: Tue, 16 Jun 2026 22:10:26 +0200 Subject: [PATCH 31/52] improve surfel allocation --- shader/lighting/surfels/surf_tiled.comp | 216 ++++++++++++------------ 1 file changed, 108 insertions(+), 108 deletions(-) diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index 3ec765535..0df56b876 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -8,10 +8,11 @@ layout(local_size_x = 16, local_size_y = 16) in; const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; -const ivec2 TileSize = ivec2(128); -const float NormalBias = 0.0030; -const uint Salt = 0x9D; -const float Edge = 0.1; +const ivec2 TileSize = ivec2(128); +const float NormalBias = 0.0030; +const uint Salt = 0x9D; +const float Edge = 0.1; +const float MaxAttempts = 3; layout(std140, push_constant) uniform Push { vec3 originLwc; @@ -70,103 +71,31 @@ float calculteWeight(const SurfelAlloc s, float rMax, const vec3 wpos, const vec return calculteWeight(s.pos.xyz, s.norm, s.pos.w, rMax, wpos, norm); } -void mainTile(const ivec2 fragCoord, const vec3 wpos, const vec3 norm) { +float amendCoverage(const ivec2 fragCoord, const vec3 wpos, const vec3 norm) { + const int i = pointQueueSize-1; + const SurfelAlloc s = pointQueue[i]; + return calculteWeight(s,pointRMax[i],wpos,norm); + } + +float estimateCoverage(const ivec2 fragCoord, const vec3 wpos, const vec3 norm, const uint accounted) { float wSum = 0; - for(int i=pointQueueSize; i>0;) { + for(int i=pointQueueSize; i>accounted;) { --i; const SurfelAlloc s = pointQueue[i]; - const float w = calculteWeight(s,pointRMax[i],wpos,norm); - wSum = (wSum + w); + wSum += calculteWeight(s,pointRMax[i],wpos,norm); if(wSum > 1.0) - break; + return 1.0; } - - imageStore(dbgImage, fragCoord, vec4(wSum)); - - if(wSum > 1.0) - return; - + return wSum; + } + +void fragCoverageVote(float wSum) { uint w = floatBitsToUint(wSum) & 0xFFFF0000; uint b = uint(w) | uint(gl_LocalInvocationIndex) ^ Salt; atomicMin(fragVote, b); } -void reuseSurfel(ivec2 fragCoord, const ivec2 screenSize, const uint vote) { - const uint laneID = gl_LocalInvocationIndex; - - if((vote & 0xFFFF0000)==0xFFFF0000) - return; - - const uint id = (vote & 0xFFFF) ^ Salt; - fragCoord.x += int(id % gl_WorkGroupSize.x); - fragCoord.y += int(id / gl_WorkGroupSize.x); - - const float z = texelFetch(depth, fragCoord, 0).x; - const vec3 norm = normalFetch(gbufNormal, fragCoord); - const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); - - if(laneID Edge) { - uint w = floatBitsToUint(wsurf) & 0xFFFF0000; - uint b = uint(w) | uint(laneID); - atomicMax(reuseVote, b); - } - } - barrier(); - - if(laneID!=0) - return; - - const uint reuseId = reuseVote & 0x0000FFFF; - if(reuseId==0x0000FFFF || pointQueueSize>=pointQueue.length()) - return; - - fragVote = 0xFFFFFFFF; - reuseVote = 0x0000FFFF; - - pointQueue[pointQueueSize] = prevQueue[reuseId]; - pointRMax [pointQueueSize] = prevRMax [reuseId]; - pointQueueSize++; - - prevQueue[reuseId] = prevQueue[prevQueueSize-1]; - prevRMax [reuseId] = prevRMax [prevQueueSize-1]; - prevQueueSize--; - } - -void surfAlloc(ivec2 fragCoord, const ivec2 screenSize) { - if(gl_LocalInvocationIndex!=0) - return; - - if(pointQueueSize>=pointQueue.length()) { - return; - } - - const uint vote = fragVote; - fragVote = 0xFFFFFFFF; - - if((vote & 0xFFFF0000)==0xFFFF0000) - return; - - const uint id = (vote & 0xFFFF) ^ Salt; - fragCoord.x += int(id % gl_WorkGroupSize.x); - fragCoord.y += int(id / gl_WorkGroupSize.x); - - const float z = texelFetch(depth, fragCoord, 0).x; - const vec3 norm = normalFetch(gbufNormal, fragCoord); - const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); - const float sz = max(pixelToWorld(DefaultCoverage, z), 0); - - SurfelAlloc s; - s.pos = vec4(wpos, sz*2.0); - s.norm = norm; - s.reuseId = 0xFFFFFFFF; - pointQueue[pointQueueSize] = s; - pointRMax [pointQueueSize] = sz; - pointQueueSize++; - } - void storeSurfels() { const uint laneID = gl_LocalInvocationIndex; @@ -209,6 +138,69 @@ void loadTile(ivec2 tileId) { } } +void reuseSurfelVote(vec3 wpos, vec3 norm) { + const uint laneID = gl_LocalInvocationIndex; + if(laneID Edge) { + uint w = floatBitsToUint(wsurf) & 0xFFFF0000; + uint b = uint(w) | uint(laneID); + atomicMax(reuseVote, b); + } + } + } + +void reuseSurfel(uint reuseId) { + pointQueue[pointQueueSize] = prevQueue[reuseId]; + pointRMax [pointQueueSize] = prevRMax [reuseId]; + pointQueueSize++; + + prevQueue[reuseId] = prevQueue[prevQueueSize-1]; + prevRMax [reuseId] = prevRMax [prevQueueSize-1]; + prevQueueSize--; + } + +void allocSurfel(vec3 wpos, vec3 norm, float sz) { + SurfelAlloc s; + s.pos = vec4(wpos, sz*2.0); + s.norm = norm; + s.reuseId = 0xFFFFFFFF; + pointQueue[pointQueueSize] = s; + pointRMax [pointQueueSize] = sz; + pointQueueSize++; + } + +void reuseOrAlloc(ivec2 fragCoord, const ivec2 screenSize, const uint vote) { + const uint laneID = gl_LocalInvocationIndex; + + const uint id = (vote & 0xFFFF) ^ Salt; + fragCoord.x += int(id % gl_WorkGroupSize.x); + fragCoord.y += int(id / gl_WorkGroupSize.x); + + const vec3 norm = normalFetch(gbufNormal, fragCoord); + const float z = texelFetch(depth, fragCoord, 0).x; + const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); + + reuseSurfelVote(wpos, norm); + barrier(); + + const uint reuseId = reuseVote & 0x0000FFFF; + barrier(); + + if(reuseId!=0x0000FFFF) { + if(laneID==0) { + reuseVote = 0x0000FFFF; + reuseSurfel(reuseId); + } + return; + } + + if(laneID==0) { + const float sz = max(pixelToWorld(DefaultCoverage, z), 0); + allocSurfel(wpos, norm, sz); + } + } + void mainSubtile(const ivec2 at, const ivec2 fragCoord, const ivec2 screenSize) { const bool valid = all(lessThan(fragCoord, screenSize)); const float z = valid ? texelFetch(depth,fragCoord,0).x : 1.0; @@ -217,28 +209,37 @@ void mainSubtile(const ivec2 at, const ivec2 fragCoord, const ivec2 screenSize) const vec3 norm = normalFetch(gbufNormal, fragCoord); const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); - fragVote = 0xFFFFFFFF; - barrier(); + float coverage = (sky ? 1.0 : estimateCoverage(fragCoord, wpos, norm, 0)); + for(int i=0; i=pointQueue.length()) + break; - for(int i=0; i<3; ++i) { - if(!sky) { - mainTile(fragCoord, wpos, norm); - } + if(coverage<1.0) + fragCoverageVote(coverage); barrier(); - //TODO: streamline reuse-alloc loop const uint vote = fragVote; barrier(); + fragVote = 0xFFFFFFFF; if((vote & 0xFFFF0000)==0xFFFF0000) - return; + break; - reuseSurfel(at, screenSize, vote); + reuseOrAlloc(at, screenSize, vote); barrier(); - surfAlloc(at, screenSize); - barrier(); + coverage += amendCoverage(fragCoord, wpos, norm); } + + imageStore(dbgImage, fragCoord, vec4(coverage)); + } + +ivec2 remap(ivec2 subtile, ivec2 tileCnt) { + // shuffle sub-tiles a little + uint k = uint(subtile.y * tileCnt.x + subtile.x); + k ^= 0x12; + k &= uint(NumThreads-1); + return ivec2(int(k % tileCnt.x), int(k / tileCnt.x)); } void main() { @@ -259,13 +260,12 @@ void main() { barrier(); const ivec2 screenSize = ivec2(textureSize(depth,0)); - - const ivec2 coord0 = ivec2(gl_WorkGroupID.xy) * TileSize; - const ivec2 coord1 = ivec2(gl_WorkGroupID.xy) * TileSize + TileSize; - - for(int y=coord0.y; y Date: Wed, 17 Jun 2026 21:10:59 +0200 Subject: [PATCH 32/52] commandline --- game/commandline.cpp | 16 ++++++++++++---- game/commandline.h | 4 ++-- game/game/constants.h | 7 +++++++ game/gothic.cpp | 3 ++- game/gothic.h | 1 + game/graphics/renderer.cpp | 17 +++++++++-------- game/graphics/renderer.h | 2 +- 7 files changed, 34 insertions(+), 16 deletions(-) diff --git a/game/commandline.cpp b/game/commandline.cpp index eda2039ba..587a5b9bf 100644 --- a/game/commandline.cpp +++ b/game/commandline.cpp @@ -40,6 +40,12 @@ static bool boolArg(std::string_view v) { return std::string_view(v)!="0" && std::string_view(v)!="false"; } +static int intArg(std::string_view v) { + if(v=="false") + return 0; + return (std::stol(std::string(v))); + } + CommandLine::CommandLine(int argc, const char** argv) { instance = this; if(argc<1) @@ -114,8 +120,8 @@ CommandLine::CommandLine(int argc, const char** argv) { ++i; if(i0; - settings.swrtEnabled = Gothic::options().doSoftwareRT; + settings.giEnabled = Gothic::options().doRtGi; + settings.giSurfelsEnabled = Gothic::options().doIrrcGi; + settings.vsmEnabled = Gothic::options().doVirtualShadow; + settings.rtsmEnabled = Gothic::options().doSoftwareShadow; + settings.swrEnabled = Gothic::options().swRenderingPreset>0; + settings.swrtEnabled = Gothic::options().doSoftwareRT; sky.cloudsLut = device.image2d (sky.lutRGBAFormat, 2, 1); sky.transLut = device.attachment(sky.lutRGBFormat, 256, 64); @@ -562,7 +563,7 @@ void Renderer::draw(Encoder& cmd, uint8_t cmdId, size_t imgId, } void Renderer::dbgDraw(Tempest::Painter& p) { - static bool dbg = false; + static bool dbg = true; if(!dbg) return; @@ -2373,7 +2374,7 @@ void Renderer::drawRayQueryDbg(Tempest::Encoder& cmd, co } void Renderer::drawSurfelsDbg(Encoder& cmd, const WorldView& wview) { - static bool enable = false; + static bool enable = true; if(!enable) return; @@ -2390,7 +2391,7 @@ void Renderer::drawProbesDbg(Encoder& cmd, const WorldView& wview if(!settings.giEnabled) return; - static bool enable = false; + static bool enable = true; if(!enable) return; diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index a5a2789d3..e70abbeae 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -123,7 +123,7 @@ class Renderer final { bool zFogRadial = false; bool giEnabled = false; - bool giSurfelsEnabled = true; //TESTING + bool giSurfelsEnabled = false; bool aaEnabled = false; float zVidBrightness = 0.5; From 5847924608175af97417ab300280e91ca5afde8f Mon Sep 17 00:00:00 2001 From: Try Date: Thu, 18 Jun 2026 00:56:08 +0200 Subject: [PATCH 33/52] gi toggles --- game/gothic.cpp | 3 +- game/gothic.h | 3 +- game/graphics/renderer.cpp | 80 ++++++++++++++++++++------------------ game/graphics/renderer.h | 3 +- game/graphics/shaders.cpp | 20 ++++++++++ game/graphics/shaders.h | 2 + 6 files changed, 67 insertions(+), 44 deletions(-) diff --git a/game/gothic.cpp b/game/gothic.cpp index a48eea32d..e795b80ee 100644 --- a/game/gothic.cpp +++ b/game/gothic.cpp @@ -84,8 +84,7 @@ Gothic::Gothic() { auto& gpu = Resources::device().properties(); if(gpu.raytracing.rayQuery) { opts.doRayQuery = CommandLine::inst().isRayQuery(); - opts.doRtGi = opts.doRayQuery && CommandLine::inst().isRtGi()==GiMethod::Probes; - opts.doIrrcGi = opts.doRayQuery && CommandLine::inst().isRtGi()==GiMethod::IrrC; + opts.doGi = CommandLine::inst().isRtGi(); } if(hasMeshShader()) { diff --git a/game/gothic.h b/game/gothic.h index 57f976eef..00003a2b6 100644 --- a/game/gothic.h +++ b/game/gothic.h @@ -43,8 +43,7 @@ class Gothic final { struct Options { bool doRayQuery = false; - bool doRtGi = false; - bool doIrrcGi = false; + GiMethod doGi = GiMethod::None; bool doMeshShading = false; bool doBindless = false; bool doVirtualShadow = false; diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 5ebf8ba9e..55ea3a13d 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -88,8 +88,7 @@ Renderer::Renderer(Tempest::Swapchain& swapchain) Gothic::inst().togglePathtrace.bind(this, &Renderer::togglePathtrace); - settings.giEnabled = Gothic::options().doRtGi; - settings.giSurfelsEnabled = Gothic::options().doIrrcGi; + settings.giMethod = Gothic::options().doGi; settings.vsmEnabled = Gothic::options().doVirtualShadow; settings.rtsmEnabled = Gothic::options().doSoftwareShadow; settings.swrEnabled = Gothic::options().swRenderingPreset>0; @@ -194,7 +193,7 @@ void Renderer::setupSettings() { auto prevVidResIndex = settings.vidResIndex; settings.vidResIndex = Gothic::inst().settingsGetF("INTERNAL","vidResIndex"); - settings.aaEnabled = (Gothic::options().aaPreset>0) && (settings.vidResIndex==0); + settings.aaEnabled = (Gothic::options().aaPreset>0) && (settings.vidResIndex==0); // direct lighting if(settings.rtsmEnabled) @@ -217,9 +216,24 @@ void Renderer::setupSettings() { else lights.directLightPso = &shaders.lights; + const auto gi = settings.giMethod; + if(gi==GiMethod::Probes && Shaders::isGi1Supported() && Gothic::options().doRayQuery) { + settings.giMethod = GiMethod::Probes; + } + else if(gi==GiMethod::IrrC && Shaders::isGi2Supported() && Gothic::options().doRayQuery) { + settings.giMethod = GiMethod::IrrC; + } + else { + settings.giMethod = GiMethod::None; + } + if(prevVidResIndex!=settings.vidResIndex) { resetSwapchain(); } + if(settings.giMethod!=GiMethod::None) { + // need a projective shadow, for gi + resetShadowmap(); + } resetSkyFog(); resetShadowmap(); @@ -231,21 +245,15 @@ void Renderer::toggleGi() { if(!Gothic::options().doRayQuery) return; - auto prop = device.properties(); - if(prop.tex2d.maxSize<4096 || !prop.hasStorageFormat(R11G11B10UF) || !prop.hasStorageFormat(R16)) - return; - - settings.giEnabled = !settings.giEnabled; + if(settings.giMethod==GiMethod::None && Gothic::options().doGi!=GiMethod::None) + settings.giMethod = Gothic::options().doGi; + else if(settings.giMethod==GiMethod::None && Shaders::isGi1Supported()) + settings.giMethod = GiMethod::Probes; // default for now + else + settings.giMethod = GiMethod::None; device.waitIdle(); - if(auto wview = Gothic::inst().worldView()) { - wview->resetRendering(); - } - if(settings.giEnabled) { - // need a projective shadow, for gi - resetShadowmap(); - } - prepareUniforms(); + setupSettings(); } void Renderer::toggleVsm() { @@ -326,7 +334,7 @@ bool Renderer::requiresTlas() const { if(!Gothic::options().doRayQuery) return false; - if(settings.giEnabled || settings.giSurfelsEnabled || settings.pathTraceEnabled) + if(settings.giMethod!=GiMethod::None || settings.pathTraceEnabled) return true; if(!(settings.rtsmEnabled || settings.vsmEnabled)) return true; @@ -413,7 +421,7 @@ void Renderer::resetShadowmap() { for(int i=0; i& cmd, Wor if(!enable) return; - if(!settings.giSurfelsEnabled) + if(settings.giMethod!=GiMethod::IrrC) return; // const auto maxSeed = tileCount(zbuffer.size(), 4); // 4px is smalles footprint @@ -2106,7 +2114,7 @@ void Renderer::prepareIrradiance(Encoder& cmd, WorldView& wview) } void Renderer::prepareGi(Encoder& cmd, WorldView& wview) { - if(!settings.giEnabled || !settings.zCloudShadowScale) { + if(settings.giMethod!=GiMethod::Probes || !settings.zCloudShadowScale) { return; } @@ -2388,7 +2396,7 @@ void Renderer::drawSurfelsDbg(Encoder& cmd, const WorldView& wvie } void Renderer::drawProbesDbg(Encoder& cmd, const WorldView& wview) { - if(!settings.giEnabled) + if(settings.giMethod!=GiMethod::Probes) return; static bool enable = true; @@ -2405,7 +2413,7 @@ void Renderer::drawProbesDbg(Encoder& cmd, const WorldView& wview } void Renderer::drawProbesHitDbg(Encoder& cmd) { - if(!settings.giEnabled) + if(settings.giMethod!=GiMethod::Probes) return; static bool enable = false; @@ -2427,32 +2435,28 @@ void Renderer::drawAmbient(Encoder& cmd, const WorldView& view) { if(!enable) return; - if(settings.giEnabled && settings.zCloudShadowScale) { - cmd.setDebugMarker("AmbientLight"); - cmd.setBinding(0, view.sceneGlobals().uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gi.probesLighting); - cmd.setBinding(2, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(3, gbufNormal, Sampler::nearest()); - cmd.setBinding(4, zbuffer, Sampler::nearest()); - cmd.setBinding(5, ssao.ssaoBlur, Sampler::nearest()); - cmd.setBinding(6, gi.hashTable); - cmd.setBinding(7, gi.probes); - cmd.setPipeline(shaders.probeAmbient); - cmd.draw(nullptr, 0, 3); - return; - } - cmd.setDebugMarker("AmbientLight"); cmd.setBinding(0, view.sceneGlobals().uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); cmd.setBinding(2, gbufNormal, Sampler::nearest()); cmd.setBinding(3, sky.irradianceLut); - if(settings.giSurfelsEnabled) { + if(settings.giMethod==GiMethod::IrrC) { auto& ao = (settings.zCloudShadowScale ? textureCast(ssao.ssaoBlur) : Resources::fallbackBlack()); cmd.setBinding(4, ao, Sampler::nearest(ClampMode::ClampToEdge)); cmd.setBinding(5, surf.irrImage, Sampler::nearest(ClampMode::ClampToEdge)); cmd.setPipeline(shaders.ambientLightSurf); } + else if(settings.giMethod==GiMethod::Probes && settings.zCloudShadowScale) { + //TBD + cmd.setBinding(1, gi.probesLighting); + cmd.setBinding(2, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(3, gbufNormal, Sampler::nearest()); + cmd.setBinding(4, zbuffer, Sampler::nearest()); + cmd.setBinding(5, ssao.ssaoBlur, Sampler::nearest()); + cmd.setBinding(6, gi.hashTable); + cmd.setBinding(7, gi.probes); + cmd.setPipeline(shaders.probeAmbient); + } else if(settings.zCloudShadowScale) { cmd.setBinding(4, ssao.ssaoBlur, Sampler::nearest(ClampMode::ClampToEdge)); cmd.setPipeline(shaders.ambientLightSsao); diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index e70abbeae..e016bf37d 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -122,8 +122,7 @@ class Renderer final { bool zCloudShadowScale = false; bool zFogRadial = false; - bool giEnabled = false; - bool giSurfelsEnabled = false; + GiMethod giMethod = GiMethod::None; bool aaEnabled = false; float zVidBrightness = 0.5; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 4b64a6a6d..7ccd59bef 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -381,6 +381,26 @@ bool Shaders::isRtsmSupported() { return true; } +bool Shaders::isGi1Supported() { + auto& gpu = Resources::device().properties(); + if(!gpu.raytracing.rayQuery) + return false; + if(!gpu.hasStorageFormat(R11G11B10UF) || !gpu.hasStorageFormat(R16)) + return false; + if(gpu.tex2d.maxSize<4096 || gpu.compute.maxInvocations<256 || !gpu.descriptors.nonUniformIndexing) + return false; + return true; + } + +bool Shaders::isGi2Supported() { + auto& gpu = Resources::device().properties(); + if(!gpu.raytracing.rayQuery) + return false; + if(gpu.compute.maxInvocations<256 || !gpu.descriptors.nonUniformIndexing) + return false; + return true; + } + const RenderPipeline* Shaders::materialPipeline(const Material& mat, DrawCommands::Type t, PipelineType pt, bool bl) const { if(t==DrawCommands::Static) { // same shader diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index a4b0d05b2..33cb8a31c 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -27,6 +27,8 @@ class Shaders { static Shaders& inst(); static bool isVsmSupported(); static bool isRtsmSupported(); + static bool isGi1Supported(); + static bool isGi2Supported(); Tempest::RenderPipeline lights, lightsRq, lightsVsm; Tempest::RenderPipeline directLight, directLightSh, directLightRq; From acc88dab1ad7066d7030e2f1c26b37e731d8215c Mon Sep 17 00:00:00 2001 From: Try Date: Thu, 18 Jun 2026 02:05:27 +0200 Subject: [PATCH 34/52] aggressive prune on high coverage areas --- shader/lighting/surfels/surf_common.glsl | 2 +- shader/lighting/surfels/surf_tiled.comp | 43 ++++++++++++++---------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 724e9f099..a8e981be1 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -4,7 +4,7 @@ #include "common.glsl" const float SKY_DEPTH = 0.999995; -const int MinCoverage = 4; // in pixels +const int MinCoverage = 8; // in pixels const int DefaultCoverage = 128; // in pixels struct Surfel { diff --git a/shader/lighting/surfels/surf_tiled.comp b/shader/lighting/surfels/surf_tiled.comp index 0df56b876..4df8b55d4 100644 --- a/shader/lighting/surfels/surf_tiled.comp +++ b/shader/lighting/surfels/surf_tiled.comp @@ -12,7 +12,8 @@ const ivec2 TileSize = ivec2(128); const float NormalBias = 0.0030; const uint Salt = 0x9D; const float Edge = 0.1; -const float MaxAttempts = 3; +const float MaxAttempts = 4; +const int MaxQueue = 256; layout(std140, push_constant) uniform Push { vec3 originLwc; @@ -31,24 +32,17 @@ layout(binding = 8, std430) buffer SB2 { uvec4 count; SurfelAlloc req[] // layout(binding = 11, rgba8) uniform image2D dbgImage; -shared SurfelAlloc prevQueue [256]; -shared float prevRMax [256]; +shared SurfelAlloc prevQueue [MaxQueue]; +shared float prevRMax [MaxQueue]; -shared SurfelAlloc pointQueue[128]; -shared float pointRMax [128]; +shared SurfelAlloc pointQueue[MaxQueue]; +shared float pointRMax [MaxQueue]; shared int pointQueueSize; shared int prevQueueSize; shared uint fragVote, reuseVote; -vec3 rayOrigin(ivec2 frag, float depth, vec3 normal) { - const vec2 fragCoord = ((frag.xy+0.5)*scene.screenResInv)*2.0 - vec2(1.0); - const vec4 scr = vec4(fragCoord.x, fragCoord.y, depth, 1.0); - const vec4 wpos = scene.viewProjectLwcInv * scr; - return (wpos.xyz + normal*NormalBias)/wpos.w; - } - vec3 worldPos(float z, vec3 normal, ivec2 fragCoord, ivec2 screenSize) { const mat4 inv = scene.viewProjectLwcInv; const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; @@ -121,21 +115,34 @@ void loadTile(ivec2 tileId) { ivec2 bboxMin = ivec2(gl_WorkGroupID.xy*TileSize); ivec2 bboxMax = bboxMin + ivec2(TileSize); - if(laneID==0) - prevQueueSize = int(min(cnt, prevQueue.length())); + const bool conservative = (cnt>prevQueue.length()); + barrier(); - for(uint i=laneID; i Date: Thu, 18 Jun 2026 22:15:43 +0200 Subject: [PATCH 35/52] cleanup --- game/graphics/renderer.cpp | 16 +++++++--------- shader/lighting/rt/probe_ambient.frag | 13 ++++++------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 55ea3a13d..c73a4a90a 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -2439,29 +2439,27 @@ void Renderer::drawAmbient(Encoder& cmd, const WorldView& view) { cmd.setBinding(0, view.sceneGlobals().uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, sky.irradianceLut); if(settings.giMethod==GiMethod::IrrC) { auto& ao = (settings.zCloudShadowScale ? textureCast(ssao.ssaoBlur) : Resources::fallbackBlack()); + cmd.setBinding(3, surf.irrImage, Sampler::nearest(ClampMode::ClampToEdge)); cmd.setBinding(4, ao, Sampler::nearest(ClampMode::ClampToEdge)); - cmd.setBinding(5, surf.irrImage, Sampler::nearest(ClampMode::ClampToEdge)); cmd.setPipeline(shaders.ambientLightSurf); } else if(settings.giMethod==GiMethod::Probes && settings.zCloudShadowScale) { - //TBD - cmd.setBinding(1, gi.probesLighting); - cmd.setBinding(2, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(3, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, ssao.ssaoBlur, Sampler::nearest()); cmd.setBinding(4, zbuffer, Sampler::nearest()); - cmd.setBinding(5, ssao.ssaoBlur, Sampler::nearest()); - cmd.setBinding(6, gi.hashTable); - cmd.setBinding(7, gi.probes); + cmd.setBinding(5, gi.hashTable); + cmd.setBinding(6, gi.probes); + cmd.setBinding(7, gi.probesLighting); cmd.setPipeline(shaders.probeAmbient); } else if(settings.zCloudShadowScale) { + cmd.setBinding(3, sky.irradianceLut); cmd.setBinding(4, ssao.ssaoBlur, Sampler::nearest(ClampMode::ClampToEdge)); cmd.setPipeline(shaders.ambientLightSsao); } else { + cmd.setBinding(3, sky.irradianceLut); cmd.setPipeline(shaders.ambientLight); } cmd.draw(nullptr, 0, 3); diff --git a/shader/lighting/rt/probe_ambient.frag b/shader/lighting/rt/probe_ambient.frag index 1bd00d783..33271911c 100644 --- a/shader/lighting/rt/probe_ambient.frag +++ b/shader/lighting/rt/probe_ambient.frag @@ -17,14 +17,13 @@ layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; -layout(binding = 1) uniform sampler2D probesLighting; -layout(binding = 2) uniform sampler2D gbufDiffuse; -layout(binding = 3) uniform usampler2D gbufNormal; +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D ssao; layout(binding = 4) uniform sampler2D depth; -layout(binding = 5) uniform sampler2D ssao; - -layout(binding = 6, std430) readonly buffer Hbo0 { uint hashTable[]; }; -layout(binding = 7, std430) readonly buffer Pbo { ProbesHeader probeHeader; Probe probe[]; }; +layout(binding = 5, std430) readonly buffer Hbo0 { uint hashTable[]; }; +layout(binding = 6, std430) readonly buffer Pbo { ProbesHeader probeHeader; Probe probe[]; }; +layout(binding = 7) uniform sampler2D probesLighting; layout(location = 0) out vec4 outColor; From 98be5e872ec1e4735ef238b14977be429c0f2764 Mon Sep 17 00:00:00 2001 From: Try Date: Sun, 21 Jun 2026 01:36:10 +0200 Subject: [PATCH 36/52] Wendland weighting for surfels --- game/graphics/renderer.cpp | 2 +- shader/CMakeLists.txt | 1 + shader/lighting/ambient_light.frag | 19 +++++++++++------ shader/lighting/surfels/surf_common.glsl | 21 +++++++++++++++---- shader/lighting/surfels/surf_dbg.frag | 4 ++-- shader/lighting/surfels/surf_enlist.comp | 14 +++++++++++++ shader/lighting/surfels/surf_pathtrace.comp | 23 +++++++++++++++++---- 7 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 shader/lighting/surfels/surf_enlist.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index c73a4a90a..a5e92ef35 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -2399,7 +2399,7 @@ void Renderer::drawProbesDbg(Encoder& cmd, const WorldView& wview if(settings.giMethod!=GiMethod::Probes) return; - static bool enable = true; + static bool enable = false; if(!enable) return; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 809d23160..45e0fa6e6 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -321,6 +321,7 @@ add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) +add_shader(surf_enlist.comp lighting/surfels/surf_enlist.comp) add_shader(surf_pathtrace.comp lighting/surfels/surf_pathtrace.comp) # Pathtracing diff --git a/shader/lighting/ambient_light.frag b/shader/lighting/ambient_light.frag index cabcc98b1..a63808b35 100644 --- a/shader/lighting/ambient_light.frag +++ b/shader/lighting/ambient_light.frag @@ -13,12 +13,14 @@ layout(binding = 0, std140) uniform UboScene { }; layout(binding = 1) uniform texture2D gbufDiffuse; layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform texture2D irradiance; -#if defined(SSAO) -layout(binding = 4) uniform sampler2D ssao; -#endif #if defined(SURFEL_GI) -layout(binding = 5) uniform sampler2D surfGi; +layout(binding = 3) uniform sampler2D surfGi; +layout(binding = 4) uniform sampler2D ssao; +#elif defined(SSAO) +layout(binding = 3) uniform texture2D irradiance; +layout(binding = 4) uniform sampler2D ssao; +#else +layout(binding = 3) uniform texture2D irradiance; #endif layout(location = 0) out vec4 outColor; @@ -31,6 +33,7 @@ float textureSsao() { return textureLod(ssao, uv, 0).r; } float textureSsao() { return 1; } #endif +#if !defined(SURFEL_GI) vec3 skyIrradiance(vec3 n) { ivec3 d; d.x = n.x>=0 ? 1 : 0; @@ -46,6 +49,7 @@ vec3 skyIrradiance(vec3 n) { return ret; } +#endif float grayscale(vec3 color) { return dot(color, vec3(0.2125, 0.7154, 0.0721)); @@ -79,8 +83,11 @@ void main() { vec3 color = linear; color *= luminance(norm); +#if defined(SURFEL_GI) + // preexposed already + //color *= ao; +#else color *= ao; -#if !defined(SURFEL_GI) // preexposed already color *= scene.exposure; #endif diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index a8e981be1..91ef18c46 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -94,7 +94,7 @@ uint surfHash(vec3 pos, float cellSize, uint inorm) { #endif } -float calculteWeight(const vec3 spos, const vec3 snorm, float radius, float rMax, const vec3 wpos, const vec3 wnorm) { +float calculteWeight(const vec3 spos, const vec3 snorm, float rEff, float rMax, const vec3 wpos, const vec3 wnorm) { // An Approximate Global Illumination System for Computer Generated Films // https://www.tabellion.org/et/paper/siggraph_2004_gi_for_films.pdf // https://cgg.mff.cuni.cz/~jaroslav/papers/2008-irradiance_caching_class/03-greg-ic.pdf @@ -104,7 +104,7 @@ float calculteWeight(const vec3 spos, const vec3 snorm, float radius, float rMax dist = max(dist, 0.0001); #if 0 - float ePos = dist/radius; + float ePos = dist/rEff; float eNorm = sqrt(max(1 - 1*dotN, 0)) / sqrt(1.0 - cos(M_PI/6.0)); // Eq. 4 float w = 1.0 - max(ePos, eNorm); // Eq. 2 @@ -113,12 +113,25 @@ float calculteWeight(const vec3 spos, const vec3 snorm, float radius, float rMax //float eOccl = (dot(ldir, snorm) > 0.1*dist) ? 0.1 : 1; return w*eOccl; #elif 1 - float wPos = max(1.0 - dist/rMax, 0.0)*(radius/dist); + // Wendland C2 enspired falloff + rEff = min(rEff, rMax*0.5); + float q = max(min(dist,rMax)-rEff, 0)/(rMax-rEff); + float wPos = pow(1-q, 4.0)*(4.0*q + 1.0); + float wNorm = pow(max(dotN, 0.0), 2.0); + float wOccl = 1.0 - max(dot((ldir/dist), snorm), 0.0); + return wPos * wNorm * wOccl; +#elif 0 + float wPos = 1.0 - smoothstep(min(rEff,rMax*0.6), rMax, dist); + float wNorm = pow(max(dotN, 0.0), 2.0); + float wOccl = 1.0 - max(dot((ldir/dist), snorm), 0.0); + return wPos * wNorm * wOccl; +#elif 0 + float wPos = max(1.0 - dist/rMax, 0.0)*(rEff/dist); float wNorm = pow(max(dotN, 0.0), 2.0); float wOccl = dot((ldir/dist), snorm)*0.5+0.5; // allow small occlusion return wPos * wNorm * wOccl; #else - float ePos = max(dist/radius, 0.0); + float ePos = max(dist/rEff, 0.0); float eNorm = sqrt(max(1 - 1*dotN, 0)); float eOccl = dot((ldir/dist), 0.5*(snorm+wnorm))*0.5+0.5; // allow small occlusion return (1.0*eOccl)/max(ePos + eNorm, 0.0001) - 1.0; diff --git a/shader/lighting/surfels/surf_dbg.frag b/shader/lighting/surfels/surf_dbg.frag index 0e4eb75b6..a7cf533c1 100644 --- a/shader/lighting/surfels/surf_dbg.frag +++ b/shader/lighting/surfels/surf_dbg.frag @@ -43,8 +43,8 @@ void main(void) { if(length(delta) > radius) ;//discard; - // vec3 clr = surfDebugColor(p, instanceIndex) * (1.0-qDist); - vec3 clr = 3.0 * p.irradiance * (1.0-qDist) * scene.exposure; + vec3 clr = surfDebugColor(p, instanceIndex) * (1.0-qDist); + //vec3 clr = 3.0 * p.irradiance * (1.0-qDist) * scene.exposure; outColor = vec4(clr,1.0); // outColor = vec4(1,0,0,1.0); } diff --git a/shader/lighting/surfels/surf_enlist.comp b/shader/lighting/surfels/surf_enlist.comp new file mode 100644 index 000000000..cb1bf8e23 --- /dev/null +++ b/shader/lighting/surfels/surf_enlist.comp @@ -0,0 +1,14 @@ +#version 460 + +layout(local_size_x = 64) in; + +#include "lighting/surfels/surf_common.glsl" + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + +layout(binding = 0, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; + +void main() { + const Surfel p = surfels[gl_GlobalInvocationID.x]; + + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_pathtrace.comp b/shader/lighting/surfels/surf_pathtrace.comp index f80913503..167094e54 100644 --- a/shader/lighting/surfels/surf_pathtrace.comp +++ b/shader/lighting/surfels/surf_pathtrace.comp @@ -5,6 +5,7 @@ #define RAY_QUERY_AT // #define USE_MIN_HIT_DIST +// #define RTAO #include "lighting/rt/rt_common.glsl" #include "lighting/pt/pathtrace_common.glsl" @@ -18,6 +19,8 @@ layout(local_size_x = 64) in; const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; +const int numBounces = 5; +// const int numBounces = 1; layout(binding = 0, std140) uniform UboScene { SceneDesc scene; @@ -52,8 +55,6 @@ float sampleDirectLight(vec3 norm, vec3 rayOrigin, vec3 rayDirection, bool shado } vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout Random rngState) { - const int numBounces = 5; - vec3 thruput = vec3(1); vec3 color = vec3(0); bool underWater = (scene.underWater!=0); @@ -90,6 +91,10 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout Random rngState) { break; } +#if defined(RTAO) + return vec4(color, depth); +#endif + /* if(underWater) { const float depth = hit.rayT / 5000.0; // 50 meters @@ -130,6 +135,7 @@ vec4 pathtrace(vec3 rayOrigin, vec3 rayDirection, inout Random rngState) { } shared vec4 reduction[NumThreads]; +shared uint hitCnt; void reduceIrr() { uint laneID = gl_LocalInvocationIndex; @@ -148,7 +154,7 @@ void reduceIrr() { } void main() { - const float eps = 0.001; + const float eps = 0.0001; const uint numPaths = NumThreads; const uint surfelId = gl_WorkGroupID.x; //gl_GlobalInvocationID.x; if(surfelId>=count.x) @@ -165,10 +171,16 @@ void main() { // const vec3 ray = randCosWeightedHemisphereDirection(decodeNormal(p.norm), rngState); const vec4 pt = pathtrace(p.pos, ray, rngState); + hitCnt = 0; + barrier(); + + if(pt.a!=TMax) + atomicAdd(hitCnt, 1); + #if defined(USE_MIN_HIT_DIST) reduction[i] = vec4(pt.rgb, pt.a); #else - reduction[i] = vec4(pt.rgb, 1.0/clamp(pt.a, eps, p.radius)); + reduction[i] = vec4(pt.rgb, 1.0/clamp(pt.a*0.4, 10.0, 1*p.radius)); #endif barrier(); @@ -178,6 +190,9 @@ void main() { #if defined(USE_MIN_HIT_DIST) const float hitMin = max(4, reduction[0].a); surfels[surfelId].radiusMean = hitMin; +#elif 0 + const float hitMean = float(hitCnt)/max(reduction[0].a, eps); //harmonic mean + surfels[surfelId].radiusMean = hitCnt > 0 ? hitMean : p.radius; #else const float hitMean = float(numPaths)/max(reduction[0].a, eps); //harmonic mean surfels[surfelId].radiusMean = hitMean; From b5da82af28fd94607456f5d297ab76c8ab7ff9e2 Mon Sep 17 00:00:00 2001 From: Try Date: Wed, 24 Jun 2026 01:01:59 +0200 Subject: [PATCH 37/52] blue-noise based allocator initial --- game/graphics/renderer.cpp | 132 +++++++++++++-- game/graphics/renderer.h | 9 +- game/graphics/shaders.cpp | 16 +- game/graphics/shaders.h | 4 +- shader/CMakeLists.txt | 14 +- shader/lighting/surfels/surf_binning.comp | 16 +- shader/lighting/surfels/surf_common.glsl | 9 ++ shader/lighting/surfels/surf_dbg.frag | 6 +- shader/lighting/surfels/surf_enlist.comp | 14 -- shader/lighting/surfels/surf_init2.comp | 11 ++ shader/lighting/surfels/surf_spawn.comp | 124 ++++++++++++++ .../lighting/surfels/surf_tile_decimate.comp | 153 ++++++++++++++++++ .../lighting/surfels/surf_tile_normalize.comp | 49 ++++++ shader/lighting/surfels/surf_tile_weight.comp | 45 ++++++ shader/lighting/surfels/surf_weight.comp | 59 +++++++ 15 files changed, 619 insertions(+), 42 deletions(-) delete mode 100644 shader/lighting/surfels/surf_enlist.comp create mode 100644 shader/lighting/surfels/surf_init2.comp create mode 100644 shader/lighting/surfels/surf_spawn.comp create mode 100644 shader/lighting/surfels/surf_tile_decimate.comp create mode 100644 shader/lighting/surfels/surf_tile_normalize.comp create mode 100644 shader/lighting/surfels/surf_tile_weight.comp create mode 100644 shader/lighting/surfels/surf_weight.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index a5e92ef35..0e95676b7 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -571,7 +571,7 @@ void Renderer::draw(Encoder& cmd, uint8_t cmdId, size_t imgId, } void Renderer::dbgDraw(Tempest::Painter& p) { - static bool dbg = true; + static bool dbg = false; if(!dbg) return; @@ -1953,6 +1953,109 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor if(settings.giMethod!=GiMethod::IrrC) return; + const uint32_t maxSurfels = surf.maxSurfels; + const int32_t tileSize = 128; + const int32_t DefaultCoverage = 128; + const auto binCount = tileCount(zbuffer.size(), DefaultCoverage); + + auto& scene = wview.sceneGlobals(); + auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); + auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::R11G11B10UF, zbuffer.size()); + + auto& surfels = usesSsboInit(surf.surfels, shaders.surfSpawn.sizeofBuffer(4, maxSurfels)); + auto& surfAlloc = usesSsboInit(surf.surfAlloc, shaders.surfSpawn.sizeofBuffer(5, maxSurfels)); + auto& surfList = usesSsbo (surf.surfList, 16*maxSurfels*sizeof(uint32_t)); + + auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); + auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); + auto& surfPdf = usesImage2d(surf.surfPdf, TextureFormat::R32F, binCount); + + struct Push { + Vec3 originLwc; + uint32_t tileSize; + } push = {}; + push.originLwc = scene.originLwc; + push.tileSize = uint32_t(tileSize); + + cmd.setDebugMarker("Surfels"); + // prev-frame + // surfelsBinning(cmd, wview, tileSize); + + static bool apply = false; + if(apply) { + //TODO: apply pass 1 + } + + static bool alloc = true; + if(alloc) { + //alloc = false; + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, surfAlloc); + // + cmd.setBinding(11, dbgImage); + + cmd.setPipeline(shaders.surfInit2); + cmd.dispatchThreads(1); + + cmd.setPipeline(shaders.surfSpawn); + cmd.dispatchThreads(zbuffer.size()); + } + + surfelsBinning(cmd, wview, tileSize, true); + + if(true) { + cmd.setPushData(push); + cmd.setBinding(4, surfels); + cmd.setBinding(5, surfAlloc); + cmd.setBinding(6, surfList); + cmd.setBinding(7, surfCnts); + cmd.setBinding(8, surfBins); + cmd.setBinding(9, surfPdf); + cmd.setPipeline(shaders.surfWeight); + cmd.dispatchIndirect(surfAlloc, 0); + + cmd.setPipeline(shaders.surfTileWeight); + cmd.dispatch(binCount); + + cmd.setPipeline(shaders.surfTileNorm); + cmd.dispatch(1); + + cmd.setPipeline(shaders.surfTileDecim); + cmd.dispatch(binCount); + } + + if(apply) { + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, surfList); + cmd.setBinding(6, surfCnts); + cmd.setBinding(7, surfBins); + cmd.setBinding(8, irrImage); + // + cmd.setBinding(11, dbgImage); + + cmd.setPipeline(shaders.surfApply); + cmd.dispatchThreads(zbuffer.size()); + } + } + +void Renderer::prepareSurfels2(Tempest::Encoder& cmd, WorldView& wview) { + static bool enable = true; + if(!enable) + return; + + if(settings.giMethod!=GiMethod::IrrC) + return; + // const auto maxSeed = tileCount(zbuffer.size(), 4); // 4px is smalles footprint // const uint32_t maxSurfels = uint32_t(maxSeed.w * maxSeed.h); // surf.maxSurfels; const uint32_t maxSurfels = surf.maxSurfels; @@ -1977,7 +2080,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor if(binning) { // prev-frame //cmd.setDebugMarker("Surfels: binning"); - surfelsBinning(cmd, wview, tileSize); + surfelsBinning(cmd, wview, tileSize, false); } struct Push { @@ -2017,7 +2120,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor //alloc = false; } - static bool rays = true; + static bool rays = false; if(rays) { cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, surfels); @@ -2038,10 +2141,10 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor if(binning) { // current frame //cmd.setDebugMarker("Surfels: binning"); - surfelsBinning(cmd, wview, tileSize); + surfelsBinning(cmd, wview, tileSize, false); } - static bool apply = true; + static bool apply = false; if(apply) { //cmd.setDebugMarker("Surfels: resolve"); cmd.setPushData(push); @@ -2062,14 +2165,15 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor } } -void Renderer::surfelsBinning(Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize) { +void Renderer::surfelsBinning(Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool alloc) { const uint32_t maxSurfels = surf.maxSurfels; - auto& scene = wview.sceneGlobals(); - auto& surfels = surf.surfels; - auto& surfCnts = surf.surfCnts; - auto& surfBins = surf.surfBins; - auto& surfList = surf.surfList; + auto& scene = wview.sceneGlobals(); + auto& surfels = alloc ? surf.surfAlloc : surf.surfels; + auto& surfCnts = surf.surfCnts; + auto& surfBins = surf.surfBins; + auto& surfList = surf.surfList; + auto& surfBinning = alloc ? shaders.surfBinningA : shaders.surfBinningS; struct Push { int32_t tileSize; @@ -2089,15 +2193,15 @@ void Renderer::surfelsBinning(Tempest::Encoder& cmd, Wor push.allocPass = 0; cmd.setPushData(push); - cmd.setPipeline(shaders.surfBinning); - cmd.dispatchThreads(maxSurfels); + cmd.setPipeline(surfBinning); + cmd.dispatchThreads(maxSurfels); //TODO: indirect cmd.setPipeline(shaders.surfBinAlloc); cmd.dispatchThreads(surfBins.size()); push.allocPass = 1; cmd.setPushData(push); - cmd.setPipeline(shaders.surfBinning); + cmd.setPipeline(surfBinning); cmd.dispatchThreads(maxSurfels); } diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index e016bf37d..deab6793b 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -66,7 +66,8 @@ class Renderer final { void prepareEpipolar (Tempest::Encoder& cmd, WorldView& wview); void prepareSurfels (Tempest::Encoder& cmd, WorldView& wview); - void surfelsBinning (Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize); + void prepareSurfels2 (Tempest::Encoder& cmd, WorldView& wview); + void surfelsBinning (Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool alloc); void drawHiZ (Tempest::Encoder& cmd, WorldView& view); void buildHiZ (Tempest::Encoder& cmd); @@ -213,11 +214,11 @@ class Renderer final { struct { const uint32_t maxSurfels = 16*1024; - Tempest::StorageBuffer surfels; + Tempest::StorageBuffer surfels, surfAlloc; Tempest::StorageImage irrImage; - Tempest::StorageImage surfCnts, surfBins; - Tempest::StorageBuffer surfList, surfAlloc, surfDedup; + Tempest::StorageImage surfCnts, surfBins, surfPdf; + Tempest::StorageBuffer surfList, surfDedup; Tempest::StorageImage dbgImage; } surf; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 7ccd59bef..2bf6d05e0 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -199,7 +199,7 @@ void Shaders::compileShaders() { rtPathtrace = device.pipeline(Triangles,state,vs,fs); } - if(Gothic::options().doRayQuery) { + if(isGi1Supported()) { RenderState state; state.setCullFaceMode(RenderState::CullMode::NoCull); state.setZTestMode (RenderState::ZTestMode::Less); @@ -237,7 +237,7 @@ void Shaders::compileShaders() { probeAmbient = device.pipeline(Triangles,state,vs,fs); } - if(true) { + if(isGi2Supported()) { RenderState state; state.setCullFaceMode(RenderState::CullMode::NoCull); state.setZTestMode (RenderState::ZTestMode::Less); @@ -254,7 +254,15 @@ void Shaders::compileShaders() { surfAlloc = computeShader("surf_alloc.comp.sprv"); surfApply = computeShader("surf_apply.comp.sprv"); - surfBinning = computeShader("surf_binning.comp.sprv"); + surfInit2 = computeShader("surf_init2.comp.sprv"); + surfSpawn = computeShader("surf_spawn.comp.sprv"); + surfWeight = computeShader("surf_weight.comp.sprv"); + surfTileWeight = computeShader("surf_tile_weight.comp.sprv"); + surfTileNorm = computeShader("surf_tile_normalize.comp.sprv"); + surfTileDecim = computeShader("surf_tile_decimate.comp.sprv"); + + surfBinningS = computeShader("surf_binning_s.comp.sprv"); + surfBinningA = computeShader("surf_binning_a.comp.sprv"); surfBinClear = computeShader("surf_bin_clear.comp.sprv"); surfBinAlloc = computeShader("surf_bin_alloc.comp.sprv"); @@ -398,6 +406,8 @@ bool Shaders::isGi2Supported() { return false; if(gpu.compute.maxInvocations<256 || !gpu.descriptors.nonUniformIndexing) return false; + if(!gpu.hasStorageFormat(R11G11B10UF) || !gpu.hasStorageFormat(R32F)) + return false; return true; } diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 33cb8a31c..89858abb4 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -89,7 +89,9 @@ class Shaders { // GI-Surf Tempest::RenderPipeline surfDbg; Tempest::ComputePipeline surfInit, surfTiled, surfAlloc; - Tempest::ComputePipeline surfBinClear, surfBinning, surfBinAlloc; + Tempest::ComputePipeline surfBinClear, surfBinningS, surfBinningA, surfBinAlloc; + Tempest::ComputePipeline surfInit2; + Tempest::ComputePipeline surfSpawn, surfWeight, surfTileWeight, surfTileNorm, surfTileDecim; Tempest::ComputePipeline surfApply; Tempest::ComputePipeline surfPathtrace; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 45e0fa6e6..ab2486ebb 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -316,12 +316,20 @@ add_shader(surf_init.comp lighting/surfels/surf_init.comp) add_shader(surf_tiled.comp lighting/surfels/surf_tiled.comp) add_shader(surf_alloc.comp lighting/surfels/surf_alloc.comp) -add_shader(surf_binning.comp lighting/surfels/surf_binning.comp) +add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) + add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) -add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) +add_shader(surf_binning_s.comp lighting/surfels/surf_binning.comp -DSURFEL) +add_shader(surf_binning_a.comp lighting/surfels/surf_binning.comp -DALLOC) + +add_shader(surf_init2.comp lighting/surfels/surf_init2.comp) +add_shader(surf_spawn.comp lighting/surfels/surf_spawn.comp) +add_shader(surf_weight.comp lighting/surfels/surf_weight.comp) +add_shader(surf_tile_weight.comp lighting/surfels/surf_tile_weight.comp) +add_shader(surf_tile_normalize.comp lighting/surfels/surf_tile_normalize.comp) +add_shader(surf_tile_decimate.comp lighting/surfels/surf_tile_decimate.comp) -add_shader(surf_enlist.comp lighting/surfels/surf_enlist.comp) add_shader(surf_pathtrace.comp lighting/surfels/surf_pathtrace.comp) # Pathtracing diff --git a/shader/lighting/surfels/surf_binning.comp b/shader/lighting/surfels/surf_binning.comp index 67dbeab3e..796bb2dba 100644 --- a/shader/lighting/surfels/surf_binning.comp +++ b/shader/lighting/surfels/surf_binning.comp @@ -13,8 +13,15 @@ layout(std140, push_constant) uniform Push { layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; + +#if defined(SURFEL) layout(binding = 1, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 2, r32ui) uniform uimage2D surfCnts; +#elif defined(ALLOC) +layout(binding = 1, std430) readonly buffer SB0 { uvec4 count; Candidate surfels[]; }; +#else +#error "Unknown shader varriant" +#endif +layout(binding = 2, r32ui) uniform uimage2D surfCnts; layout(binding = 3, r32ui) uniform readonly uimage2D surfBins; layout(binding = 4, std430) buffer SB1 { uint surfelIds[]; }; @@ -68,6 +75,7 @@ void main() { if(surfelId>=count.x) return; +#if defined(SURFEL) const Surfel p = surfels[surfelId]; const vec4 pos4 = scene.viewProject * vec4(p.pos, 1.0); const vec2 posNdc = ((pos4.xy/pos4.w)*0.5+0.5); @@ -76,11 +84,15 @@ void main() { const float rMax = pixelToWorld(DefaultCoverage, pos4.z/pos4.w); const float radiusMean = max(rMin, min(p.radiusMean, rMax)); const int radiusPix = DefaultCoverage; //min(worldToPixel(p.pos, p.radiusMean), DefaultCoverage); - surfels[surfelId].fragCoord = fragCoord; surfels[surfelId].radiusPix = radiusPix; surfels[surfelId].radius = rMax; surfels[surfelId].radiusMean = radiusMean; +#else + const Candidate p = surfels[surfelId]; + const ivec2 fragCoord = p.fragCoord; + const int radiusPix = DefaultCoverage; +#endif ivec2 pos0 = ivec2(fragCoord-radiusPix)/tileSize; ivec2 pos1 = ivec2(fragCoord+radiusPix)/tileSize + 1; diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 91ef18c46..275d0d9bb 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -23,6 +23,15 @@ struct SurfelAlloc { uint reuseId; }; +struct Candidate { + vec3 pos; + float radius; + vec3 norm; + float weight; + ivec2 fragCoord; + ivec2 padd0; + }; + bool isSurfelVisible(const Surfel s, ivec2 bboxMin, ivec2 bboxMax) { const ivec2 at = s.fragCoord; const int radius = s.radiusPix; diff --git a/shader/lighting/surfels/surf_dbg.frag b/shader/lighting/surfels/surf_dbg.frag index a7cf533c1..a596a90e7 100644 --- a/shader/lighting/surfels/surf_dbg.frag +++ b/shader/lighting/surfels/surf_dbg.frag @@ -43,7 +43,11 @@ void main(void) { if(length(delta) > radius) ;//discard; - vec3 clr = surfDebugColor(p, instanceIndex) * (1.0-qDist); + //vec3 clr = surfDebugColor(p, instanceIndex) * (1.0-qDist); + //vec3 clr = vec3(1.0 / max(p.irradiance.r,1)) * (1.0-qDist); + const float weight = p.irradiance.r; //exp(-p.irradiance.r/64.0); + vec3 clr = vec3(mix(vec3(1,1,1), vec3(0,0,1), weight)) * (1.0-qDist); + //vec3 clr = vec3(mix(vec3(1,1,1), vec3(0,0,1), 64.0 / max(p.irradiance.r,0.1))) * (1.0-qDist); //vec3 clr = 3.0 * p.irradiance * (1.0-qDist) * scene.exposure; outColor = vec4(clr,1.0); // outColor = vec4(1,0,0,1.0); diff --git a/shader/lighting/surfels/surf_enlist.comp b/shader/lighting/surfels/surf_enlist.comp deleted file mode 100644 index cb1bf8e23..000000000 --- a/shader/lighting/surfels/surf_enlist.comp +++ /dev/null @@ -1,14 +0,0 @@ -#version 460 - -layout(local_size_x = 64) in; - -#include "lighting/surfels/surf_common.glsl" - -const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; - -layout(binding = 0, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; - -void main() { - const Surfel p = surfels[gl_GlobalInvocationID.x]; - - } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_init2.comp b/shader/lighting/surfels/surf_init2.comp new file mode 100644 index 000000000..0f6095ece --- /dev/null +++ b/shader/lighting/surfels/surf_init2.comp @@ -0,0 +1,11 @@ +#version 450 + +layout(local_size_x = 1) in; + +layout(binding = 4, std430) buffer SB0 { uvec4 count; } surf; +layout(binding = 5, std430) buffer SB2 { uvec4 count; } alloc; + +void main() { + surf. count = uvec4(0,1,1,0); + alloc.count = uvec4(0,1,1,0); + } diff --git a/shader/lighting/surfels/surf_spawn.comp b/shader/lighting/surfels/surf_spawn.comp new file mode 100644 index 000000000..ce59de545 --- /dev/null +++ b/shader/lighting/surfels/surf_spawn.comp @@ -0,0 +1,124 @@ +#version 460 + +#extension GL_EXT_shader_explicit_arithmetic_types_int32 : enable + +layout(local_size_x = 16, local_size_y = 16) in; + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + +const float NormalBias = 0.0030; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1) uniform sampler2D gbufDiffuse; +layout(binding = 2) uniform usampler2D gbufNormal; +layout(binding = 3) uniform sampler2D depth; +layout(binding = 4, std430) readonly buffer SB1 { uvec4 count; Surfel surfels[]; } surf; +layout(binding = 5, std430) buffer SB0 { uvec4 count; Candidate candidate[]; } alloc; +// +layout(binding = 11, rgba8) uniform image2D dbgImage; + +shared uint32_t fragVote; + +uint32_t packVote(uint weight, uint32_t key) { + uint32_t w = (weight << 16) & 0xFFFF0000; + return uint32_t(w) | uint32_t(key & 0x0000FFFF); + } + +uint32_t unpackVoteKey(uint vote) { + return uint32_t(vote & 0x0000FFFF); + } + +uint wangHashNoise(uvec2 uv, uint s) { + uint seed = (uv.x*1664525u + uv.y) + s; + uint hash = wangHash(seed) & 0xFFFF; + return hash; + //float value = float(hash) / float(0xFFFF); + //return value; + } + +uint hash3(uvec3 p) { + p = p * 1664525u + 1013904223u; + + p.x += p.y * p.z; + p.y += p.z * p.x; + p.z += p.x * p.y; + + p ^= p >> 16u; + + p.x += p.y * p.z; + p.y += p.z * p.x; + p.z += p.x * p.y; + + return p.x ^ p.y ^ p.z; + } + +vec3 worldPos(float z, vec3 normal, ivec2 fragCoord, ivec2 screenSize) { + const mat4 inv = scene.viewProjectLwcInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return (pos.xyz + normal*NormalBias)/pos.w + originLwc; + } + +float pixelToWorld(float pixelRadius, float z) { + z = linearDepth(z, scene.clipInfo); + + float clipRadiusX = (2.0 * pixelRadius) * scene.screenResInv.x; + float clipRadiusY = (2.0 * pixelRadius) * scene.screenResInv.y; + + float worldRadiusX = (clipRadiusX * z) / scene.project[0][0]; + float worldRadiusY = (clipRadiusY * z) / scene.project[1][1]; + return min(worldRadiusX, worldRadiusY); + } + +void main() { + const uint laneID = gl_LocalInvocationIndex; + + fragVote = packVote(0xFFFF, 0xFFFF); + barrier(); + + const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); + const ivec2 screenSize = ivec2(textureSize(depth,0)); + const bool valid = all(lessThan(fragCoord, screenSize)); + + // const ivec2 tileId = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy)/int(tileSize); + // const uint cnt = imageLoad(surfCnts, tileId).x; + // const uint ptr = imageLoad(surfBins, tileId).x; + + const float z = valid ? texelFetch(depth,fragCoord,0).x : 1; + const vec3 norm = normalFetch(gbufNormal, fragCoord); + const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); + const bool sky = (z >= SKY_DEPTH); + + if(!sky) { + const uint rand = wangHashNoise(fragCoord, 0); + // const uint rand = hash3(uvec3(wpos/1.0)); + atomicMin(fragVote, packVote(rand, gl_LocalInvocationIndex)); + imageStore(dbgImage, fragCoord, vec4(float(rand)/float(0xFFFF))); + } + barrier(); + + if(unpackVoteKey(fragVote)!=gl_LocalInvocationIndex) + return; + + const uint surfelId = atomicAdd(alloc.count.x,1); + + Candidate sx; + sx.pos = wpos; + sx.norm = norm; + sx.radius = pixelToWorld(DefaultCoverage, z); + sx.fragCoord = fragCoord; + + //sx.radiusMean = sx.radius; + //sx.radiusPix = DefaultCoverage; + //sx.irradiance = surfDebugColor(wpos, surfelId); + + alloc.candidate[surfelId] = sx; + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_tile_decimate.comp b/shader/lighting/surfels/surf_tile_decimate.comp new file mode 100644 index 000000000..e25c15f39 --- /dev/null +++ b/shader/lighting/surfels/surf_tile_decimate.comp @@ -0,0 +1,153 @@ +#version 460 + +#include "lighting/surfels/surf_common.glsl" + +layout(local_size_x = 128) in; + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; +const int MaxSurfels = 2048; +const int Quota = 3; + +struct Item { + float weight; + uint idx; + }; + +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5, std430) readonly buffer SB1 { uvec4 count; Candidate candidate[]; } alloc; +layout(binding = 6, std430) readonly buffer SB2 { uint surfelList[]; }; +layout(binding = 7, r32ui) uniform uimage2D surfCnts; +layout(binding = 8, r32ui) uniform uimage2D surfBins; +layout(binding = 9, r32f) uniform image2D surfPdf; + +shared uint wId; +shared Item data[128]; + +uint nextPowerOfTwo(uint x) { + if(x <= 1u) + return 1u; + return 1u << (findMSB(x - 1u) + 1); + } + +void swap(inout Item a, inout Item b) { + Item t = a; + a = b; + b = t; + } + +void bitonicSort(uint count) { + uint laneID = gl_LocalInvocationIndex; + + count = nextPowerOfTwo(count); + + for(uint k = 2; k <= count; k <<= 1) { + for(uint j = k >> 1; j > 0; j >>= 1) { + uint ixj = laneID ^ j; + + if(ixj > laneID) { + bool ascending = !((laneID & k) == 0); + + float a = data[laneID].weight; + float b = data[ixj ].weight; + + const bool swapNeeded = ascending ? (a > b) : (a < b); + if(swapNeeded) + swap(data[laneID], data[ixj]); + } + + barrier(); + } + } + } + +void allocateAll() { + const uint laneID = gl_LocalInvocationIndex; + + const ivec2 tileId = ivec2(gl_WorkGroupID.xy); + const uint cnt = imageLoad(surfCnts, tileId).x; + const uint ptr = imageLoad(surfBins, tileId).x; + + wId = 0; + barrier(); + + for(uint i=laneID; i=surfels.length()) + continue; + + Surfel sx; + sx.pos = p.pos; + sx.norm = encodeNormal(p.norm); + sx.radius = p.radius; + sx.radiusPix = DefaultCoverage; + sx.irradiance = vec3(p.weight); // surfDebugColor(p.pos, surfelId); + + surfels[surfelId] = sx; + } + } + +void main() { + const uint laneID = gl_LocalInvocationIndex; + const ivec2 imgSize = imageSize(surfPdf); + const int numTiles = imgSize.x*imgSize.y; + const int maxSurfels = max(MaxSurfels-numTiles*Quota, 0); + + const ivec2 tileId = ivec2(gl_WorkGroupID.xy); + const uint cnt = imageLoad(surfCnts, tileId).x; + const uint ptr = imageLoad(surfBins, tileId).x; + + const int cntAlloc = int(imageLoad(surfPdf, tileId).x * maxSurfels) + Quota; + //allocateAll(); + //return; + + wId = 0; + for(uint i=laneID; i=data.length()) + continue; + + data[num].weight = p.weight; + data[num].idx = sId; + } + barrier(); + + bitonicSort(min(wId, data.length())); + barrier(); + + for(uint i=laneID; i< cnt && i=surfels.length()) + continue; + + const Candidate p = alloc.candidate[data[i].idx]; + Surfel sx; + sx.pos = p.pos; + sx.norm = encodeNormal(p.norm); + sx.radius = p.radius; + sx.radiusPix = DefaultCoverage; + sx.irradiance = vec3(p.weight); // surfDebugColor(p.pos, surfelId); + + surfels[surfelId] = sx; + } + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_tile_normalize.comp b/shader/lighting/surfels/surf_tile_normalize.comp new file mode 100644 index 000000000..fe3d50a4e --- /dev/null +++ b/shader/lighting/surfels/surf_tile_normalize.comp @@ -0,0 +1,49 @@ +#version 460 + +#include "lighting/surfels/surf_common.glsl" + +layout(local_size_x = 256) in; + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + +layout(binding = 7, r32ui) uniform uimage2D surfCnts; +layout(binding = 8, r32ui) uniform uimage2D surfBins; +layout(binding = 9, r32f) uniform image2D surfPdf; + +shared float reduction[NumThreads]; + +void reducePdf(float w) { + uint laneID = gl_LocalInvocationIndex; + + reduction[laneID] = w; + barrier(); + + for(uint stride = NumThreads/2; stride > 0; stride >>= 1) { + if(laneID < stride) { + reduction[laneID] += reduction[laneID + stride]; + } + barrier(); + } + } + +void main() { + const ivec2 imgSize = imageSize(surfPdf); + const int numTiles = imgSize.x*imgSize.y; + + float pdfSum = 0; + for(uint i=gl_LocalInvocationIndex; i 0; stride >>= 1) { + barrier(); + if(laneID < stride) { + reduction[laneID] += reduction[laneID + stride]; + } + } + } + +void main() { + const ivec2 tileId = ivec2(gl_WorkGroupID.xy); + const uint cnt = imageLoad(surfCnts, tileId).x; + const uint ptr = imageLoad(surfBins, tileId).x; + + float wSum = 0; + for(uint i=gl_LocalInvocationIndex; i 0; stride >>= 1) { + if(laneID < stride) { + reduction[laneID] += reduction[laneID + stride]; + } + barrier(); + } + } + +void main() { + const uint surfelId = gl_WorkGroupID.x; + const Candidate p = alloc.candidate[surfelId]; + const vec3 wpos = p.pos; + const vec3 norm = p.norm; + + const ivec2 tileId = p.fragCoord/int(tileSize); + const uint cnt = imageLoad(surfCnts, tileId).x; + const uint ptr = imageLoad(surfBins, tileId).x; + + float wSum = 0; + for(uint i=gl_LocalInvocationIndex; i Date: Wed, 24 Jun 2026 22:14:09 +0200 Subject: [PATCH 38/52] progress --- game/graphics/renderer.cpp | 35 ++++++++++++---- .../lighting/surfels/surf_tile_decimate.comp | 40 +++++++++++++------ shader/lighting/surfels/surf_weight.comp | 28 ++++++++++++- 3 files changed, 81 insertions(+), 22 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 0e95676b7..1ce833b35 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -571,7 +571,7 @@ void Renderer::draw(Encoder& cmd, uint8_t cmdId, size_t imgId, } void Renderer::dbgDraw(Tempest::Painter& p) { - static bool dbg = false; + static bool dbg = true; if(!dbg) return; @@ -1945,7 +1945,7 @@ void Renderer::prepareEpipolar(Tempest::Encoder& cmd, Wo cmd.dispatch(uint32_t(epTrace.h())); } -void Renderer::prepareSurfels(Tempest::Encoder& cmd, WorldView& wview) { +void Renderer::prepareSurfels2(Tempest::Encoder& cmd, WorldView& wview) { static bool enable = true; if(!enable) return; @@ -1986,8 +1986,8 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor //TODO: apply pass 1 } - static bool alloc = true; - if(alloc) { + static bool spawn = true; + if(spawn) { //alloc = false; cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); @@ -2008,7 +2008,8 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor surfelsBinning(cmd, wview, tileSize, true); - if(true) { + static bool alloc = true; + if(alloc) { cmd.setPushData(push); cmd.setBinding(4, surfels); cmd.setBinding(5, surfAlloc); @@ -2029,6 +2030,26 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatch(binCount); } + static bool rays = false; + if(rays) { + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, surfels); + cmd.setBinding(2, sky.viewCldLut); + // + cmd.setBinding(6, scene.rtScene.tlas); + cmd.setBinding(7, Sampler::trillinear()); + cmd.setBinding(8, scene.rtScene.tex); + cmd.setBinding(9, scene.rtScene.vbo); + cmd.setBinding(10,scene.rtScene.ibo); + cmd.setBinding(11,scene.rtScene.rtDesc); + + cmd.setPipeline(shaders.surfPathtrace); + //cmd.dispatchThreads(maxSurfels); + cmd.dispatchIndirect(surfels, 0); + } + + surfelsBinning(cmd, wview, tileSize, false); + if(apply) { cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); @@ -2048,7 +2069,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor } } -void Renderer::prepareSurfels2(Tempest::Encoder& cmd, WorldView& wview) { +void Renderer::prepareSurfels(Tempest::Encoder& cmd, WorldView& wview) { static bool enable = true; if(!enable) return; @@ -2144,7 +2165,7 @@ void Renderer::prepareSurfels2(Tempest::Encoder& cmd, Wo surfelsBinning(cmd, wview, tileSize, false); } - static bool apply = false; + static bool apply = true; if(apply) { //cmd.setDebugMarker("Surfels: resolve"); cmd.setPushData(push); diff --git a/shader/lighting/surfels/surf_tile_decimate.comp b/shader/lighting/surfels/surf_tile_decimate.comp index e25c15f39..6d379552c 100644 --- a/shader/lighting/surfels/surf_tile_decimate.comp +++ b/shader/lighting/surfels/surf_tile_decimate.comp @@ -6,7 +6,7 @@ layout(local_size_x = 128) in; const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; const int MaxSurfels = 2048; -const int Quota = 3; +const int Quota = 16; struct Item { float weight; @@ -20,7 +20,7 @@ layout(binding = 7, r32ui) uniform uimage2D surfCnts; layout(binding = 8, r32ui) uniform uimage2D surfBins; layout(binding = 9, r32f) uniform image2D surfPdf; -shared uint wId; +shared uint dataSize; shared Item data[128]; uint nextPowerOfTwo(uint x) { @@ -67,9 +67,6 @@ void allocateAll() { const uint cnt = imageLoad(surfCnts, tileId).x; const uint ptr = imageLoad(surfBins, tileId).x; - wId = 0; - barrier(); - for(uint i=laneID; i=data.length()) continue; - data[num].weight = p.weight; + data[num].weight = stableWeight(p.weight, p.fragCoord); data[num].idx = sId; } barrier(); - bitonicSort(min(wId, data.length())); + if(laneID==0) + dataSize = min(dataSize, data.length()); + barrier(); + + bitonicSort(dataSize); barrier(); - for(uint i=laneID; i< cnt && i Date: Thu, 25 Jun 2026 20:56:47 +0200 Subject: [PATCH 39/52] 2-pass surfel allocator initial --- game/graphics/renderer.cpp | 131 ++++++++++++-- game/graphics/renderer.h | 1 + game/graphics/shaders.cpp | 4 + game/graphics/shaders.h | 2 + shader/CMakeLists.txt | 4 + shader/lighting/surfels/surf_alloc2.comp | 206 ++++++++++++++++++++++ shader/lighting/surfels/surf_apply2.comp | 114 ++++++++++++ shader/lighting/surfels/surf_compact.comp | 45 +++++ 8 files changed, 489 insertions(+), 18 deletions(-) create mode 100644 shader/lighting/surfels/surf_alloc2.comp create mode 100644 shader/lighting/surfels/surf_apply2.comp create mode 100644 shader/lighting/surfels/surf_compact.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 1ce833b35..34ecef63c 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1945,6 +1945,111 @@ void Renderer::prepareEpipolar(Tempest::Encoder& cmd, Wo cmd.dispatch(uint32_t(epTrace.h())); } +void Renderer::prepareSurfels(Tempest::Encoder& cmd, WorldView& wview) { + static bool enable = true; + if(!enable) + return; + + if(settings.giMethod!=GiMethod::IrrC) + return; + + const uint32_t maxSurfels = surf.maxSurfels; + const uint32_t maxAlloc = maxSurfels * 16; + const int32_t tileSize = 128; + const int32_t DefaultCoverage = 128; + const auto binCount = tileCount(zbuffer.size(), DefaultCoverage); + + auto& scene = wview.sceneGlobals(); + auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); + auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::RGBA16F, zbuffer.size()); + (void)irrImage; + + auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc2.sizeofBuffer(4, maxSurfels)); + auto& surfAlloc = usesSsboInit(surf.surfAlloc, shaders.surfAlloc2.sizeofBuffer(5, maxAlloc)); + auto& surfUsage = usesSsboInit(surf.surfDedup, (maxSurfels+32-1)/32); //TODO: naming + + auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); + auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); + auto& surfList = usesSsbo (surf.surfList, 16*maxSurfels*sizeof(uint32_t)); + + struct Push { + Vec3 originLwc; + uint32_t tileSize; + } push = {}; + push.originLwc = scene.originLwc; + push.tileSize = uint32_t(tileSize); + + cmd.setDebugMarker("Surfels"); + + // prev-frame + surfelsBinning(cmd, wview, tileSize, false); + + static bool apply = true; + if(apply) { + // apply = false; + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, irrImage, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, surfUsage); + cmd.setBinding(6, surfCnts); + cmd.setBinding(7, surfBins); + cmd.setBinding(8, surfList); + // + cmd.setBinding(11, dbgImage); + + cmd.setPipeline(shaders.surfApply2); + cmd.dispatchThreads(zbuffer.size()); + + cmd.setPipeline(shaders.surfCompact); + cmd.dispatch(1); + } + + static bool alloc = true; + if(alloc) { + // alloc = false; + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, irrImage, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, surfAlloc); + cmd.setBinding(6, surfCnts); + cmd.setBinding(7, surfBins); + cmd.setBinding(8, surfList); + // + cmd.setBinding(11, dbgImage); + + //cmd.setPipeline(shaders.surfInit2); + //cmd.dispatchThreads(1); //for sake of zeroing counters + + const auto tc = tileCount(zbuffer.size(), 128); + cmd.setPipeline(shaders.surfAlloc2); + cmd.dispatch(tc); + } + + static bool rays = true; + if(rays) { + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, surfels); + cmd.setBinding(2, sky.viewCldLut); + // + cmd.setBinding(6, scene.rtScene.tlas); + cmd.setBinding(7, Sampler::trillinear()); + cmd.setBinding(8, scene.rtScene.tex); + cmd.setBinding(9, scene.rtScene.vbo); + cmd.setBinding(10,scene.rtScene.ibo); + cmd.setBinding(11,scene.rtScene.rtDesc); + + cmd.setPipeline(shaders.surfPathtrace); + //cmd.dispatchThreads(maxSurfels); + cmd.dispatchIndirect(surfels, 0); + } + } + void Renderer::prepareSurfels2(Tempest::Encoder& cmd, WorldView& wview) { static bool enable = true; if(!enable) @@ -2069,7 +2174,7 @@ void Renderer::prepareSurfels2(Tempest::Encoder& cmd, Wo } } -void Renderer::prepareSurfels(Tempest::Encoder& cmd, WorldView& wview) { +void Renderer::prepareSurfels3(Tempest::Encoder& cmd, WorldView& wview) { static bool enable = true; if(!enable) return; @@ -2096,14 +2201,6 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); - cmd.setDebugMarker("Surfels"); - static bool binning = true; - if(binning) { - // prev-frame - //cmd.setDebugMarker("Surfels: binning"); - surfelsBinning(cmd, wview, tileSize, false); - } - struct Push { Vec3 originLwc; uint32_t tileSize; @@ -2111,7 +2208,10 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor push.originLwc = scene.originLwc; push.tileSize = uint32_t(tileSize); - //cmd.setDebugMarker("Surfels"); + cmd.setDebugMarker("Surfels"); + // prev-frame + surfelsBinning(cmd, wview, tileSize, false); + static bool alloc = true; if(alloc) { cmd.setPushData(push); @@ -2141,7 +2241,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor //alloc = false; } - static bool rays = false; + static bool rays = true; if(rays) { cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, surfels); @@ -2159,15 +2259,10 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatchIndirect(surfels, 0); } - if(binning) { - // current frame - //cmd.setDebugMarker("Surfels: binning"); - surfelsBinning(cmd, wview, tileSize, false); - } + surfelsBinning(cmd, wview, tileSize, false); - static bool apply = true; + static bool apply = false; if(apply) { - //cmd.setDebugMarker("Surfels: resolve"); cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index deab6793b..aec882628 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -67,6 +67,7 @@ class Renderer final { void prepareSurfels (Tempest::Encoder& cmd, WorldView& wview); void prepareSurfels2 (Tempest::Encoder& cmd, WorldView& wview); + void prepareSurfels3 (Tempest::Encoder& cmd, WorldView& wview); void surfelsBinning (Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool alloc); void drawHiZ (Tempest::Encoder& cmd, WorldView& view); diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 2bf6d05e0..f626c5187 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -266,6 +266,10 @@ void Shaders::compileShaders() { surfBinClear = computeShader("surf_bin_clear.comp.sprv"); surfBinAlloc = computeShader("surf_bin_alloc.comp.sprv"); + surfAlloc2 = computeShader("surf_alloc2.comp.sprv"); + surfApply2 = computeShader("surf_apply2.comp.sprv"); + surfCompact = computeShader("surf_compact.comp.sprv"); + surfPathtrace = computeShader("surf_pathtrace.comp.sprv"); } diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 89858abb4..a8f79d819 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -95,6 +95,8 @@ class Shaders { Tempest::ComputePipeline surfApply; Tempest::ComputePipeline surfPathtrace; + Tempest::ComputePipeline surfAlloc2, surfApply2, surfCompact; + // Epipolar Tempest::ComputePipeline fogEpipolarVsm; Tempest::ComputePipeline fogEpipolarOcclusion; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index ab2486ebb..1674c5765 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -330,6 +330,10 @@ add_shader(surf_tile_weight.comp lighting/surfels/surf_tile_weight.comp) add_shader(surf_tile_normalize.comp lighting/surfels/surf_tile_normalize.comp) add_shader(surf_tile_decimate.comp lighting/surfels/surf_tile_decimate.comp) +add_shader(surf_alloc2.comp lighting/surfels/surf_alloc2.comp) +add_shader(surf_apply2.comp lighting/surfels/surf_apply2.comp) +add_shader(surf_compact.comp lighting/surfels/surf_compact.comp) + add_shader(surf_pathtrace.comp lighting/surfels/surf_pathtrace.comp) # Pathtracing diff --git a/shader/lighting/surfels/surf_alloc2.comp b/shader/lighting/surfels/surf_alloc2.comp new file mode 100644 index 000000000..930704017 --- /dev/null +++ b/shader/lighting/surfels/surf_alloc2.comp @@ -0,0 +1,206 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 16, local_size_y = 16) in; + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + +const ivec2 TileSize = ivec2(128); +const float NormalBias = 0.0030; +const uint Salt = 0x9D; +const float Edge = 0.1; +const float MaxAttempts = 1; +const int MaxQueue = 256; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1) uniform texture2D irradiance; +layout(binding = 2) uniform utexture2D gbufNormal; +layout(binding = 3) uniform texture2D depth; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; } surf; +// +layout(binding = 6, r32ui) uniform uimage2D surfCnts; +layout(binding = 7, r32ui) uniform uimage2D surfBins; +layout(binding = 8, std430) readonly buffer SB2 { uint surfelList[]; }; +// +layout(binding = 11, rgba8) uniform image2D dbgImage; + +shared SurfelAlloc pointQueue[MaxQueue]; +shared float pointRMax [MaxQueue]; +shared int pointQueueSize; + +shared uint fragVote; + +vec3 worldPos(float z, vec3 normal, ivec2 fragCoord, ivec2 screenSize) { + const mat4 inv = scene.viewProjectLwcInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return (pos.xyz + normal*NormalBias)/pos.w + originLwc; + } + +float pixelToWorld(float pixelRadius, float z) { + z = linearDepth(z, scene.clipInfo); + + float clipRadiusX = (2.0 * pixelRadius) * scene.screenResInv.x; + float clipRadiusY = (2.0 * pixelRadius) * scene.screenResInv.y; + + float worldRadiusX = (clipRadiusX * z) / scene.project[0][0]; + float worldRadiusY = (clipRadiusY * z) / scene.project[1][1]; + return min(worldRadiusX, worldRadiusY); + } + +float calculteWeight(const SurfelAlloc s, float rMax, const vec3 wpos, const vec3 norm) { + return calculteWeight(s.pos.xyz, s.norm, s.pos.w, rMax, wpos, norm); + } + +float amendCoverage(const ivec2 fragCoord, const vec3 wpos, const vec3 norm) { + const int i = pointQueueSize-1; + const SurfelAlloc s = pointQueue[i]; + return calculteWeight(s,pointRMax[i],wpos,norm); + } + +float estimateCoverage(const ivec2 fragCoord, const vec3 wpos, const vec3 norm, const uint accounted) { + float wSum = texelFetch(irradiance, fragCoord, 0).a; + if(wSum>1.0) + return 1.0; + + for(int i=pointQueueSize; i>accounted;) { + --i; + const SurfelAlloc s = pointQueue[i]; + wSum += calculteWeight(s,pointRMax[i],wpos,norm); + if(wSum > 1.0) + return 1.0; + } + return wSum; + } + +void fragCoverageVote(float wSum) { + uint w = floatBitsToUint(wSum) & 0xFFFF0000; + uint b = uint(w) | uint(gl_LocalInvocationIndex) ^ Salt; + atomicMin(fragVote, b); + } + +void storeSurfels() { + const uint laneID = gl_LocalInvocationIndex; + + if(laneID==0) { + pointQueueSize = min(pointQueueSize, pointQueue.length()); + fragVote = atomicAdd(surf.count.x, pointQueueSize); + } + barrier(); + + if(laneID= SKY_DEPTH); + + const vec3 norm = normalFetch(gbufNormal, fragCoord); + const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); + + float coverage = (sky ? 1.0 : estimateCoverage(fragCoord, wpos, norm, 0)); + + for(int i=0; i=pointQueue.length()) + break; + + if(coverage<1.0) + fragCoverageVote(coverage); + barrier(); + + const uint vote = fragVote; + barrier(); + + fragVote = 0xFFFFFFFF; + if((vote & 0xFFFF0000)==0xFFFF0000) + break; + + allocSurfel(at, screenSize, vote); + barrier(); + + coverage += amendCoverage(fragCoord, wpos, norm); + } + + imageStore(dbgImage, fragCoord, vec4(coverage)); + } + +ivec2 remap(ivec2 subtile, ivec2 tileCnt) { + // shuffle sub-tiles a little + uint k = uint(subtile.y * tileCnt.x + subtile.x); + k ^= 0x12; + k &= uint(NumThreads-1); + return ivec2(int(k % tileCnt.x), int(k / tileCnt.x)); + } + +void main() { +#if 0 + if(gl_WorkGroupID.xy!=uvec2(8,5) && gl_WorkGroupID.xy!=uvec2(8,6)) + return; +#endif + + if(!(7 < gl_WorkGroupID.x && gl_WorkGroupID.x<=9 && + 3 < gl_WorkGroupID.y && gl_WorkGroupID.y<=6)) + ;//return; + + pointQueueSize = 0; + fragVote = 0xFFFFFFFF; + barrier(); + + const ivec2 screenSize = ivec2(textureSize(depth,0)); + const ivec2 tileCount = TileSize/ivec2(gl_WorkGroupSize.xy); + for(int y=0; y= SKY_DEPTH); + + ivec2 bboxMin = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy); + ivec2 bboxMax = bboxMin + ivec2(gl_WorkGroupSize.xy); + + vec4 clr = vec4(0); + for(uint i=0; ; i+=NumThreads) { + surfelCount = 0; + barrier(); + + if(i+laneID < cnt) { + const uint sId = surfelList[ptr+i+laneID]; + const Surfel s = surfels[sId]; + + if(isSurfelVisible(s, bboxMin, bboxMax)) { + const uint id = atomicAdd(surfelCount, 1); + surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); + surfelsNorm[id] = vec4(decodeNormal(s.norm), s.radius); + surfelsIrr [id] = vec4(s.irradiance, s.radiusMean); + surfelsUse [id] = sId; + } + } + barrier(); + + if(!sky) { + applyBatch(clr, wpos, norm, surfelCount); + } + + if(i+NumThreads>=cnt) + break; + barrier(); + } + + if(!valid || sky) { + imageStore(irradiance, fragCoord, vec4(0,0,0,1)); + imageStore(dbgImage, fragCoord, vec4(1)); + return; + } + + if(clr.a>0) + clr.rgb /= clr.a; + clr.rgb *= scene.exposure; + + imageStore(irradiance, fragCoord, vec4(clr.rgb, clr.a)); + imageStore(dbgImage, fragCoord, vec4(clr.a)); + } diff --git a/shader/lighting/surfels/surf_compact.comp b/shader/lighting/surfels/surf_compact.comp new file mode 100644 index 000000000..df882f958 --- /dev/null +++ b/shader/lighting/surfels/surf_compact.comp @@ -0,0 +1,45 @@ +#version 450 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 256) in; + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5, std430) buffer SB1 { uint usage[]; }; + +shared uint wPtr; + +void main() { + const uint laneID = gl_LocalInvocationIndex; + + wPtr = 0; + barrier(); + + Surfel sx; + for(uint ix=0; ix Date: Fri, 26 Jun 2026 00:22:14 +0200 Subject: [PATCH 40/52] progress --- game/graphics/renderer.cpp | 52 +++++++++----- game/graphics/renderer.h | 3 +- game/graphics/shaders.cpp | 1 + game/graphics/shaders.h | 2 +- shader/CMakeLists.txt | 1 + shader/lighting/surfels/surf_alloc2.comp | 9 +-- shader/lighting/surfels/surf_apply2.comp | 14 +++- shader/lighting/surfels/surf_bin_alloc.comp | 10 +-- shader/lighting/surfels/surf_bin_clear.comp | 8 +-- shader/lighting/surfels/surf_bin_sort.comp | 79 +++++++++++++++++++++ shader/lighting/surfels/surf_binning.comp | 12 ++-- shader/lighting/surfels/surf_compact.comp | 11 +-- shader/lighting/surfels/surf_dbg.frag | 5 +- 13 files changed, 156 insertions(+), 51 deletions(-) create mode 100644 shader/lighting/surfels/surf_bin_sort.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 34ecef63c..074dd49d0 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1954,26 +1954,24 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor return; const uint32_t maxSurfels = surf.maxSurfels; - const uint32_t maxAlloc = maxSurfels * 16; + const uint32_t usageWords = (maxSurfels+32-1)/32; const int32_t tileSize = 128; const int32_t DefaultCoverage = 128; const auto binCount = tileCount(zbuffer.size(), DefaultCoverage); - auto& scene = wview.sceneGlobals(); - auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); - auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::RGBA16F, zbuffer.size()); - (void)irrImage; + auto& scene = wview.sceneGlobals(); + auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); + auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::RGBA16F, zbuffer.size()); - auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc2.sizeofBuffer(4, maxSurfels)); - auto& surfAlloc = usesSsboInit(surf.surfAlloc, shaders.surfAlloc2.sizeofBuffer(5, maxAlloc)); - auto& surfUsage = usesSsboInit(surf.surfDedup, (maxSurfels+32-1)/32); //TODO: naming + auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc2.sizeofBuffer(4, maxSurfels)); + auto& surfUsage = usesSsboInit(surf.surfUsage, usageWords*sizeof(uint32_t)); - auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); - auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); - auto& surfList = usesSsbo (surf.surfList, 16*maxSurfels*sizeof(uint32_t)); + auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); + auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); + auto& surfList = usesSsbo (surf.surfList, 16*maxSurfels*sizeof(uint32_t)); struct Push { - Vec3 originLwc; + Vec3 originLwc; uint32_t tileSize; } push = {}; push.originLwc = scene.originLwc; @@ -1982,8 +1980,17 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setDebugMarker("Surfels"); // prev-frame + { surfelsBinning(cmd, wview, tileSize, false); + cmd.setBinding(3, surfCnts); + cmd.setBinding(4, surfBins); + cmd.setBinding(5, surfList); + + cmd.setPipeline(shaders.surfBinSort); // assist with stable GC + cmd.dispatch(surfBins.size()); + } + static bool apply = true; if(apply) { // apply = false; @@ -2016,7 +2023,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setBinding(2, gbufNormal, Sampler::nearest()); cmd.setBinding(3, zbuffer, Sampler::nearest()); cmd.setBinding(4, surfels); - cmd.setBinding(5, surfAlloc); + // cmd.setBinding(6, surfCnts); cmd.setBinding(7, surfBins); cmd.setBinding(8, surfList); @@ -2031,7 +2038,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatch(tc); } - static bool rays = true; + static bool rays = false; if(rays) { cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, surfels); @@ -2046,7 +2053,12 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setPipeline(shaders.surfPathtrace); //cmd.dispatchThreads(maxSurfels); - cmd.dispatchIndirect(surfels, 0); + cmd.dispatchIndirect(surfels, 0); //NOTE: need to split into old/new + } + //surfelsBinning(cmd, wview, tileSize, false); + + if(apply) { + //TODO: patch pass } } @@ -2286,6 +2298,7 @@ void Renderer::surfelsBinning(Tempest::Encoder& cmd, Wor auto& scene = wview.sceneGlobals(); auto& surfels = alloc ? surf.surfAlloc : surf.surfels; + auto& binCtrl = usesSsboInit(surf.binCtrl, sizeof(uint32_t)); auto& surfCnts = surf.surfCnts; auto& surfBins = surf.surfBins; auto& surfList = surf.surfList; @@ -2299,10 +2312,11 @@ void Renderer::surfelsBinning(Tempest::Encoder& cmd, Wor cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, surfels); - cmd.setBinding(2, surfCnts); - cmd.setBinding(3, surfBins); - cmd.setBinding(4, surfList); + cmd.setBinding(1, binCtrl); + cmd.setBinding(2, surfels); + cmd.setBinding(3, surfCnts); + cmd.setBinding(4, surfBins); + cmd.setBinding(5, surfList); cmd.setPipeline(shaders.surfBinClear); cmd.dispatchThreads(surfBins.size()); diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index aec882628..f77a53776 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -219,7 +219,8 @@ class Renderer final { Tempest::StorageImage irrImage; Tempest::StorageImage surfCnts, surfBins, surfPdf; - Tempest::StorageBuffer surfList, surfDedup; + Tempest::StorageBuffer binCtrl; + Tempest::StorageBuffer surfList, surfUsage, surfDedup; Tempest::StorageImage dbgImage; } surf; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index f626c5187..da7e5c96b 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -265,6 +265,7 @@ void Shaders::compileShaders() { surfBinningA = computeShader("surf_binning_a.comp.sprv"); surfBinClear = computeShader("surf_bin_clear.comp.sprv"); surfBinAlloc = computeShader("surf_bin_alloc.comp.sprv"); + surfBinSort = computeShader("surf_bin_sort.comp.sprv"); surfAlloc2 = computeShader("surf_alloc2.comp.sprv"); surfApply2 = computeShader("surf_apply2.comp.sprv"); diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index a8f79d819..d1b85c6ce 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -89,7 +89,7 @@ class Shaders { // GI-Surf Tempest::RenderPipeline surfDbg; Tempest::ComputePipeline surfInit, surfTiled, surfAlloc; - Tempest::ComputePipeline surfBinClear, surfBinningS, surfBinningA, surfBinAlloc; + Tempest::ComputePipeline surfBinClear, surfBinningS, surfBinningA, surfBinAlloc, surfBinSort; Tempest::ComputePipeline surfInit2; Tempest::ComputePipeline surfSpawn, surfWeight, surfTileWeight, surfTileNorm, surfTileDecim; Tempest::ComputePipeline surfApply; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 1674c5765..455fad126 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -322,6 +322,7 @@ add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) add_shader(surf_binning_s.comp lighting/surfels/surf_binning.comp -DSURFEL) add_shader(surf_binning_a.comp lighting/surfels/surf_binning.comp -DALLOC) +add_shader(surf_bin_sort.comp lighting/surfels/surf_bin_sort.comp) add_shader(surf_init2.comp lighting/surfels/surf_init2.comp) add_shader(surf_spawn.comp lighting/surfels/surf_spawn.comp) diff --git a/shader/lighting/surfels/surf_alloc2.comp b/shader/lighting/surfels/surf_alloc2.comp index 930704017..9268d02c6 100644 --- a/shader/lighting/surfels/surf_alloc2.comp +++ b/shader/lighting/surfels/surf_alloc2.comp @@ -93,6 +93,7 @@ void storeSurfels() { if(laneID==0) { pointQueueSize = min(pointQueueSize, pointQueue.length()); fragVote = atomicAdd(surf.count.x, pointQueueSize); + atomicAdd(surf.count.w, pointQueueSize); } barrier(); @@ -105,9 +106,9 @@ void storeSurfels() { Surfel sx; sx.pos = p.pos.xyz; sx.norm = encodeNormal(p.norm); - sx.radius = r; //p.pos.w; - sx.radiusMean = r; //p.pos.w; - sx.irradiance = surfDebugColor(p.pos.xyz, ptr); + sx.radius = r; + sx.radiusMean = p.pos.w; + sx.irradiance = debugColors[(gl_WorkGroupID.x*32+gl_WorkGroupID.y)%debugColors.length()]; //surfDebugColor(p.pos.xyz, ptr); sx.radiusPix = DefaultCoverage; surf.surfels[ptr] = sx; } @@ -181,7 +182,7 @@ ivec2 remap(ivec2 subtile, ivec2 tileCnt) { void main() { #if 0 - if(gl_WorkGroupID.xy!=uvec2(8,5) && gl_WorkGroupID.xy!=uvec2(8,6)) + if(gl_WorkGroupID.xy!=uvec2(10,6)) return; #endif diff --git a/shader/lighting/surfels/surf_apply2.comp b/shader/lighting/surfels/surf_apply2.comp index d30057e81..def781696 100644 --- a/shader/lighting/surfels/surf_apply2.comp +++ b/shader/lighting/surfels/surf_apply2.comp @@ -43,9 +43,13 @@ void applyBatch(inout vec4 clr, const vec3 wpos, const vec3 norm, const uint sur for(int i=0; i=1.0 || w<0.02); clr += vec4(color*w, w); + if(crowd) + continue; const uint sId = surfelsUse[i]; atomicOr(usage[sId/32], 1u<> 1; j > 0; j >>= 1) { + for (uint i = laneID; i < count; i += NumThreads) { + uint ixj = i ^ j; + + if(ixj > i) { + bool ascending = ((i & k) == 0); + + uint a = data[i ]; + uint b = data[ixj]; + + const bool swapNeeded = ascending ? (a > b) : (a < b); + if(swapNeeded) + swap(data[i], data[ixj]); + } + } + barrier(); + } + } + } + +void main() { + const uint laneID = gl_LocalInvocationIndex; + + const ivec2 tileId = ivec2(gl_WorkGroupID.xy); + const uint ptr = imageLoad(surfBins, tileId).x; + const uint cnt = imageLoad(surfCnts, tileId).x; + const uint cntM = min(cnt, data.length()); + const uint cntPow2 = nextPowerOfTwo(cntM); + + for(uint i=laneID; icntM) + imageStore(surfCnts, tileId, uvec4(cntM)); + } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_binning.comp b/shader/lighting/surfels/surf_binning.comp index 796bb2dba..811a17284 100644 --- a/shader/lighting/surfels/surf_binning.comp +++ b/shader/lighting/surfels/surf_binning.comp @@ -14,16 +14,17 @@ layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; +layout(binding = 1, std430) buffer SB0 { uint binAlloc; }; #if defined(SURFEL) -layout(binding = 1, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 2, std430) buffer SB1 { uvec4 count; Surfel surfels[]; }; #elif defined(ALLOC) -layout(binding = 1, std430) readonly buffer SB0 { uvec4 count; Candidate surfels[]; }; +layout(binding = 2, std430) readonly buffer SB1 { uvec4 count; Candidate surfels[]; }; #else #error "Unknown shader varriant" #endif -layout(binding = 2, r32ui) uniform uimage2D surfCnts; -layout(binding = 3, r32ui) uniform readonly uimage2D surfBins; -layout(binding = 4, std430) buffer SB1 { uint surfelIds[]; }; +layout(binding = 3, r32ui) uniform uimage2D surfCnts; +layout(binding = 4, r32ui) uniform readonly uimage2D surfBins; +layout(binding = 5, std430) buffer SB2 { uint surfelIds[]; }; vec4 projectSphere(const vec3 pos, float R) { // https://jcgt.org/published/0002/02/05/paper.pdf @@ -84,6 +85,7 @@ void main() { const float rMax = pixelToWorld(DefaultCoverage, pos4.z/pos4.w); const float radiusMean = max(rMin, min(p.radiusMean, rMax)); const int radiusPix = DefaultCoverage; //min(worldToPixel(p.pos, p.radiusMean), DefaultCoverage); + surfels[surfelId].fragCoord = fragCoord; surfels[surfelId].radiusPix = radiusPix; surfels[surfelId].radius = rMax; diff --git a/shader/lighting/surfels/surf_compact.comp b/shader/lighting/surfels/surf_compact.comp index df882f958..a2ed0d99c 100644 --- a/shader/lighting/surfels/surf_compact.comp +++ b/shader/lighting/surfels/surf_compact.comp @@ -21,19 +21,20 @@ void main() { Surfel sx; for(uint ix=0; ix Date: Fri, 26 Jun 2026 20:40:56 +0200 Subject: [PATCH 41/52] clowd elimination in progress --- shader/lighting/surfels/surf_apply2.comp | 2 +- shader/lighting/surfels/surf_bin_sort.comp | 4 +++- shader/lighting/surfels/surf_common.glsl | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/shader/lighting/surfels/surf_apply2.comp b/shader/lighting/surfels/surf_apply2.comp index def781696..6eb1f333a 100644 --- a/shader/lighting/surfels/surf_apply2.comp +++ b/shader/lighting/surfels/surf_apply2.comp @@ -46,7 +46,7 @@ void applyBatch(inout vec4 clr, const vec3 wpos, const vec3 norm, const uint sur if(w <= 0.0) continue; - const bool crowd = (clr.a>=1.0 || w<0.02); + const bool crowd = (clr.a>=1.0 || w<0.05); clr += vec4(color*w, w); if(crowd) continue; diff --git a/shader/lighting/surfels/surf_bin_sort.comp b/shader/lighting/surfels/surf_bin_sort.comp index 3519a4c61..bed12cef4 100644 --- a/shader/lighting/surfels/surf_bin_sort.comp +++ b/shader/lighting/surfels/surf_bin_sort.comp @@ -1,5 +1,7 @@ #version 450 +#include "lighting/surfels/surf_common.glsl" + layout(local_size_x = 256) in; const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; @@ -8,7 +10,7 @@ layout(binding = 3, r32ui) uniform uimage2D surfCnts; layout(binding = 4, r32ui) uniform uimage2D surfBins; layout(binding = 5, std430) buffer SB2 { uint surfelList[]; }; -shared uint data[512]; +shared uint data[MaxInTile]; uint nextPowerOfTwo(uint x) { if(x <= 1u) diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 275d0d9bb..0e92e7c52 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -6,6 +6,7 @@ const float SKY_DEPTH = 0.999995; const int MinCoverage = 8; // in pixels const int DefaultCoverage = 128; // in pixels +const uint MaxInTile = 512; // ~32px (~6x6) per surfel struct Surfel { vec3 pos; From 99c6b309eb578389a3abee30e2e10593bf652357 Mon Sep 17 00:00:00 2001 From: Try Date: Sun, 28 Jun 2026 01:02:21 +0200 Subject: [PATCH 42/52] improve surfel gc --- game/graphics/renderer.cpp | 3 + game/graphics/shaders.cpp | 1 + game/graphics/shaders.h | 2 +- shader/CMakeLists.txt | 1 + shader/lighting/surfels/surf_apply2.comp | 87 ++++++++++++++++----- shader/lighting/surfels/surf_bin_alloc.comp | 2 +- shader/lighting/surfels/surf_bin_sort.comp | 2 +- shader/lighting/surfels/surf_common.glsl | 2 +- shader/lighting/surfels/surf_decimate.comp | 70 +++++++++++++++++ 9 files changed, 145 insertions(+), 25 deletions(-) create mode 100644 shader/lighting/surfels/surf_decimate.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 074dd49d0..e22ac0161 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -2010,6 +2010,9 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setPipeline(shaders.surfApply2); cmd.dispatchThreads(zbuffer.size()); + cmd.setPipeline(shaders.surfDecimate); + cmd.dispatchThreads(maxSurfels); + cmd.setPipeline(shaders.surfCompact); cmd.dispatch(1); } diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index da7e5c96b..9b560c19b 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -270,6 +270,7 @@ void Shaders::compileShaders() { surfAlloc2 = computeShader("surf_alloc2.comp.sprv"); surfApply2 = computeShader("surf_apply2.comp.sprv"); surfCompact = computeShader("surf_compact.comp.sprv"); + surfDecimate = computeShader("surf_decimate.comp.sprv"); surfPathtrace = computeShader("surf_pathtrace.comp.sprv"); } diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index d1b85c6ce..c99529fe4 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -95,7 +95,7 @@ class Shaders { Tempest::ComputePipeline surfApply; Tempest::ComputePipeline surfPathtrace; - Tempest::ComputePipeline surfAlloc2, surfApply2, surfCompact; + Tempest::ComputePipeline surfAlloc2, surfApply2, surfDecimate, surfCompact; // Epipolar Tempest::ComputePipeline fogEpipolarVsm; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 455fad126..39f7697fe 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -334,6 +334,7 @@ add_shader(surf_tile_decimate.comp lighting/surfels/surf_tile_decimate.comp) add_shader(surf_alloc2.comp lighting/surfels/surf_alloc2.comp) add_shader(surf_apply2.comp lighting/surfels/surf_apply2.comp) add_shader(surf_compact.comp lighting/surfels/surf_compact.comp) +add_shader(surf_decimate.comp lighting/surfels/surf_decimate.comp) add_shader(surf_pathtrace.comp lighting/surfels/surf_pathtrace.comp) diff --git a/shader/lighting/surfels/surf_apply2.comp b/shader/lighting/surfels/surf_apply2.comp index 6eb1f333a..1a453bc57 100644 --- a/shader/lighting/surfels/surf_apply2.comp +++ b/shader/lighting/surfels/surf_apply2.comp @@ -16,8 +16,8 @@ layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; layout(binding = 1, rgba16f) uniform image2D irradiance; -layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform sampler2D depth; +layout(binding = 2) uniform utexture2D gbufNormal; +layout(binding = 3) uniform texture2D depth; layout(binding = 4, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; layout(binding = 5, std430) buffer SB1 { uint usage[]; }; layout(binding = 6, r32ui) uniform uimage2D surfCnts; @@ -39,6 +39,40 @@ vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { return pos.xyz/pos.w + originLwc; } +void applyGlob(inout vec4 clr, const vec3 wpos, const vec3 norm, const uint ptr, const uint cnt) { + const uint laneID = gl_LocalInvocationIndex; + + ivec2 bboxMin = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy); + ivec2 bboxMax = bboxMin + ivec2(gl_WorkGroupSize.xy); + + surfelCount = 0; + barrier(); + + for(uint i=laneID; i=1.0 || w<0.05); + clr += vec4(color*w, w); + if(crowd) + continue; + atomicOr(usage[sId/32], 1u<=1.0 || w<0.05); + const bool crowd = (clr.a>=1.0 || w<0.005); clr += vec4(color*w, w); if(crowd) continue; - const uint sId = surfelsUse[i]; - atomicOr(usage[sId/32], 1u<= cnt) + return; + + const uint sId = surfelList[ptr+i]; + const Surfel s = surfels[sId]; + //TODO: Preserve order! + if(!isSurfelVisible(s, bboxMin, bboxMax)) + return; + + const uint id = atomicAdd(surfelCount, 1); + surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); + surfelsNorm[id] = vec4(decodeNormal(s.norm), s.radius); + surfelsIrr [id] = vec4(s.irradiance, s.radiusMean); + surfelsUse [id] = sId; + } + void main() { #if 0 if(gl_WorkGroupID.xy/8!=uvec2(10,6)) @@ -80,32 +136,21 @@ void main() { ivec2 bboxMax = bboxMin + ivec2(gl_WorkGroupSize.xy); vec4 clr = vec4(0); +#if 0 + applyGlob(clr, wpos, norm, ptr, cnt); +#else for(uint i=0; ; i+=NumThreads) { - surfelCount = 0; - barrier(); - - if(i+laneID < cnt) { - const uint sId = surfelList[ptr+i+laneID]; - const Surfel s = surfels[sId]; - //TODO: Preserve order! - if(isSurfelVisible(s, bboxMin, bboxMax)) { - const uint id = atomicAdd(surfelCount, 1); - surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); - surfelsNorm[id] = vec4(decodeNormal(s.norm), s.radius); - surfelsIrr [id] = vec4(s.irradiance, s.radiusMean); - surfelsUse [id] = sId; - } - } + pullSurfels(bboxMin, bboxMax, ptr, cnt, i+laneID); barrier(); if(!sky) { applyBatch(clr, wpos, norm, surfelCount); } - if(i+NumThreads>=cnt) break; barrier(); } +#endif if(!valid || sky) { imageStore(irradiance, fragCoord, vec4(0,0,0,1)); diff --git a/shader/lighting/surfels/surf_bin_alloc.comp b/shader/lighting/surfels/surf_bin_alloc.comp index 4c4aedecd..503e7ef28 100644 --- a/shader/lighting/surfels/surf_bin_alloc.comp +++ b/shader/lighting/surfels/surf_bin_alloc.comp @@ -14,7 +14,7 @@ void main() { return; const uint v = imageLoad(surfCnts, tile).x; - const uint ptr = atomicAdd(binAlloc, v); + const uint ptr = v>0 ? atomicAdd(binAlloc, v) : 0; imageStore(surfCnts, tile, uvec4(0)); imageStore(surfBins, tile, uvec4(ptr)); diff --git a/shader/lighting/surfels/surf_bin_sort.comp b/shader/lighting/surfels/surf_bin_sort.comp index bed12cef4..1684c092e 100644 --- a/shader/lighting/surfels/surf_bin_sort.comp +++ b/shader/lighting/surfels/surf_bin_sort.comp @@ -25,7 +25,7 @@ void swap(inout uint a, inout uint b) { } void bitonicSort(uint count) { - uint laneID = gl_LocalInvocationIndex; + const uint laneID = gl_LocalInvocationIndex; //count = nextPowerOfTwo(count); diff --git a/shader/lighting/surfels/surf_common.glsl b/shader/lighting/surfels/surf_common.glsl index 0e92e7c52..a0237753a 100644 --- a/shader/lighting/surfels/surf_common.glsl +++ b/shader/lighting/surfels/surf_common.glsl @@ -123,7 +123,7 @@ float calculteWeight(const vec3 spos, const vec3 snorm, float rEff, float rMax, //float eOccl = (dot(ldir, snorm) > 0.1*dist) ? 0.1 : 1; return w*eOccl; #elif 1 - // Wendland C2 enspired falloff + // Wendland C2 inspired falloff rEff = min(rEff, rMax*0.5); float q = max(min(dist,rMax)-rEff, 0)/(rMax-rEff); float wPos = pow(1-q, 4.0)*(4.0*q + 1.0); diff --git a/shader/lighting/surfels/surf_decimate.comp b/shader/lighting/surfels/surf_decimate.comp new file mode 100644 index 000000000..a2d568152 --- /dev/null +++ b/shader/lighting/surfels/surf_decimate.comp @@ -0,0 +1,70 @@ +#version 460 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 64) in; + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + +layout(std140, push_constant) uniform Push { + vec3 originLwc; + uint tileSize; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1) uniform texture2D irradiance; +// +layout(binding = 4, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 5, std430) buffer SB1 { uint usage[]; }; +// +layout(binding = 6, r32ui) uniform uimage2D surfCnts; +layout(binding = 7, r32ui) uniform uimage2D surfBins; +layout(binding = 8, std430) readonly buffer SB2 { uint surfelList[]; }; + +void main() { + const uint surfelId = gl_GlobalInvocationID.x; + if(surfelId >= count.x) + return; + + const float edge = 2.0; + const Surfel p = surfels[surfelId]; + const ivec2 sz = textureSize(irradiance, 0); + + if(p.fragCoord.x < 0 || sz.x<=p.fragCoord.x) + return; + if(p.fragCoord.y < 0 || sz.y<=p.fragCoord.y) + return; + + const vec3 wpos = p.pos; + const vec3 norm = decodeNormal(p.norm); + + const ivec2 tileId = p.fragCoord/int(tileSize); + const uint cnt = imageLoad(surfCnts, tileId).x; + const uint ptr = imageLoad(surfBins, tileId).x; + const ivec2 topLeft = tileId*int(tileSize); + + float weight = 0; + for(uint i=0; i=surfelId) + break; + + const Surfel s = surfels[sId]; + if(s.fragCoord.xedge) { + // too dense + return; + } + } + + atomicOr(usage[surfelId/32], 1u << (surfelId%32)); + } From 1259109e2a4a2a0eb043540a69b76caaf7785b70 Mon Sep 17 00:00:00 2001 From: Try Date: Sun, 28 Jun 2026 12:09:32 +0200 Subject: [PATCH 43/52] gc in progress --- game/graphics/renderer.cpp | 14 ++++++-------- shader/lighting/surfels/surf_decimate.comp | 3 +-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index e22ac0161..5391e83c3 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1993,12 +1993,11 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor static bool apply = true; if(apply) { - // apply = false; cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, irrImage, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(1, irrImage, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); cmd.setBinding(4, surfels); cmd.setBinding(5, surfUsage); cmd.setBinding(6, surfCnts); @@ -2019,12 +2018,11 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor static bool alloc = true; if(alloc) { - // alloc = false; cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, irrImage, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(1, irrImage, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); cmd.setBinding(4, surfels); // cmd.setBinding(6, surfCnts); diff --git a/shader/lighting/surfels/surf_decimate.comp b/shader/lighting/surfels/surf_decimate.comp index a2d568152..3f85bc613 100644 --- a/shader/lighting/surfels/surf_decimate.comp +++ b/shader/lighting/surfels/surf_decimate.comp @@ -29,7 +29,7 @@ void main() { if(surfelId >= count.x) return; - const float edge = 2.0; + const float edge = 1.57; // .57 is prefference driven const Surfel p = surfels[surfelId]; const ivec2 sz = textureSize(irradiance, 0); @@ -58,7 +58,6 @@ void main() { const float w = calculteWeight(s.pos, decodeNormal(s.norm), s.radiusMean, s.radius, wpos, norm); weight += w; - //atomicOr(usage[sId/32], 1u << (sId%32)); if(weight>edge) { // too dense From 071a5c03c18d19a7922115221d83c1bdb9b47e09 Mon Sep 17 00:00:00 2001 From: Try Date: Sun, 28 Jun 2026 13:23:27 +0200 Subject: [PATCH 44/52] progress --- game/graphics/renderer.cpp | 50 +++++++++++++++------- shader/lighting/surfels/surf_alloc2.comp | 7 ++- shader/lighting/surfels/surf_apply2.comp | 49 +-------------------- shader/lighting/surfels/surf_bin_sort.comp | 6 +-- shader/lighting/surfels/surf_decimate.comp | 48 +++++++++++++++------ 5 files changed, 76 insertions(+), 84 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 5391e83c3..a6e91d1f7 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -571,7 +571,7 @@ void Renderer::draw(Encoder& cmd, uint8_t cmdId, size_t imgId, } void Renderer::dbgDraw(Tempest::Painter& p) { - static bool dbg = true; + static bool dbg = false; if(!dbg) return; @@ -1980,16 +1980,40 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setDebugMarker("Surfels"); // prev-frame - { surfelsBinning(cmd, wview, tileSize, false); - cmd.setBinding(3, surfCnts); - cmd.setBinding(4, surfBins); - cmd.setBinding(5, surfList); + static bool gc = true; + if(gc) { + struct PushGc { + uint32_t pass; + uint32_t tileSize; + } pushGc = {}; - cmd.setPipeline(shaders.surfBinSort); // assist with stable GC - cmd.dispatch(surfBins.size()); - } + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + // + cmd.setBinding(4, surfels); + cmd.setBinding(5, surfUsage); + cmd.setBinding(6, surfCnts); + cmd.setBinding(7, surfBins); + cmd.setBinding(8, surfList); + + cmd.setPipeline(shaders.surfBinSort); // assist with stable GC + cmd.dispatch(surfBins.size()); + + cmd.setPipeline(shaders.surfDecimate); + for(uint32_t pass=0; pass<3; ++pass) { + pushGc.pass = pass; + pushGc.tileSize = uint32_t(tileSize); + cmd.setPushData(pushGc); + cmd.dispatchThreads(maxSurfels); + } + + cmd.setPipeline(shaders.surfCompact); + cmd.dispatch(1); + + // bin one more time, for sake of apply pass + surfelsBinning(cmd, wview, tileSize, false); + } static bool apply = true; if(apply) { @@ -2008,12 +2032,6 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setPipeline(shaders.surfApply2); cmd.dispatchThreads(zbuffer.size()); - - cmd.setPipeline(shaders.surfDecimate); - cmd.dispatchThreads(maxSurfels); - - cmd.setPipeline(shaders.surfCompact); - cmd.dispatch(1); } static bool alloc = true; @@ -2056,10 +2074,10 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor //cmd.dispatchThreads(maxSurfels); cmd.dispatchIndirect(surfels, 0); //NOTE: need to split into old/new } - //surfelsBinning(cmd, wview, tileSize, false); + //surfelsBinning(cmd, wview, tileSize, false); if(apply) { - //TODO: patch pass + //TODO: patch pass } } diff --git a/shader/lighting/surfels/surf_alloc2.comp b/shader/lighting/surfels/surf_alloc2.comp index 9268d02c6..65c1aec37 100644 --- a/shader/lighting/surfels/surf_alloc2.comp +++ b/shader/lighting/surfels/surf_alloc2.comp @@ -11,7 +11,6 @@ const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z const ivec2 TileSize = ivec2(128); const float NormalBias = 0.0030; const uint Salt = 0x9D; -const float Edge = 0.1; const float MaxAttempts = 1; const int MaxQueue = 256; @@ -67,7 +66,7 @@ float amendCoverage(const ivec2 fragCoord, const vec3 wpos, const vec3 norm) { } float estimateCoverage(const ivec2 fragCoord, const vec3 wpos, const vec3 norm, const uint accounted) { - float wSum = texelFetch(irradiance, fragCoord, 0).a; + float wSum = 0.001 + texelFetch(irradiance, fragCoord, 0).a; if(wSum>1.0) return 1.0; @@ -175,14 +174,14 @@ void mainSubtile(const ivec2 at, const ivec2 fragCoord, const ivec2 screenSize) ivec2 remap(ivec2 subtile, ivec2 tileCnt) { // shuffle sub-tiles a little uint k = uint(subtile.y * tileCnt.x + subtile.x); - k ^= 0x12; + k ^= (3*8+4); k &= uint(NumThreads-1); return ivec2(int(k % tileCnt.x), int(k / tileCnt.x)); } void main() { #if 0 - if(gl_WorkGroupID.xy!=uvec2(10,6)) + if(gl_WorkGroupID.xy!=uvec2(10,4)) return; #endif diff --git a/shader/lighting/surfels/surf_apply2.comp b/shader/lighting/surfels/surf_apply2.comp index 1a453bc57..103491a7d 100644 --- a/shader/lighting/surfels/surf_apply2.comp +++ b/shader/lighting/surfels/surf_apply2.comp @@ -29,7 +29,6 @@ layout(binding = 11, rgba8) uniform image2D dbgImage; shared vec4 surfelsPos [NumThreads]; shared vec4 surfelsNorm[NumThreads]; shared vec4 surfelsIrr [NumThreads]; -shared uint surfelsUse [NumThreads]; shared uint surfelCount; vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { @@ -39,54 +38,13 @@ vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { return pos.xyz/pos.w + originLwc; } -void applyGlob(inout vec4 clr, const vec3 wpos, const vec3 norm, const uint ptr, const uint cnt) { - const uint laneID = gl_LocalInvocationIndex; - - ivec2 bboxMin = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy); - ivec2 bboxMax = bboxMin + ivec2(gl_WorkGroupSize.xy); - - surfelCount = 0; - barrier(); - - for(uint i=laneID; i=1.0 || w<0.05); - clr += vec4(color*w, w); - if(crowd) - continue; - atomicOr(usage[sId/32], 1u<=1.0 || w<0.005); clr += vec4(color*w, w); - if(crowd) - continue; - - //const uint sId = surfelsUse[i]; - //atomicOr(usage[sId/32], 1u<= count.x) @@ -31,30 +38,45 @@ void main() { const float edge = 1.57; // .57 is prefference driven const Surfel p = surfels[surfelId]; - const ivec2 sz = textureSize(irradiance, 0); + const ivec2 sz = scene.screenRes; - if(p.fragCoord.x < 0 || sz.x<=p.fragCoord.x) + if(!(-DefaultCoverage <= p.fragCoord.x && p.fragCoord.x < sz.x+DefaultCoverage)) return; - if(p.fragCoord.y < 0 || sz.y<=p.fragCoord.y) + if(!(-DefaultCoverage <= p.fragCoord.y && p.fragCoord.y < sz.y+DefaultCoverage)) return; const vec3 wpos = p.pos; const vec3 norm = decodeNormal(p.norm); - const ivec2 tileId = p.fragCoord/int(tileSize); - const uint cnt = imageLoad(surfCnts, tileId).x; - const uint ptr = imageLoad(surfBins, tileId).x; - const ivec2 topLeft = tileId*int(tileSize); + const ivec2 tileId = (p.fragCoord/int(tileSize)); + if(passId(tileId)!=pass) + return; + + const ivec2 cTileId = clamp(tileId, ivec2(0), imageSize(surfCnts)-1); + const uint cnt = imageLoad(surfCnts, cTileId).x; + const uint ptr = imageLoad(surfBins, cTileId).x; float weight = 0; for(uint i=0; i=surfelId) - break; + break; // surfels are sorted - const Surfel s = surfels[sId]; - if(s.fragCoord.x Date: Mon, 29 Jun 2026 20:09:51 +0200 Subject: [PATCH 45/52] cleanup surfels code --- game/graphics/renderer.cpp | 247 +--------------- game/graphics/renderer.h | 9 +- game/graphics/shaders.cpp | 18 +- game/graphics/shaders.h | 10 +- shader/CMakeLists.txt | 17 +- shader/lighting/surfels/surf_alloc.comp | 207 +++++++++++-- shader/lighting/surfels/surf_alloc2.comp | 206 ------------- shader/lighting/surfels/surf_apply.comp | 54 ++-- shader/lighting/surfels/surf_apply2.comp | 120 -------- shader/lighting/surfels/surf_init.comp | 14 +- shader/lighting/surfels/surf_init2.comp | 11 - shader/lighting/surfels/surf_spawn.comp | 124 -------- .../lighting/surfels/surf_tile_decimate.comp | 167 ----------- .../lighting/surfels/surf_tile_normalize.comp | 49 --- shader/lighting/surfels/surf_tile_weight.comp | 45 --- shader/lighting/surfels/surf_tiled.comp | 279 ------------------ shader/lighting/surfels/surf_weight.comp | 83 ------ 17 files changed, 244 insertions(+), 1416 deletions(-) delete mode 100644 shader/lighting/surfels/surf_alloc2.comp delete mode 100644 shader/lighting/surfels/surf_apply2.comp delete mode 100644 shader/lighting/surfels/surf_init2.comp delete mode 100644 shader/lighting/surfels/surf_spawn.comp delete mode 100644 shader/lighting/surfels/surf_tile_decimate.comp delete mode 100644 shader/lighting/surfels/surf_tile_normalize.comp delete mode 100644 shader/lighting/surfels/surf_tile_weight.comp delete mode 100644 shader/lighting/surfels/surf_tiled.comp delete mode 100644 shader/lighting/surfels/surf_weight.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index a6e91d1f7..808e75061 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1963,12 +1963,12 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::RGBA16F, zbuffer.size()); - auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc2.sizeofBuffer(4, maxSurfels)); + auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc.sizeofBuffer(4, maxSurfels)); auto& surfUsage = usesSsboInit(surf.surfUsage, usageWords*sizeof(uint32_t)); auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); - auto& surfList = usesSsbo (surf.surfList, 16*maxSurfels*sizeof(uint32_t)); + auto& surfList = usesSsbo (surf.surfList, 16*maxSurfels*sizeof(uint32_t)); struct Push { Vec3 originLwc; @@ -2030,7 +2030,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor // cmd.setBinding(11, dbgImage); - cmd.setPipeline(shaders.surfApply2); + cmd.setPipeline(shaders.surfApply); cmd.dispatchThreads(zbuffer.size()); } @@ -2049,11 +2049,11 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor // cmd.setBinding(11, dbgImage); - //cmd.setPipeline(shaders.surfInit2); + //cmd.setPipeline(shaders.surfInit); //cmd.dispatchThreads(1); //for sake of zeroing counters const auto tc = tileCount(zbuffer.size(), 128); - cmd.setPipeline(shaders.surfAlloc2); + cmd.setPipeline(shaders.surfAlloc); cmd.dispatch(tc); } @@ -2081,247 +2081,16 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor } } -void Renderer::prepareSurfels2(Tempest::Encoder& cmd, WorldView& wview) { - static bool enable = true; - if(!enable) - return; - - if(settings.giMethod!=GiMethod::IrrC) - return; - - const uint32_t maxSurfels = surf.maxSurfels; - const int32_t tileSize = 128; - const int32_t DefaultCoverage = 128; - const auto binCount = tileCount(zbuffer.size(), DefaultCoverage); - - auto& scene = wview.sceneGlobals(); - auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); - auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::R11G11B10UF, zbuffer.size()); - - auto& surfels = usesSsboInit(surf.surfels, shaders.surfSpawn.sizeofBuffer(4, maxSurfels)); - auto& surfAlloc = usesSsboInit(surf.surfAlloc, shaders.surfSpawn.sizeofBuffer(5, maxSurfels)); - auto& surfList = usesSsbo (surf.surfList, 16*maxSurfels*sizeof(uint32_t)); - - auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); - auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); - auto& surfPdf = usesImage2d(surf.surfPdf, TextureFormat::R32F, binCount); - - struct Push { - Vec3 originLwc; - uint32_t tileSize; - } push = {}; - push.originLwc = scene.originLwc; - push.tileSize = uint32_t(tileSize); - - cmd.setDebugMarker("Surfels"); - // prev-frame - // surfelsBinning(cmd, wview, tileSize); - - static bool apply = false; - if(apply) { - //TODO: apply pass 1 - } - - static bool spawn = true; - if(spawn) { - //alloc = false; - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); - cmd.setBinding(4, surfels); - cmd.setBinding(5, surfAlloc); - // - cmd.setBinding(11, dbgImage); - - cmd.setPipeline(shaders.surfInit2); - cmd.dispatchThreads(1); - - cmd.setPipeline(shaders.surfSpawn); - cmd.dispatchThreads(zbuffer.size()); - } - - surfelsBinning(cmd, wview, tileSize, true); - - static bool alloc = true; - if(alloc) { - cmd.setPushData(push); - cmd.setBinding(4, surfels); - cmd.setBinding(5, surfAlloc); - cmd.setBinding(6, surfList); - cmd.setBinding(7, surfCnts); - cmd.setBinding(8, surfBins); - cmd.setBinding(9, surfPdf); - cmd.setPipeline(shaders.surfWeight); - cmd.dispatchIndirect(surfAlloc, 0); - - cmd.setPipeline(shaders.surfTileWeight); - cmd.dispatch(binCount); - - cmd.setPipeline(shaders.surfTileNorm); - cmd.dispatch(1); - - cmd.setPipeline(shaders.surfTileDecim); - cmd.dispatch(binCount); - } - - static bool rays = false; - if(rays) { - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, surfels); - cmd.setBinding(2, sky.viewCldLut); - // - cmd.setBinding(6, scene.rtScene.tlas); - cmd.setBinding(7, Sampler::trillinear()); - cmd.setBinding(8, scene.rtScene.tex); - cmd.setBinding(9, scene.rtScene.vbo); - cmd.setBinding(10,scene.rtScene.ibo); - cmd.setBinding(11,scene.rtScene.rtDesc); - - cmd.setPipeline(shaders.surfPathtrace); - //cmd.dispatchThreads(maxSurfels); - cmd.dispatchIndirect(surfels, 0); - } - - surfelsBinning(cmd, wview, tileSize, false); - - if(apply) { - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); - cmd.setBinding(4, surfels); - cmd.setBinding(5, surfList); - cmd.setBinding(6, surfCnts); - cmd.setBinding(7, surfBins); - cmd.setBinding(8, irrImage); - // - cmd.setBinding(11, dbgImage); - - cmd.setPipeline(shaders.surfApply); - cmd.dispatchThreads(zbuffer.size()); - } - } - -void Renderer::prepareSurfels3(Tempest::Encoder& cmd, WorldView& wview) { - static bool enable = true; - if(!enable) - return; - - if(settings.giMethod!=GiMethod::IrrC) - return; - - // const auto maxSeed = tileCount(zbuffer.size(), 4); // 4px is smalles footprint - // const uint32_t maxSurfels = uint32_t(maxSeed.w * maxSeed.h); // surf.maxSurfels; - const uint32_t maxSurfels = surf.maxSurfels; - const uint32_t maxAlloc = maxSurfels * 16; - static int32_t tileSize = 128; - - auto& scene = wview.sceneGlobals(); - auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); - auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::R11G11B10UF, zbuffer.size()); - - auto& surfels = usesSsboInit(surf.surfels, shaders.surfTiled.sizeofBuffer(4, maxSurfels)); - auto& surfList = usesSsbo (surf.surfList, 16*maxSurfels*sizeof(uint32_t)); - auto& surfAlloc = usesSsbo (surf.surfAlloc, shaders.surfTiled.sizeofBuffer(8, maxAlloc)); - auto& surfDedup = usesSsboInit(surf.surfDedup, (maxSurfels+32-1)/32); - - auto binCount = tileCount(zbuffer.size(), tileSize); - auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); - auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); - - struct Push { - Vec3 originLwc; - uint32_t tileSize; - } push = {}; - push.originLwc = scene.originLwc; - push.tileSize = uint32_t(tileSize); - - cmd.setDebugMarker("Surfels"); - // prev-frame - surfelsBinning(cmd, wview, tileSize, false); - - static bool alloc = true; - if(alloc) { - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); - cmd.setBinding(4, surfels); - cmd.setBinding(5, surfList); - cmd.setBinding(6, surfCnts); - cmd.setBinding(7, surfBins); - cmd.setBinding(8, surfAlloc); - cmd.setBinding(9, surfDedup); - // - cmd.setBinding(11, dbgImage); - - cmd.setPipeline(shaders.surfInit); - cmd.dispatchThreads(surfDedup.byteSize()/sizeof(uint32_t)); //for sake of zeroing counters - - const auto tc = tileCount(zbuffer.size(), 128); - cmd.setPipeline(shaders.surfTiled); - cmd.dispatch(tc); - - cmd.setPipeline(shaders.surfAlloc); - cmd.dispatchThreads(maxAlloc); - - //alloc = false; - } - - static bool rays = true; - if(rays) { - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, surfels); - cmd.setBinding(2, sky.viewCldLut); - // - cmd.setBinding(6, scene.rtScene.tlas); - cmd.setBinding(7, Sampler::trillinear()); - cmd.setBinding(8, scene.rtScene.tex); - cmd.setBinding(9, scene.rtScene.vbo); - cmd.setBinding(10,scene.rtScene.ibo); - cmd.setBinding(11,scene.rtScene.rtDesc); - - cmd.setPipeline(shaders.surfPathtrace); - //cmd.dispatchThreads(maxSurfels); - cmd.dispatchIndirect(surfels, 0); - } - - surfelsBinning(cmd, wview, tileSize, false); - - static bool apply = false; - if(apply) { - cmd.setPushData(push); - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); - cmd.setBinding(4, surfels); - cmd.setBinding(5, surfList); - cmd.setBinding(6, surfCnts); - cmd.setBinding(7, surfBins); - cmd.setBinding(8, irrImage); - // - cmd.setBinding(11, dbgImage); - - cmd.setPipeline(shaders.surfApply); - cmd.dispatchThreads(zbuffer.size()); - } - } - void Renderer::surfelsBinning(Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool alloc) { const uint32_t maxSurfels = surf.maxSurfels; auto& scene = wview.sceneGlobals(); - auto& surfels = alloc ? surf.surfAlloc : surf.surfels; - auto& binCtrl = usesSsboInit(surf.binCtrl, sizeof(uint32_t)); + auto& surfels = surf.surfels; + auto& binCtrl = usesSsboInit(surf.surfBinsCtrl, sizeof(uint32_t)); auto& surfCnts = surf.surfCnts; auto& surfBins = surf.surfBins; auto& surfList = surf.surfList; - auto& surfBinning = alloc ? shaders.surfBinningA : shaders.surfBinningS; + auto& surfBinning = shaders.surfBinningS; struct Push { int32_t tileSize; diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index f77a53776..4d54875bc 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -66,8 +66,6 @@ class Renderer final { void prepareEpipolar (Tempest::Encoder& cmd, WorldView& wview); void prepareSurfels (Tempest::Encoder& cmd, WorldView& wview); - void prepareSurfels2 (Tempest::Encoder& cmd, WorldView& wview); - void prepareSurfels3 (Tempest::Encoder& cmd, WorldView& wview); void surfelsBinning (Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool alloc); void drawHiZ (Tempest::Encoder& cmd, WorldView& view); @@ -215,12 +213,11 @@ class Renderer final { struct { const uint32_t maxSurfels = 16*1024; - Tempest::StorageBuffer surfels, surfAlloc; + Tempest::StorageBuffer surfels, surfUsage; Tempest::StorageImage irrImage; - Tempest::StorageImage surfCnts, surfBins, surfPdf; - Tempest::StorageBuffer binCtrl; - Tempest::StorageBuffer surfList, surfUsage, surfDedup; + Tempest::StorageImage surfCnts, surfBins; + Tempest::StorageBuffer surfBinsCtrl, surfList; Tempest::StorageImage dbgImage; } surf; diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 9b560c19b..d8d14adaa 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -249,26 +249,16 @@ void Shaders::compileShaders() { auto fs = device.shader(sh.data,sh.len); surfDbg = device.pipeline(Triangles,state,vs,fs); - surfInit = computeShader("surf_init.comp.sprv"); - surfTiled = computeShader("surf_tiled.comp.sprv"); - surfAlloc = computeShader("surf_alloc.comp.sprv"); - surfApply = computeShader("surf_apply.comp.sprv"); - - surfInit2 = computeShader("surf_init2.comp.sprv"); - surfSpawn = computeShader("surf_spawn.comp.sprv"); - surfWeight = computeShader("surf_weight.comp.sprv"); - surfTileWeight = computeShader("surf_tile_weight.comp.sprv"); - surfTileNorm = computeShader("surf_tile_normalize.comp.sprv"); - surfTileDecim = computeShader("surf_tile_decimate.comp.sprv"); - surfBinningS = computeShader("surf_binning_s.comp.sprv"); surfBinningA = computeShader("surf_binning_a.comp.sprv"); surfBinClear = computeShader("surf_bin_clear.comp.sprv"); surfBinAlloc = computeShader("surf_bin_alloc.comp.sprv"); surfBinSort = computeShader("surf_bin_sort.comp.sprv"); - surfAlloc2 = computeShader("surf_alloc2.comp.sprv"); - surfApply2 = computeShader("surf_apply2.comp.sprv"); + surfInit = computeShader("surf_init.comp.sprv"); + + surfAlloc = computeShader("surf_alloc.comp.sprv"); + surfApply = computeShader("surf_apply.comp.sprv"); surfCompact = computeShader("surf_compact.comp.sprv"); surfDecimate = computeShader("surf_decimate.comp.sprv"); diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index c99529fe4..62a7a44b8 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -88,14 +88,12 @@ class Shaders { // GI-Surf Tempest::RenderPipeline surfDbg; - Tempest::ComputePipeline surfInit, surfTiled, surfAlloc; Tempest::ComputePipeline surfBinClear, surfBinningS, surfBinningA, surfBinAlloc, surfBinSort; - Tempest::ComputePipeline surfInit2; - Tempest::ComputePipeline surfSpawn, surfWeight, surfTileWeight, surfTileNorm, surfTileDecim; - Tempest::ComputePipeline surfApply; - Tempest::ComputePipeline surfPathtrace; - Tempest::ComputePipeline surfAlloc2, surfApply2, surfDecimate, surfCompact; + Tempest::ComputePipeline surfInit; + Tempest::ComputePipeline surfAlloc, surfApply, surfDecimate, surfCompact; + + Tempest::ComputePipeline surfPathtrace; // Epipolar Tempest::ComputePipeline fogEpipolarVsm; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 39f7697fe..fea169579 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -313,10 +313,11 @@ add_shader(surf_dbg.vert lighting/surfels/surf_dbg.vert) add_shader(surf_dbg.frag lighting/surfels/surf_dbg.frag) add_shader(surf_init.comp lighting/surfels/surf_init.comp) -add_shader(surf_tiled.comp lighting/surfels/surf_tiled.comp) -add_shader(surf_alloc.comp lighting/surfels/surf_alloc.comp) +add_shader(surf_alloc.comp lighting/surfels/surf_alloc.comp) add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) +add_shader(surf_compact.comp lighting/surfels/surf_compact.comp) +add_shader(surf_decimate.comp lighting/surfels/surf_decimate.comp) add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) @@ -324,18 +325,6 @@ add_shader(surf_binning_s.comp lighting/surfels/surf_binning.comp -DSURFEL add_shader(surf_binning_a.comp lighting/surfels/surf_binning.comp -DALLOC) add_shader(surf_bin_sort.comp lighting/surfels/surf_bin_sort.comp) -add_shader(surf_init2.comp lighting/surfels/surf_init2.comp) -add_shader(surf_spawn.comp lighting/surfels/surf_spawn.comp) -add_shader(surf_weight.comp lighting/surfels/surf_weight.comp) -add_shader(surf_tile_weight.comp lighting/surfels/surf_tile_weight.comp) -add_shader(surf_tile_normalize.comp lighting/surfels/surf_tile_normalize.comp) -add_shader(surf_tile_decimate.comp lighting/surfels/surf_tile_decimate.comp) - -add_shader(surf_alloc2.comp lighting/surfels/surf_alloc2.comp) -add_shader(surf_apply2.comp lighting/surfels/surf_apply2.comp) -add_shader(surf_compact.comp lighting/surfels/surf_compact.comp) -add_shader(surf_decimate.comp lighting/surfels/surf_decimate.comp) - add_shader(surf_pathtrace.comp lighting/surfels/surf_pathtrace.comp) # Pathtracing diff --git a/shader/lighting/surfels/surf_alloc.comp b/shader/lighting/surfels/surf_alloc.comp index 4b1361bc7..f668603d8 100644 --- a/shader/lighting/surfels/surf_alloc.comp +++ b/shader/lighting/surfels/surf_alloc.comp @@ -4,7 +4,15 @@ #include "scene.glsl" #include "common.glsl" -layout(local_size_x = 64) in; +layout(local_size_x = 16, local_size_y = 16) in; + +const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; + +const ivec2 TileSize = ivec2(128); +const float NormalBias = 0.0030; +const uint Salt = 0x9D; +const float MaxAttempts = 1; +const int MaxQueue = 256; layout(std140, push_constant) uniform Push { vec3 originLwc; @@ -12,32 +20,187 @@ layout(std140, push_constant) uniform Push { layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; } surf; -layout(binding = 8, std430) buffer SB2 { uvec4 count; SurfelAlloc req[]; } alloc; -layout(binding = 9, std430) buffer SB3 { uint deduplication[]; }; +layout(binding = 1) uniform texture2D irradiance; +layout(binding = 2) uniform utexture2D gbufNormal; +layout(binding = 3) uniform texture2D depth; +layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; } surf; +// +layout(binding = 6, r32ui) uniform uimage2D surfCnts; +layout(binding = 7, r32ui) uniform uimage2D surfBins; +layout(binding = 8, std430) readonly buffer SB2 { uint surfelList[]; }; +// +layout(binding = 11, rgba8) uniform image2D dbgImage; -void main() { - const uint allocId = gl_GlobalInvocationID.x; - if(allocId>=alloc.count.x || allocId>=alloc.req.length()) - return; +shared SurfelAlloc pointQueue[MaxQueue]; +shared float pointRMax [MaxQueue]; +shared int pointQueueSize; + +shared uint fragVote; + +vec3 worldPos(float z, vec3 normal, ivec2 fragCoord, ivec2 screenSize) { + const mat4 inv = scene.viewProjectLwcInv; + const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; + const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); + return (pos.xyz + normal*NormalBias)/pos.w + originLwc; + } + +float pixelToWorld(float pixelRadius, float z) { + z = linearDepth(z, scene.clipInfo); + + float clipRadiusX = (2.0 * pixelRadius) * scene.screenResInv.x; + float clipRadiusY = (2.0 * pixelRadius) * scene.screenResInv.y; + + float worldRadiusX = (clipRadiusX * z) / scene.project[0][0]; + float worldRadiusY = (clipRadiusY * z) / scene.project[1][1]; + return min(worldRadiusX, worldRadiusY); + } + +float calculteWeight(const SurfelAlloc s, float rMax, const vec3 wpos, const vec3 norm) { + return calculteWeight(s.pos.xyz, s.norm, s.pos.w, rMax, wpos, norm); + } + +float amendCoverage(const ivec2 fragCoord, const vec3 wpos, const vec3 norm) { + const int i = pointQueueSize-1; + const SurfelAlloc s = pointQueue[i]; + return calculteWeight(s,pointRMax[i],wpos,norm); + } + +float estimateCoverage(const ivec2 fragCoord, const vec3 wpos, const vec3 norm, const uint accounted) { + float wSum = 0.001 + texelFetch(irradiance, fragCoord, 0).a; + if(wSum>1.0) + return 1.0; + + for(int i=pointQueueSize; i>accounted;) { + --i; + const SurfelAlloc s = pointQueue[i]; + wSum += calculteWeight(s,pointRMax[i],wpos,norm); + if(wSum > 1.0) + return 1.0; + } + return wSum; + } + +void fragCoverageVote(float wSum) { + uint w = floatBitsToUint(wSum) & 0xFFFF0000; + uint b = uint(w) | uint(gl_LocalInvocationIndex) ^ Salt; + atomicMin(fragVote, b); + } + +void storeSurfels() { + const uint laneID = gl_LocalInvocationIndex; + + if(laneID==0) { + pointQueueSize = min(pointQueueSize, pointQueue.length()); + fragVote = atomicAdd(surf.count.x, pointQueueSize); + atomicAdd(surf.count.w, pointQueueSize); + } + barrier(); + + if(laneID= SKY_DEPTH); + + const vec3 norm = normalFetch(gbufNormal, fragCoord); + const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); + + float coverage = (sky ? 1.0 : estimateCoverage(fragCoord, wpos, norm, 0)); + + for(int i=0; i=pointQueue.length()) + break; + + if(coverage<1.0) + fragCoverageVote(coverage); + barrier(); + + const uint vote = fragVote; + barrier(); + + fragVote = 0xFFFFFFFF; + if((vote & 0xFFFF0000)==0xFFFF0000) + break; + + allocSurfel(at, screenSize, vote); + barrier(); + + coverage += amendCoverage(fragCoord, wpos, norm); + } + + imageStore(dbgImage, fragCoord, vec4(coverage)); + } + +ivec2 remap(ivec2 subtile, ivec2 tileCnt) { + // shuffle sub-tiles a little + uint k = uint(subtile.y * tileCnt.x + subtile.x); + k ^= (3*8+4); + k &= uint(NumThreads-1); + return ivec2(int(k % tileCnt.x), int(k / tileCnt.x)); + } + +void main() { +#if 0 + if(gl_WorkGroupID.xy!=uvec2(10,4)) + return; +#endif + + if(!(7 < gl_WorkGroupID.x && gl_WorkGroupID.x<=9 && + 3 < gl_WorkGroupID.y && gl_WorkGroupID.y<=6)) + ;//return; - const uint surfelId = atomicAdd(surf.count.x,1); + pointQueueSize = 0; + fragVote = 0xFFFFFFFF; + barrier(); - Surfel sx; - sx.pos = p.pos.xyz; - sx.norm = encodeNormal(p.norm); - sx.radius = p.pos.w; - sx.radiusPix = DefaultCoverage; //TODO: calculate dynamically - sx.irradiance = surfDebugColor(p.pos.xyz, surfelId); + const ivec2 screenSize = ivec2(textureSize(depth,0)); + const ivec2 tileCount = TileSize/ivec2(gl_WorkGroupSize.xy); + for(int y=0; y1.0) - return 1.0; - - for(int i=pointQueueSize; i>accounted;) { - --i; - const SurfelAlloc s = pointQueue[i]; - wSum += calculteWeight(s,pointRMax[i],wpos,norm); - if(wSum > 1.0) - return 1.0; - } - return wSum; - } - -void fragCoverageVote(float wSum) { - uint w = floatBitsToUint(wSum) & 0xFFFF0000; - uint b = uint(w) | uint(gl_LocalInvocationIndex) ^ Salt; - atomicMin(fragVote, b); - } - -void storeSurfels() { - const uint laneID = gl_LocalInvocationIndex; - - if(laneID==0) { - pointQueueSize = min(pointQueueSize, pointQueue.length()); - fragVote = atomicAdd(surf.count.x, pointQueueSize); - atomicAdd(surf.count.w, pointQueueSize); - } - barrier(); - - if(laneID= SKY_DEPTH); - - const vec3 norm = normalFetch(gbufNormal, fragCoord); - const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); - - float coverage = (sky ? 1.0 : estimateCoverage(fragCoord, wpos, norm, 0)); - - for(int i=0; i=pointQueue.length()) - break; - - if(coverage<1.0) - fragCoverageVote(coverage); - barrier(); - - const uint vote = fragVote; - barrier(); - - fragVote = 0xFFFFFFFF; - if((vote & 0xFFFF0000)==0xFFFF0000) - break; - - allocSurfel(at, screenSize, vote); - barrier(); - - coverage += amendCoverage(fragCoord, wpos, norm); - } - - imageStore(dbgImage, fragCoord, vec4(coverage)); - } - -ivec2 remap(ivec2 subtile, ivec2 tileCnt) { - // shuffle sub-tiles a little - uint k = uint(subtile.y * tileCnt.x + subtile.x); - k ^= (3*8+4); - k &= uint(NumThreads-1); - return ivec2(int(k % tileCnt.x), int(k / tileCnt.x)); - } - -void main() { -#if 0 - if(gl_WorkGroupID.xy!=uvec2(10,4)) - return; -#endif - - if(!(7 < gl_WorkGroupID.x && gl_WorkGroupID.x<=9 && - 3 < gl_WorkGroupID.y && gl_WorkGroupID.y<=6)) - ;//return; - - pointQueueSize = 0; - fragVote = 0xFFFFFFFF; - barrier(); - - const ivec2 screenSize = ivec2(textureSize(depth,0)); - const ivec2 tileCount = TileSize/ivec2(gl_WorkGroupSize.xy); - for(int y=0; y= cnt) + return; + + const uint sId = surfelList[ptr+i]; + const Surfel s = surfels[sId]; + + if(!isSurfelVisible(s, bboxMin, bboxMax)) + return; + + const uint id = atomicAdd(surfelCount, 1); + surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); + surfelsNorm[id] = vec4(decodeNormal(s.norm), s.radius); + surfelsIrr [id] = vec4(s.irradiance, s.radiusMean); + } + void main() { +#if 0 + if(gl_WorkGroupID.xy/8!=uvec2(10,6)) + return; +#endif const uint laneID = gl_LocalInvocationIndex; const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); @@ -69,32 +94,19 @@ void main() { vec4 clr = vec4(0); for(uint i=0; ; i+=NumThreads) { - surfelCount = 0; - barrier(); - - if(i+laneID < cnt) { - const uint sId = surfelList[ptr+i+laneID]; - const Surfel s = surfels[sId]; - - if(isSurfelVisible(s, bboxMin, bboxMax)) { - const uint id = atomicAdd(surfelCount, 1); - surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); - surfelsNorm[id] = vec4(decodeNormal(s.norm), s.radius); - surfelsIrr [id] = vec4(s.irradiance, s.radiusMean); - } - } + pullSurfels(bboxMin, bboxMax, ptr, cnt, i+laneID); barrier(); if(!sky) { applyBatch(clr, wpos, norm, surfelCount); } - if(i+NumThreads>=cnt) break; barrier(); } if(!valid || sky) { + imageStore(irradiance, fragCoord, vec4(0,0,0,1)); imageStore(dbgImage, fragCoord, vec4(1)); return; } diff --git a/shader/lighting/surfels/surf_apply2.comp b/shader/lighting/surfels/surf_apply2.comp deleted file mode 100644 index 103491a7d..000000000 --- a/shader/lighting/surfels/surf_apply2.comp +++ /dev/null @@ -1,120 +0,0 @@ -#version 450 - -#include "lighting/surfels/surf_common.glsl" -#include "scene.glsl" -#include "common.glsl" - -layout(local_size_x = 16, local_size_y = 16) in; - -const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; - -layout(std140, push_constant) uniform Push { - vec3 originLwc; - uint tileSize; - }; -layout(binding = 0, std140) uniform UboScene { - SceneDesc scene; - }; -layout(binding = 1, rgba16f) uniform image2D irradiance; -layout(binding = 2) uniform utexture2D gbufNormal; -layout(binding = 3) uniform texture2D depth; -layout(binding = 4, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 5, std430) buffer SB1 { uint usage[]; }; -layout(binding = 6, r32ui) uniform uimage2D surfCnts; -layout(binding = 7, r32ui) uniform uimage2D surfBins; -layout(binding = 8, std430) readonly buffer SB2 { uint surfelList[]; }; -// -layout(binding = 11, rgba8) uniform image2D dbgImage; - -shared vec4 surfelsPos [NumThreads]; -shared vec4 surfelsNorm[NumThreads]; -shared vec4 surfelsIrr [NumThreads]; -shared uint surfelCount; - -vec3 worldPos(float z, ivec2 fragCoord, ivec2 screenSize) { - const mat4 inv = scene.viewProjectLwcInv; - const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; - const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); - return pos.xyz/pos.w + originLwc; - } - -void applyBatch(inout vec4 clr, const vec3 wpos, const vec3 norm, const uint surfCount) { - for(int i=0; i= cnt) - return; - - const uint sId = surfelList[ptr+i]; - const Surfel s = surfels[sId]; - - if(!isSurfelVisible(s, bboxMin, bboxMax)) - return; - - const uint id = atomicAdd(surfelCount, 1); - surfelsPos [id] = vec4(s.pos, uintBitsToFloat(sId)); - surfelsNorm[id] = vec4(decodeNormal(s.norm), s.radius); - surfelsIrr [id] = vec4(s.irradiance, s.radiusMean); - } - -void main() { -#if 0 - if(gl_WorkGroupID.xy/8!=uvec2(10,6)) - return; -#endif - const uint laneID = gl_LocalInvocationIndex; - - const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); - const ivec2 screenSize = ivec2(textureSize(depth,0)); - const bool valid = all(lessThan(fragCoord, screenSize)); - - const ivec2 tileId = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy)/int(tileSize); - const uint cnt = imageLoad(surfCnts, tileId).x; - const uint ptr = imageLoad(surfBins, tileId).x; - - const float z = valid ? texelFetch(depth,fragCoord,0).x : 1; - const vec3 wpos = worldPos(z, fragCoord, screenSize); - const vec3 norm = normalFetch(gbufNormal, fragCoord); - const bool sky = (z >= SKY_DEPTH); - - ivec2 bboxMin = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy); - ivec2 bboxMax = bboxMin + ivec2(gl_WorkGroupSize.xy); - - vec4 clr = vec4(0); - for(uint i=0; ; i+=NumThreads) { - pullSurfels(bboxMin, bboxMax, ptr, cnt, i+laneID); - barrier(); - - if(!sky) { - applyBatch(clr, wpos, norm, surfelCount); - } - if(i+NumThreads>=cnt) - break; - barrier(); - } - - if(!valid || sky) { - imageStore(irradiance, fragCoord, vec4(0,0,0,1)); - imageStore(dbgImage, fragCoord, vec4(1)); - return; - } - - if(clr.a>0) - clr.rgb /= clr.a; - clr.rgb *= scene.exposure; - - imageStore(irradiance, fragCoord, vec4(clr.rgb, clr.a)); - imageStore(dbgImage, fragCoord, vec4(clr.a)); - } diff --git a/shader/lighting/surfels/surf_init.comp b/shader/lighting/surfels/surf_init.comp index 40a2aecd4..0f6095ece 100644 --- a/shader/lighting/surfels/surf_init.comp +++ b/shader/lighting/surfels/surf_init.comp @@ -1,17 +1,11 @@ #version 450 -layout(local_size_x = 64) in; +layout(local_size_x = 1) in; layout(binding = 4, std430) buffer SB0 { uvec4 count; } surf; -layout(binding = 8, std430) buffer SB2 { uvec4 count; } alloc; -layout(binding = 9, std430) buffer SB3 { uint deduplication[]; }; +layout(binding = 5, std430) buffer SB2 { uvec4 count; } alloc; void main() { - if(gl_GlobalInvocationID.x==0) { - surf. count = uvec4(0,1,1,0); - alloc.count = uvec4(0,1,1,0); - } - - if(gl_GlobalInvocationID.x < deduplication.length()) - deduplication[gl_GlobalInvocationID.x] = 0; + surf. count = uvec4(0,1,1,0); + alloc.count = uvec4(0,1,1,0); } diff --git a/shader/lighting/surfels/surf_init2.comp b/shader/lighting/surfels/surf_init2.comp deleted file mode 100644 index 0f6095ece..000000000 --- a/shader/lighting/surfels/surf_init2.comp +++ /dev/null @@ -1,11 +0,0 @@ -#version 450 - -layout(local_size_x = 1) in; - -layout(binding = 4, std430) buffer SB0 { uvec4 count; } surf; -layout(binding = 5, std430) buffer SB2 { uvec4 count; } alloc; - -void main() { - surf. count = uvec4(0,1,1,0); - alloc.count = uvec4(0,1,1,0); - } diff --git a/shader/lighting/surfels/surf_spawn.comp b/shader/lighting/surfels/surf_spawn.comp deleted file mode 100644 index ce59de545..000000000 --- a/shader/lighting/surfels/surf_spawn.comp +++ /dev/null @@ -1,124 +0,0 @@ -#version 460 - -#extension GL_EXT_shader_explicit_arithmetic_types_int32 : enable - -layout(local_size_x = 16, local_size_y = 16) in; - -#include "lighting/surfels/surf_common.glsl" -#include "scene.glsl" - -const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; - -const float NormalBias = 0.0030; - -layout(std140, push_constant) uniform Push { - vec3 originLwc; - }; -layout(binding = 0, std140) uniform UboScene { - SceneDesc scene; - }; -layout(binding = 1) uniform sampler2D gbufDiffuse; -layout(binding = 2) uniform usampler2D gbufNormal; -layout(binding = 3) uniform sampler2D depth; -layout(binding = 4, std430) readonly buffer SB1 { uvec4 count; Surfel surfels[]; } surf; -layout(binding = 5, std430) buffer SB0 { uvec4 count; Candidate candidate[]; } alloc; -// -layout(binding = 11, rgba8) uniform image2D dbgImage; - -shared uint32_t fragVote; - -uint32_t packVote(uint weight, uint32_t key) { - uint32_t w = (weight << 16) & 0xFFFF0000; - return uint32_t(w) | uint32_t(key & 0x0000FFFF); - } - -uint32_t unpackVoteKey(uint vote) { - return uint32_t(vote & 0x0000FFFF); - } - -uint wangHashNoise(uvec2 uv, uint s) { - uint seed = (uv.x*1664525u + uv.y) + s; - uint hash = wangHash(seed) & 0xFFFF; - return hash; - //float value = float(hash) / float(0xFFFF); - //return value; - } - -uint hash3(uvec3 p) { - p = p * 1664525u + 1013904223u; - - p.x += p.y * p.z; - p.y += p.z * p.x; - p.z += p.x * p.y; - - p ^= p >> 16u; - - p.x += p.y * p.z; - p.y += p.z * p.x; - p.z += p.x * p.y; - - return p.x ^ p.y ^ p.z; - } - -vec3 worldPos(float z, vec3 normal, ivec2 fragCoord, ivec2 screenSize) { - const mat4 inv = scene.viewProjectLwcInv; - const vec2 uv = vec2(fragCoord+0.5)*scene.screenResInv; - const vec4 pos = inv*vec4(uv * 2.0 - 1.0, z, 1); - return (pos.xyz + normal*NormalBias)/pos.w + originLwc; - } - -float pixelToWorld(float pixelRadius, float z) { - z = linearDepth(z, scene.clipInfo); - - float clipRadiusX = (2.0 * pixelRadius) * scene.screenResInv.x; - float clipRadiusY = (2.0 * pixelRadius) * scene.screenResInv.y; - - float worldRadiusX = (clipRadiusX * z) / scene.project[0][0]; - float worldRadiusY = (clipRadiusY * z) / scene.project[1][1]; - return min(worldRadiusX, worldRadiusY); - } - -void main() { - const uint laneID = gl_LocalInvocationIndex; - - fragVote = packVote(0xFFFF, 0xFFFF); - barrier(); - - const ivec2 fragCoord = ivec2(gl_GlobalInvocationID.xy); - const ivec2 screenSize = ivec2(textureSize(depth,0)); - const bool valid = all(lessThan(fragCoord, screenSize)); - - // const ivec2 tileId = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy)/int(tileSize); - // const uint cnt = imageLoad(surfCnts, tileId).x; - // const uint ptr = imageLoad(surfBins, tileId).x; - - const float z = valid ? texelFetch(depth,fragCoord,0).x : 1; - const vec3 norm = normalFetch(gbufNormal, fragCoord); - const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); - const bool sky = (z >= SKY_DEPTH); - - if(!sky) { - const uint rand = wangHashNoise(fragCoord, 0); - // const uint rand = hash3(uvec3(wpos/1.0)); - atomicMin(fragVote, packVote(rand, gl_LocalInvocationIndex)); - imageStore(dbgImage, fragCoord, vec4(float(rand)/float(0xFFFF))); - } - barrier(); - - if(unpackVoteKey(fragVote)!=gl_LocalInvocationIndex) - return; - - const uint surfelId = atomicAdd(alloc.count.x,1); - - Candidate sx; - sx.pos = wpos; - sx.norm = norm; - sx.radius = pixelToWorld(DefaultCoverage, z); - sx.fragCoord = fragCoord; - - //sx.radiusMean = sx.radius; - //sx.radiusPix = DefaultCoverage; - //sx.irradiance = surfDebugColor(wpos, surfelId); - - alloc.candidate[surfelId] = sx; - } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_tile_decimate.comp b/shader/lighting/surfels/surf_tile_decimate.comp deleted file mode 100644 index 6d379552c..000000000 --- a/shader/lighting/surfels/surf_tile_decimate.comp +++ /dev/null @@ -1,167 +0,0 @@ -#version 460 - -#include "lighting/surfels/surf_common.glsl" - -layout(local_size_x = 128) in; - -const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; -const int MaxSurfels = 2048; -const int Quota = 16; - -struct Item { - float weight; - uint idx; - }; - -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; }; -layout(binding = 5, std430) readonly buffer SB1 { uvec4 count; Candidate candidate[]; } alloc; -layout(binding = 6, std430) readonly buffer SB2 { uint surfelList[]; }; -layout(binding = 7, r32ui) uniform uimage2D surfCnts; -layout(binding = 8, r32ui) uniform uimage2D surfBins; -layout(binding = 9, r32f) uniform image2D surfPdf; - -shared uint dataSize; -shared Item data[128]; - -uint nextPowerOfTwo(uint x) { - if(x <= 1u) - return 1u; - return 1u << (findMSB(x - 1u) + 1); - } - -void swap(inout Item a, inout Item b) { - Item t = a; - a = b; - b = t; - } - -void bitonicSort(uint count) { - uint laneID = gl_LocalInvocationIndex; - - count = nextPowerOfTwo(count); - - for(uint k = 2; k <= count; k <<= 1) { - for(uint j = k >> 1; j > 0; j >>= 1) { - uint ixj = laneID ^ j; - - if(ixj > laneID) { - bool ascending = !((laneID & k) == 0); - - float a = data[laneID].weight; - float b = data[ixj ].weight; - - const bool swapNeeded = ascending ? (a > b) : (a < b); - if(swapNeeded) - swap(data[laneID], data[ixj]); - } - - barrier(); - } - } - } - -void allocateAll() { - const uint laneID = gl_LocalInvocationIndex; - - const ivec2 tileId = ivec2(gl_WorkGroupID.xy); - const uint cnt = imageLoad(surfCnts, tileId).x; - const uint ptr = imageLoad(surfBins, tileId).x; - - for(uint i=laneID; i=surfels.length()) - continue; - - Surfel sx; - sx.pos = p.pos; - sx.norm = encodeNormal(p.norm); - sx.radius = p.radius; - sx.radiusPix = DefaultCoverage; - sx.irradiance = vec3(p.weight); // surfDebugColor(p.pos, surfelId); - - surfels[surfelId] = sx; - } - } - -float stableWeight(float w, uvec2 uv) { - uint seed = (uv.x*1664525u + uv.y); - uint hash = wangHash(seed) & 0xFFFF; - - return uintBitsToFloat((floatBitsToUint(w) & 0xFFFF0000) | hash); - } - -void main() { - const uint laneID = gl_LocalInvocationIndex; - const ivec2 imgSize = imageSize(surfPdf); - const int numTiles = imgSize.x*imgSize.y; - const int maxSurfels = max(MaxSurfels-numTiles*Quota, 0); - - const ivec2 tileId = ivec2(gl_WorkGroupID.xy); - const uint cnt = imageLoad(surfCnts, tileId).x; - const uint ptr = imageLoad(surfBins, tileId).x; - - const int cntAlloc = int(imageLoad(surfPdf, tileId).x * maxSurfels) + Quota; -#if 0 - if(tileId!=ivec2(10,4)) - return; -#endif -#if 0 - allocateAll(); - return; -#endif - - dataSize = 0; - for(uint i=laneID; i=data.length()) - continue; - - data[num].weight = stableWeight(p.weight, p.fragCoord); - data[num].idx = sId; - } - barrier(); - - if(laneID==0) - dataSize = min(dataSize, data.length()); - barrier(); - - bitonicSort(dataSize); - barrier(); - - for(uint i=laneID; i=surfels.length()) - continue; - - const Candidate p = alloc.candidate[data[i].idx]; - Surfel sx; - sx.pos = p.pos; - sx.norm = encodeNormal(p.norm); - sx.radius = p.radius; - sx.radiusPix = DefaultCoverage; - sx.irradiance = vec3(p.weight); // surfDebugColor(p.pos, surfelId); - - surfels[surfelId] = sx; - } - } \ No newline at end of file diff --git a/shader/lighting/surfels/surf_tile_normalize.comp b/shader/lighting/surfels/surf_tile_normalize.comp deleted file mode 100644 index fe3d50a4e..000000000 --- a/shader/lighting/surfels/surf_tile_normalize.comp +++ /dev/null @@ -1,49 +0,0 @@ -#version 460 - -#include "lighting/surfels/surf_common.glsl" - -layout(local_size_x = 256) in; - -const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; - -layout(binding = 7, r32ui) uniform uimage2D surfCnts; -layout(binding = 8, r32ui) uniform uimage2D surfBins; -layout(binding = 9, r32f) uniform image2D surfPdf; - -shared float reduction[NumThreads]; - -void reducePdf(float w) { - uint laneID = gl_LocalInvocationIndex; - - reduction[laneID] = w; - barrier(); - - for(uint stride = NumThreads/2; stride > 0; stride >>= 1) { - if(laneID < stride) { - reduction[laneID] += reduction[laneID + stride]; - } - barrier(); - } - } - -void main() { - const ivec2 imgSize = imageSize(surfPdf); - const int numTiles = imgSize.x*imgSize.y; - - float pdfSum = 0; - for(uint i=gl_LocalInvocationIndex; i 0; stride >>= 1) { - barrier(); - if(laneID < stride) { - reduction[laneID] += reduction[laneID + stride]; - } - } - } - -void main() { - const ivec2 tileId = ivec2(gl_WorkGroupID.xy); - const uint cnt = imageLoad(surfCnts, tileId).x; - const uint ptr = imageLoad(surfBins, tileId).x; - - float wSum = 0; - for(uint i=gl_LocalInvocationIndex; iaccounted;) { - --i; - const SurfelAlloc s = pointQueue[i]; - wSum += calculteWeight(s,pointRMax[i],wpos,norm); - if(wSum > 1.0) - return 1.0; - } - return wSum; - } - -void fragCoverageVote(float wSum) { - uint w = floatBitsToUint(wSum) & 0xFFFF0000; - uint b = uint(w) | uint(gl_LocalInvocationIndex) ^ Salt; - atomicMin(fragVote, b); - } - -void storeSurfels() { - const uint laneID = gl_LocalInvocationIndex; - - if(laneID==0) { - pointQueueSize = min(pointQueueSize, pointQueue.length()); - fragVote = atomicAdd(alloc.count.x, pointQueueSize); - } - barrier(); - - if(laneIDprevQueue.length()); - - barrier(); - - for(uint i=laneID; i Edge) { - uint w = floatBitsToUint(wsurf) & 0xFFFF0000; - uint b = uint(w) | uint(laneID); - atomicMax(reuseVote, b); - } - } - } - -void reuseSurfel(uint reuseId) { - pointQueue[pointQueueSize] = prevQueue[reuseId]; - pointRMax [pointQueueSize] = prevRMax [reuseId]; - pointQueueSize++; - - prevQueue[reuseId] = prevQueue[prevQueueSize-1]; - prevRMax [reuseId] = prevRMax [prevQueueSize-1]; - prevQueueSize--; - } - -void allocSurfel(vec3 wpos, vec3 norm, float sz) { - SurfelAlloc s; - s.pos = vec4(wpos, sz*2.0); - s.norm = norm; - s.reuseId = 0xFFFFFFFF; - pointQueue[pointQueueSize] = s; - pointRMax [pointQueueSize] = sz; - pointQueueSize++; - } - -void reuseOrAlloc(ivec2 fragCoord, const ivec2 screenSize, const uint vote) { - const uint laneID = gl_LocalInvocationIndex; - - const uint id = (vote & 0xFFFF) ^ Salt; - fragCoord.x += int(id % gl_WorkGroupSize.x); - fragCoord.y += int(id / gl_WorkGroupSize.x); - - const vec3 norm = normalFetch(gbufNormal, fragCoord); - const float z = texelFetch(depth, fragCoord, 0).x; - const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); - - reuseSurfelVote(wpos, norm); - barrier(); - - const uint reuseId = reuseVote & 0x0000FFFF; - barrier(); - - if(reuseId!=0x0000FFFF) { - if(laneID==0) { - reuseVote = 0x0000FFFF; - reuseSurfel(reuseId); - } - return; - } - - if(laneID==0) { - const float sz = max(pixelToWorld(DefaultCoverage, z), 0); - allocSurfel(wpos, norm, sz); - } - } - -void mainSubtile(const ivec2 at, const ivec2 fragCoord, const ivec2 screenSize) { - const bool valid = all(lessThan(fragCoord, screenSize)); - const float z = valid ? texelFetch(depth,fragCoord,0).x : 1.0; - const bool sky = (z >= SKY_DEPTH); - - const vec3 norm = normalFetch(gbufNormal, fragCoord); - const vec3 wpos = worldPos(z, norm, fragCoord, screenSize); - - float coverage = (sky ? 1.0 : estimateCoverage(fragCoord, wpos, norm, 0)); - for(int i=0; i=pointQueue.length()) - break; - - if(coverage<1.0) - fragCoverageVote(coverage); - barrier(); - - const uint vote = fragVote; - barrier(); - - fragVote = 0xFFFFFFFF; - if((vote & 0xFFFF0000)==0xFFFF0000) - break; - - reuseOrAlloc(at, screenSize, vote); - barrier(); - - coverage += amendCoverage(fragCoord, wpos, norm); - } - - imageStore(dbgImage, fragCoord, vec4(coverage)); - } - -ivec2 remap(ivec2 subtile, ivec2 tileCnt) { - // shuffle sub-tiles a little - uint k = uint(subtile.y * tileCnt.x + subtile.x); - k ^= 0x12; - k &= uint(NumThreads-1); - return ivec2(int(k % tileCnt.x), int(k / tileCnt.x)); - } - -void main() { - // if(gl_WorkGroupID.xy!=uvec2(8,5) && gl_WorkGroupID.xy!=uvec2(8,6)) - // return; - if(!(7 < gl_WorkGroupID.x && gl_WorkGroupID.x<=9 && - 3 < gl_WorkGroupID.y && gl_WorkGroupID.y<=6)) - ;//return; - - pointQueueSize = 0; - prevQueueSize = 0; - fragVote = 0xFFFFFFFF; - reuseVote = 0x0000FFFF; - barrier(); - - const ivec2 tileId = ivec2(gl_WorkGroupID.xy*TileSize)/int(TileSize); - loadTile(tileId); - barrier(); - - const ivec2 screenSize = ivec2(textureSize(depth,0)); - const ivec2 tileCount = TileSize/ivec2(gl_WorkGroupSize.xy); - for(int y=0; y 0; stride >>= 1) { - if(laneID < stride) { - reduction[laneID] += reduction[laneID + stride]; - } - barrier(); - } - } - -float wangHashNoise(uvec2 uv, uint s) { - uint seed = (uv.x*1664525u + uv.y) + s; - uint hash = wangHash(seed) & 0xFFFF; - return float(hash) / float(0xFFFF); - } - -void main() { - const uint surfelId = gl_WorkGroupID.x; - const Candidate p = alloc.candidate[surfelId]; - const vec3 wpos = p.pos; - const vec3 norm = p.norm; - - const ivec2 tileId = p.fragCoord/int(tileSize); - const uint cnt = imageLoad(surfCnts, tileId).x; - const uint ptr = imageLoad(surfBins, tileId).x; - - float wSum = 0; - for(uint i=gl_LocalInvocationIndex; i Date: Mon, 29 Jun 2026 22:30:50 +0200 Subject: [PATCH 46/52] cleanup --- game/graphics/renderer.cpp | 85 +++++++++++++------ game/graphics/renderer.h | 3 +- game/graphics/shaders.cpp | 3 +- game/graphics/shaders.h | 2 +- shader/CMakeLists.txt | 3 +- shader/lighting/surfels/surf_alloc.comp | 8 +- shader/lighting/surfels/surf_apply.comp | 41 ++++++--- .../{surf_binning.comp => surf_bin_pass.comp} | 29 +++---- shader/lighting/surfels/surf_common.glsl | 7 ++ shader/lighting/surfels/surf_compact.comp | 15 ++-- shader/lighting/surfels/surf_init.comp | 9 +- shader/lighting/surfels/surf_pathtrace.comp | 12 +-- 12 files changed, 137 insertions(+), 80 deletions(-) rename shader/lighting/surfels/{surf_binning.comp => surf_bin_pass.comp} (82%) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 808e75061..8e5f01cad 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1960,8 +1960,8 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor const auto binCount = tileCount(zbuffer.size(), DefaultCoverage); auto& scene = wview.sceneGlobals(); - auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); - auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::RGBA16F, zbuffer.size()); + auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); + auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::RGBA16F, zbuffer.size()); auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc.sizeofBuffer(4, maxSurfels)); auto& surfUsage = usesSsboInit(surf.surfUsage, usageWords*sizeof(uint32_t)); @@ -1973,17 +1973,19 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor struct Push { Vec3 originLwc; uint32_t tileSize; + uint32_t pass; } push = {}; push.originLwc = scene.originLwc; push.tileSize = uint32_t(tileSize); + push.pass = 0; cmd.setDebugMarker("Surfels"); // prev-frame - surfelsBinning(cmd, wview, tileSize, false); - static bool gc = true; if(gc) { + surfelsBinning(cmd, wview, tileSize, false); + struct PushGc { uint32_t pass; uint32_t tileSize; @@ -2010,13 +2012,17 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setPipeline(shaders.surfCompact); cmd.dispatch(1); + } - // bin one more time, for sake of apply pass - surfelsBinning(cmd, wview, tileSize, false); + static bool rays = true; + if(rays) { + surfelsTrace(cmd, wview, surfels, false); } static bool apply = true; if(apply) { + surfelsBinning(cmd, wview, tileSize, false); + cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, irrImage, Sampler::nearest()); @@ -2057,31 +2063,33 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatch(tc); } - static bool rays = false; if(rays) { - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, surfels); - cmd.setBinding(2, sky.viewCldLut); - // - cmd.setBinding(6, scene.rtScene.tlas); - cmd.setBinding(7, Sampler::trillinear()); - cmd.setBinding(8, scene.rtScene.tex); - cmd.setBinding(9, scene.rtScene.vbo); - cmd.setBinding(10,scene.rtScene.ibo); - cmd.setBinding(11,scene.rtScene.rtDesc); - - cmd.setPipeline(shaders.surfPathtrace); - //cmd.dispatchThreads(maxSurfels); - cmd.dispatchIndirect(surfels, 0); //NOTE: need to split into old/new + surfelsTrace(cmd, wview, surfels, true); } - //surfelsBinning(cmd, wview, tileSize, false); if(apply) { - //TODO: patch pass + surfelsBinning(cmd, wview, tileSize, true); + + push.pass = 1; + cmd.setPushData(push); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, irrImage, Sampler::nearest()); + cmd.setBinding(2, gbufNormal, Sampler::nearest()); + cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(4, surfels); + cmd.setBinding(5, surfUsage); + cmd.setBinding(6, surfCnts); + cmd.setBinding(7, surfBins); + cmd.setBinding(8, surfList); + // + cmd.setBinding(11, dbgImage); + + cmd.setPipeline(shaders.surfApply); + cmd.dispatchThreads(zbuffer.size()); } } -void Renderer::surfelsBinning(Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool alloc) { +void Renderer::surfelsBinning(Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool postPass) { const uint32_t maxSurfels = surf.maxSurfels; auto& scene = wview.sceneGlobals(); @@ -2090,13 +2098,14 @@ void Renderer::surfelsBinning(Tempest::Encoder& cmd, Wor auto& surfCnts = surf.surfCnts; auto& surfBins = surf.surfBins; auto& surfList = surf.surfList; - auto& surfBinning = shaders.surfBinningS; struct Push { int32_t tileSize; int32_t allocPass; + int32_t postPass; } push = {}; push.tileSize = tileSize; + push.postPass = postPass ? 1 : 0; cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); @@ -2111,7 +2120,7 @@ void Renderer::surfelsBinning(Tempest::Encoder& cmd, Wor push.allocPass = 0; cmd.setPushData(push); - cmd.setPipeline(surfBinning); + cmd.setPipeline(shaders.surfBinPass); cmd.dispatchThreads(maxSurfels); //TODO: indirect cmd.setPipeline(shaders.surfBinAlloc); @@ -2119,10 +2128,32 @@ void Renderer::surfelsBinning(Tempest::Encoder& cmd, Wor push.allocPass = 1; cmd.setPushData(push); - cmd.setPipeline(surfBinning); + cmd.setPipeline(shaders.surfBinPass); cmd.dispatchThreads(maxSurfels); } +void Renderer::surfelsTrace(Tempest::Encoder& cmd, WorldView& wview, StorageBuffer& surfels, bool postPass) { + auto& scene = wview.sceneGlobals(); + + uint32_t pass = 1; + cmd.setPushData(pass); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, surfels); + cmd.setBinding(2, sky.viewCldLut); + // + cmd.setBinding(6, scene.rtScene.tlas); + cmd.setBinding(7, Sampler::trillinear()); + cmd.setBinding(8, scene.rtScene.tex); + cmd.setBinding(9, scene.rtScene.vbo); + cmd.setBinding(10,scene.rtScene.ibo); + cmd.setBinding(11,scene.rtScene.rtDesc); + + cmd.setPipeline(shaders.surfPathtrace); + //cmd.dispatchThreads(maxSurfels); + const uint32_t offset = postPass ? sizeof(uint32_t) : 0; + cmd.dispatchIndirect(surfels, offset); + } + void Renderer::prepareIrradiance(Encoder& cmd, WorldView& wview) { auto& scene = wview.sceneGlobals(); diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index 4d54875bc..ec9ca79c0 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -66,7 +66,8 @@ class Renderer final { void prepareEpipolar (Tempest::Encoder& cmd, WorldView& wview); void prepareSurfels (Tempest::Encoder& cmd, WorldView& wview); - void surfelsBinning (Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool alloc); + void surfelsBinning (Tempest::Encoder& cmd, WorldView& wview, int32_t tileSize, bool postPass); + void surfelsTrace (Tempest::Encoder& cmd, WorldView& wview, Tempest::StorageBuffer& surfels, bool postPass); void drawHiZ (Tempest::Encoder& cmd, WorldView& view); void buildHiZ (Tempest::Encoder& cmd); diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index d8d14adaa..17405f7e9 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -249,8 +249,7 @@ void Shaders::compileShaders() { auto fs = device.shader(sh.data,sh.len); surfDbg = device.pipeline(Triangles,state,vs,fs); - surfBinningS = computeShader("surf_binning_s.comp.sprv"); - surfBinningA = computeShader("surf_binning_a.comp.sprv"); + surfBinPass = computeShader("surf_bin_pass.comp.sprv"); surfBinClear = computeShader("surf_bin_clear.comp.sprv"); surfBinAlloc = computeShader("surf_bin_alloc.comp.sprv"); surfBinSort = computeShader("surf_bin_sort.comp.sprv"); diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 62a7a44b8..26cd90dbe 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -88,7 +88,7 @@ class Shaders { // GI-Surf Tempest::RenderPipeline surfDbg; - Tempest::ComputePipeline surfBinClear, surfBinningS, surfBinningA, surfBinAlloc, surfBinSort; + Tempest::ComputePipeline surfBinClear, surfBinPass, surfBinAlloc, surfBinSort; Tempest::ComputePipeline surfInit; Tempest::ComputePipeline surfAlloc, surfApply, surfDecimate, surfCompact; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index fea169579..7b4c22833 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -321,8 +321,7 @@ add_shader(surf_decimate.comp lighting/surfels/surf_decimate.comp) add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) -add_shader(surf_binning_s.comp lighting/surfels/surf_binning.comp -DSURFEL) -add_shader(surf_binning_a.comp lighting/surfels/surf_binning.comp -DALLOC) +add_shader(surf_bin_pass.comp lighting/surfels/surf_bin_pass.comp) add_shader(surf_bin_sort.comp lighting/surfels/surf_bin_sort.comp) add_shader(surf_pathtrace.comp lighting/surfels/surf_pathtrace.comp) diff --git a/shader/lighting/surfels/surf_alloc.comp b/shader/lighting/surfels/surf_alloc.comp index f668603d8..360a6eba8 100644 --- a/shader/lighting/surfels/surf_alloc.comp +++ b/shader/lighting/surfels/surf_alloc.comp @@ -23,7 +23,7 @@ layout(binding = 0, std140) uniform UboScene { layout(binding = 1) uniform texture2D irradiance; layout(binding = 2) uniform utexture2D gbufNormal; layout(binding = 3) uniform texture2D depth; -layout(binding = 4, std430) buffer SB0 { uvec4 count; Surfel surfels[]; } surf; +layout(binding = 4, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; } surf; // layout(binding = 6, r32ui) uniform uimage2D surfCnts; layout(binding = 7, r32ui) uniform uimage2D surfBins; @@ -91,8 +91,8 @@ void storeSurfels() { if(laneID==0) { pointQueueSize = min(pointQueueSize, pointQueue.length()); - fragVote = atomicAdd(surf.count.x, pointQueueSize); - atomicAdd(surf.count.w, pointQueueSize); + fragVote = atomicAdd(surf.header.count, pointQueueSize); + atomicAdd(surf.header.added, pointQueueSize); } barrier(); @@ -107,7 +107,7 @@ void storeSurfels() { sx.norm = encodeNormal(p.norm); sx.radius = r; sx.radiusMean = p.pos.w; - sx.irradiance = debugColors[(gl_WorkGroupID.x*32+gl_WorkGroupID.y)%debugColors.length()]; //surfDebugColor(p.pos.xyz, ptr); + sx.irradiance = debugColors[(gl_WorkGroupID.x*32+gl_WorkGroupID.y)%debugColors.length()] * scene.exposure; sx.radiusPix = DefaultCoverage; surf.surfels[ptr] = sx; } diff --git a/shader/lighting/surfels/surf_apply.comp b/shader/lighting/surfels/surf_apply.comp index 103491a7d..8c7a00478 100644 --- a/shader/lighting/surfels/surf_apply.comp +++ b/shader/lighting/surfels/surf_apply.comp @@ -11,6 +11,7 @@ const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z layout(std140, push_constant) uniform Push { vec3 originLwc; uint tileSize; + uint pass; }; layout(binding = 0, std140) uniform UboScene { SceneDesc scene; @@ -18,7 +19,7 @@ layout(binding = 0, std140) uniform UboScene { layout(binding = 1, rgba16f) uniform image2D irradiance; layout(binding = 2) uniform utexture2D gbufNormal; layout(binding = 3) uniform texture2D depth; -layout(binding = 4, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 4, std430) readonly buffer SB0 { SurfHeader header; Surfel surfels[]; }; layout(binding = 5, std430) buffer SB1 { uint usage[]; }; layout(binding = 6, r32ui) uniform uimage2D surfCnts; layout(binding = 7, r32ui) uniform uimage2D surfBins; @@ -51,9 +52,6 @@ void applyBatch(inout vec4 clr, const vec3 wpos, const vec3 norm, const uint sur void pullSurfels(ivec2 bboxMin, ivec2 bboxMax, uint ptr, uint cnt, uint i) { const uint laneID = gl_LocalInvocationIndex; - surfelCount = 0; - barrier(); - if(i >= cnt) return; @@ -84,6 +82,9 @@ void main() { const uint cnt = imageLoad(surfCnts, tileId).x; const uint ptr = imageLoad(surfBins, tileId).x; + if(pass>0 && cnt==0) + return; + const float z = valid ? texelFetch(depth,fragCoord,0).x : 1; const vec3 wpos = worldPos(z, fragCoord, screenSize); const vec3 norm = normalFetch(gbufNormal, fragCoord); @@ -92,29 +93,47 @@ void main() { ivec2 bboxMin = ivec2(gl_WorkGroupID.xy*gl_WorkGroupSize.xy); ivec2 bboxMax = bboxMin + ivec2(gl_WorkGroupSize.xy); + surfelCount = 0; + vec4 clr = vec4(0); - for(uint i=0; ; i+=NumThreads) { + for(uint i=0; i=cnt) - break; barrier(); + + surfelCount = 0; } - if(!valid || sky) { + if(!valid) + return; + + if(sky) { imageStore(irradiance, fragCoord, vec4(0,0,0,1)); imageStore(dbgImage, fragCoord, vec4(1)); return; } - if(clr.a>0) - clr.rgb /= clr.a; clr.rgb *= scene.exposure; - imageStore(irradiance, fragCoord, vec4(clr.rgb, clr.a)); + if(pass==0) { + // first pass + if(clr.a>0) + clr.rgb /= clr.a; + imageStore(irradiance, fragCoord, vec4(clr)); + } else { + // post pass + const vec4 pre = imageLoad(irradiance, fragCoord); + clr += vec4(pre.rgb*pre.a, pre.a); + if(clr.a>0) + clr.rgb /= clr.a; + imageStore(irradiance, fragCoord, vec4(clr.rgb, clr.a)); + } + imageStore(dbgImage, fragCoord, vec4(clr.a)); } diff --git a/shader/lighting/surfels/surf_binning.comp b/shader/lighting/surfels/surf_bin_pass.comp similarity index 82% rename from shader/lighting/surfels/surf_binning.comp rename to shader/lighting/surfels/surf_bin_pass.comp index 811a17284..069e4a340 100644 --- a/shader/lighting/surfels/surf_binning.comp +++ b/shader/lighting/surfels/surf_bin_pass.comp @@ -9,19 +9,14 @@ layout(local_size_x = 64) in; layout(std140, push_constant) uniform Push { int tileSize; int allocPass; + int postPass; }; layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; layout(binding = 1, std430) buffer SB0 { uint binAlloc; }; -#if defined(SURFEL) -layout(binding = 2, std430) buffer SB1 { uvec4 count; Surfel surfels[]; }; -#elif defined(ALLOC) -layout(binding = 2, std430) readonly buffer SB1 { uvec4 count; Candidate surfels[]; }; -#else -#error "Unknown shader varriant" -#endif +layout(binding = 2, std430) buffer SB1 { SurfHeader header; Surfel surfels[]; } surf; layout(binding = 3, r32ui) uniform uimage2D surfCnts; layout(binding = 4, r32ui) uniform readonly uimage2D surfBins; layout(binding = 5, std430) buffer SB2 { uint surfelIds[]; }; @@ -73,11 +68,12 @@ int worldToPixel(const vec3 pos, float R) { void main() { const uint surfelId = gl_GlobalInvocationID.x; - if(surfelId>=count.x) + if(surfelId>=surf.header.count) + return; + if(surfelId=count.x) - return; - + const uint surfelId = pass==0 ? gl_WorkGroupID.x : (header.count-gl_WorkGroupID.z-1); + // if(surfelId>=header.count) + // return; const Surfel p = surfels[surfelId]; const mat3 tbn = toTangent(decodeNormal(p.norm)); From 7567851bdc0584baf49dd62780232613288feb54 Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 30 Jun 2026 00:32:33 +0200 Subject: [PATCH 47/52] refactor away frustrum culling and state update --- game/graphics/renderer.cpp | 32 +++-- game/graphics/shaders.cpp | 7 +- game/graphics/shaders.h | 3 +- shader/CMakeLists.txt | 7 +- shader/lighting/surfels/surf_bin_pass.comp | 62 +--------- shader/lighting/surfels/surf_culling.comp | 135 +++++++++++++++++++++ shader/lighting/surfels/surf_decimate.comp | 7 +- shader/lighting/surfels/surf_update.comp | 88 ++++++++++++++ 8 files changed, 268 insertions(+), 73 deletions(-) create mode 100644 shader/lighting/surfels/surf_culling.comp create mode 100644 shader/lighting/surfels/surf_update.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 8e5f01cad..4095925b7 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1982,6 +1982,21 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setDebugMarker("Surfels"); // prev-frame + { + float znear = scene.znear; + cmd.setPushData(znear); + cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, hiz.hiZ); + cmd.setBinding(2, zbuffer); + cmd.setBinding(3, surfels); + + cmd.setPipeline(shaders.surfUpdate); + cmd.dispatchThreads(maxSurfels); + + cmd.setPipeline(shaders.surfCulling); + cmd.dispatchThreads(maxSurfels); + } + static bool gc = true; if(gc) { surfelsBinning(cmd, wview, tileSize, false); @@ -1992,6 +2007,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor } pushGc = {}; cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); + cmd.setBinding(1, hiz.hiZ); // cmd.setBinding(4, surfels); cmd.setBinding(5, surfUsage); @@ -2025,9 +2041,9 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, irrImage, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(1, irrImage); + cmd.setBinding(2, gbufNormal); + cmd.setBinding(3, zbuffer); cmd.setBinding(4, surfels); cmd.setBinding(5, surfUsage); cmd.setBinding(6, surfCnts); @@ -2040,13 +2056,14 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.dispatchThreads(zbuffer.size()); } + // current-frame static bool alloc = true; if(alloc) { cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, irrImage, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(1, irrImage); + cmd.setBinding(2, gbufNormal); + cmd.setBinding(3, zbuffer); cmd.setBinding(4, surfels); // cmd.setBinding(6, surfCnts); @@ -2055,9 +2072,6 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor // cmd.setBinding(11, dbgImage); - //cmd.setPipeline(shaders.surfInit); - //cmd.dispatchThreads(1); //for sake of zeroing counters - const auto tc = tileCount(zbuffer.size(), 128); cmd.setPipeline(shaders.surfAlloc); cmd.dispatch(tc); diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 17405f7e9..f1714dbd0 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -256,10 +256,13 @@ void Shaders::compileShaders() { surfInit = computeShader("surf_init.comp.sprv"); + surfUpdate = computeShader("surf_update.comp.sprv"); + surfCulling = computeShader("surf_culling.comp.sprv"); + surfDecimate = computeShader("surf_decimate.comp.sprv"); + surfCompact = computeShader("surf_compact.comp.sprv"); + surfAlloc = computeShader("surf_alloc.comp.sprv"); surfApply = computeShader("surf_apply.comp.sprv"); - surfCompact = computeShader("surf_compact.comp.sprv"); - surfDecimate = computeShader("surf_decimate.comp.sprv"); surfPathtrace = computeShader("surf_pathtrace.comp.sprv"); } diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index 26cd90dbe..dfee816f4 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -91,7 +91,8 @@ class Shaders { Tempest::ComputePipeline surfBinClear, surfBinPass, surfBinAlloc, surfBinSort; Tempest::ComputePipeline surfInit; - Tempest::ComputePipeline surfAlloc, surfApply, surfDecimate, surfCompact; + Tempest::ComputePipeline surfAlloc, surfApply; + Tempest::ComputePipeline surfUpdate, surfCulling, surfDecimate, surfCompact; Tempest::ComputePipeline surfPathtrace; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 7b4c22833..6d634ecd1 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -314,10 +314,13 @@ add_shader(surf_dbg.frag lighting/surfels/surf_dbg.frag) add_shader(surf_init.comp lighting/surfels/surf_init.comp) +add_shader(surf_update.comp lighting/surfels/surf_update.comp) +add_shader(surf_culling.comp lighting/surfels/surf_culling.comp) +add_shader(surf_decimate.comp lighting/surfels/surf_decimate.comp) +add_shader(surf_compact.comp lighting/surfels/surf_compact.comp) + add_shader(surf_alloc.comp lighting/surfels/surf_alloc.comp) add_shader(surf_apply.comp lighting/surfels/surf_apply.comp) -add_shader(surf_compact.comp lighting/surfels/surf_compact.comp) -add_shader(surf_decimate.comp lighting/surfels/surf_decimate.comp) add_shader(surf_bin_clear.comp lighting/surfels/surf_bin_clear.comp) add_shader(surf_bin_alloc.comp lighting/surfels/surf_bin_alloc.comp) diff --git a/shader/lighting/surfels/surf_bin_pass.comp b/shader/lighting/surfels/surf_bin_pass.comp index 069e4a340..5609cf938 100644 --- a/shader/lighting/surfels/surf_bin_pass.comp +++ b/shader/lighting/surfels/surf_bin_pass.comp @@ -16,56 +16,11 @@ layout(binding = 0, std140) uniform UboScene { }; layout(binding = 1, std430) buffer SB0 { uint binAlloc; }; -layout(binding = 2, std430) buffer SB1 { SurfHeader header; Surfel surfels[]; } surf; +layout(binding = 2, std430) readonly buffer SB1 { SurfHeader header; Surfel surfels[]; } surf; layout(binding = 3, r32ui) uniform uimage2D surfCnts; layout(binding = 4, r32ui) uniform readonly uimage2D surfBins; layout(binding = 5, std430) buffer SB2 { uint surfelIds[]; }; -vec4 projectSphere(const vec3 pos, float R) { - // https://jcgt.org/published/0002/02/05/paper.pdf - const vec4 viewPos = (scene.viewProject * vec4(pos.xyz, 1)); - const vec3 c = viewPos.xyz; - - if (c.z + R < 0.0) { - return vec4(-1); - } - - const float P00 = scene.project[0][0]; // fx - const float P11 = scene.project[1][1]; // fy - - vec3 cr = c * R; - float czr2 = c.z * c.z - R * R; - - float vx = sqrt(c.x * c.x + czr2); - float minx = (vx * c.x - cr.z) / (vx * c.z + cr.x); - float maxx = (vx * c.x + cr.z) / (vx * c.z - cr.x); - - float vy = sqrt(c.y * c.y + czr2); - float miny = (vy * c.y - cr.z) / (vy * c.z + cr.y); - float maxy = (vy * c.y + cr.z) / (vy * c.z - cr.y); - - vec4 aabb = vec4(minx * P00, miny * P11, maxx * P00, maxy * P11); - aabb = aabb*0.5 + vec4(0.5); - return vec4(floor(aabb.xy*scene.screenRes), ceil(aabb.zw*scene.screenRes)); - } - -float pixelToWorld(float pixelRadius, float z) { - z = linearDepth(z, scene.clipInfo); - - float clipRadiusX = (2.0 * pixelRadius) * scene.screenResInv.x; - float clipRadiusY = (2.0 * pixelRadius) * scene.screenResInv.y; - - float worldRadiusX = (clipRadiusX * z) / scene.project[0][0]; - float worldRadiusY = (clipRadiusY * z) / scene.project[1][1]; - return min(worldRadiusX, worldRadiusY); - } - -int worldToPixel(const vec3 pos, float R) { - vec4 area = projectSphere(pos, R); - vec2 sz = area.zw - area.xy; - return int( ceil(max(sz.x, sz.y)*0.5) ); - } - void main() { const uint surfelId = gl_GlobalInvocationID.x; if(surfelId>=surf.header.count) @@ -74,18 +29,11 @@ void main() { return; const Surfel p = surf.surfels[surfelId]; - const vec4 pos4 = scene.viewProject * vec4(p.pos, 1.0); - const vec2 posNdc = ((pos4.xy/pos4.w)*0.5+0.5); - const ivec2 fragCoord = ivec2(posNdc*scene.screenRes + 0.5); - const float rMin = pixelToWorld(MinCoverage, pos4.z/pos4.w); - const float rMax = pixelToWorld(DefaultCoverage, pos4.z/pos4.w); - const float radiusMean = max(rMin, min(p.radiusMean, rMax)); - const int radiusPix = DefaultCoverage; //min(worldToPixel(p.pos, p.radiusMean), DefaultCoverage); + const ivec2 fragCoord = p.fragCoord; + const int radiusPix = DefaultCoverage; - surf.surfels[surfelId].fragCoord = fragCoord; - surf.surfels[surfelId].radiusPix = radiusPix; - surf.surfels[surfelId].radius = rMax; - surf.surfels[surfelId].radiusMean = radiusMean; + if(p.radius==0) + return; ivec2 pos0 = ivec2(fragCoord-radiusPix)/tileSize; ivec2 pos1 = ivec2(fragCoord+radiusPix)/tileSize + 1; diff --git a/shader/lighting/surfels/surf_culling.comp b/shader/lighting/surfels/surf_culling.comp new file mode 100644 index 000000000..f10c89ee2 --- /dev/null +++ b/shader/lighting/surfels/surf_culling.comp @@ -0,0 +1,135 @@ +#version 460 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 64) in; + +layout(push_constant, std140) uniform Push { + float znear; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1) uniform texture2D hiZ; +layout(binding = 2) uniform texture2D depth; +layout(binding = 3, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; }; + +float hiZFetch(in texture2D hiZ, in ivec2 ibbox[2]) { + if(ibbox[0]==ibbox[1]) + return texelFetch(hiZ, ibbox[0], 0).x; + + const uint sz = max(ibbox[1].x-ibbox[0].x, ibbox[1].y-ibbox[0].y); + const int mip = findMSB(sz - 1) + 1; // log2 of next pot + + ibbox[0].x = (ibbox[0].x >> mip); + ibbox[0].y = (ibbox[0].y >> mip); + + ivec2 hiZsize = textureSize(hiZ,mip); + float z = texelFetchOffset(hiZ, ibbox[0], mip, ivec2(0,0)).x; + if(ibbox[0].x+1 z) + return false; + return true; + } + +bool projectSphere(const vec3 c, float R, out vec4 aabb, out float depthMin, out float depthMax) { + // https://jcgt.org/published/0002/02/05/paper.pdf + depthMin = scene.project[3][2]/max(c.z - R, znear) + scene.project[2][2]; + depthMax = scene.project[3][2]/max(c.z + R, znear) + scene.project[2][2]; + + if (c.z + R < 0.0) { + return false; + } + + const float P00 = scene.project[0][0]; // fx + const float P11 = scene.project[1][1]; // fy + + vec3 cr = c * R; + float czr2 = c.z * c.z - R * R; + + float vx = sqrt(c.x * c.x + czr2); + float minx = (vx * c.x - cr.z) / (vx * c.z + cr.x); + float maxx = (vx * c.x + cr.z) / (vx * c.z - cr.x); + + float vy = sqrt(c.y * c.y + czr2); + float miny = (vy * c.y - cr.z) / (vy * c.z + cr.y); + float maxy = (vy * c.y + cr.z) / (vy * c.z - cr.y); + + aabb = vec4(minx * P00, miny * P11, maxx * P00, maxy * P11); + aabb = aabb*0.5 + vec4(0.5); + return true; + } + +bool frustrumTest(const vec4 sphere) { + if(sphere.w<=0.f) + return false; + for(int i=0; i<6; ++i) { + if(dot(vec4(sphere.xyz,1.0), scene.frustrum[i]) <= -sphere.w) { + return false; + } + } + return true; + } + +bool isSurfelVisible(const vec4 p, float radiusMean, ivec2 fragCoord) { + if(!frustrumTest(p)) + return false; + + const vec3 viewPos = (scene.viewProject * vec4(p.xyz, 1)).xyz; + if(0<=fragCoord.x && fragCoord.x radiusMean) { + return false; + } + } + +#if 0 + vec4 aabb = vec4(0); + float depthMin=0, depthMax=0; + if(!projectSphere(viewPos, p.w, aabb, depthMin, depthMax)) + return false; + + if(!hiZTest(aabb, depthMin)) + return false; +#endif + + return true; + } + +void main() { + const uint surfelId = gl_GlobalInvocationID.x; + if(surfelId >= header.count) + return; + + const Surfel s = surfels[surfelId]; + if(isSurfelVisible(vec4(s.pos, s.radius), s.radiusMean, s.fragCoord)) + return; + + surfels[surfelId].radius = 0; + } diff --git a/shader/lighting/surfels/surf_decimate.comp b/shader/lighting/surfels/surf_decimate.comp index 67913252f..8ccf40a1a 100644 --- a/shader/lighting/surfels/surf_decimate.comp +++ b/shader/lighting/surfels/surf_decimate.comp @@ -16,7 +16,7 @@ layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; // -layout(binding = 4, std430) readonly buffer SB0 { uvec4 count; Surfel surfels[]; }; +layout(binding = 4, std430) readonly buffer SB0 { SurfHeader header; Surfel surfels[]; }; layout(binding = 5, std430) buffer SB1 { uint usage[]; }; layout(binding = 6, r32ui) uniform uimage2D surfCnts; layout(binding = 7, r32ui) uniform uimage2D surfBins; @@ -33,13 +33,16 @@ uint passId(ivec2 tileId) { void main() { const uint surfelId = gl_GlobalInvocationID.x; - if(surfelId >= count.x) + if(surfelId >= header.count) return; const float edge = 1.57; // .57 is prefference driven const Surfel p = surfels[surfelId]; const ivec2 sz = scene.screenRes; + if(p.radius==0) + return; // disabled + if(!(-DefaultCoverage <= p.fragCoord.x && p.fragCoord.x < sz.x+DefaultCoverage)) return; if(!(-DefaultCoverage <= p.fragCoord.y && p.fragCoord.y < sz.y+DefaultCoverage)) diff --git a/shader/lighting/surfels/surf_update.comp b/shader/lighting/surfels/surf_update.comp new file mode 100644 index 000000000..67540be99 --- /dev/null +++ b/shader/lighting/surfels/surf_update.comp @@ -0,0 +1,88 @@ +#version 460 + +#include "lighting/surfels/surf_common.glsl" +#include "scene.glsl" +#include "common.glsl" + +layout(local_size_x = 64) in; + +layout(push_constant, std140) uniform Push { + float znear; + }; +layout(binding = 0, std140) uniform UboScene { + SceneDesc scene; + }; +layout(binding = 1) uniform texture2D hiZ; +layout(binding = 2) uniform texture2D depth; +layout(binding = 3, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; }; + + +bool projectSphere(const vec3 c, float R, out vec4 aabb, out float depthMin, out float depthMax) { + // https://jcgt.org/published/0002/02/05/paper.pdf + depthMin = scene.project[3][2]/max(c.z - R, znear) + scene.project[2][2]; + depthMax = scene.project[3][2]/max(c.z + R, znear) + scene.project[2][2]; + + if (c.z + R < 0.0) { + return false; + } + + const float P00 = scene.project[0][0]; // fx + const float P11 = scene.project[1][1]; // fy + + vec3 cr = c * R; + float czr2 = c.z * c.z - R * R; + + float vx = sqrt(c.x * c.x + czr2); + float minx = (vx * c.x - cr.z) / (vx * c.z + cr.x); + float maxx = (vx * c.x + cr.z) / (vx * c.z - cr.x); + + float vy = sqrt(c.y * c.y + czr2); + float miny = (vy * c.y - cr.z) / (vy * c.z + cr.y); + float maxy = (vy * c.y + cr.z) / (vy * c.z - cr.y); + + aabb = vec4(minx * P00, miny * P11, maxx * P00, maxy * P11); + aabb = aabb*0.5 + vec4(0.5); + return true; + } + +float pixelToWorld(float pixelRadius, float z) { + z = linearDepth(z, scene.clipInfo); + + float clipRadiusX = (2.0 * pixelRadius) * scene.screenResInv.x; + float clipRadiusY = (2.0 * pixelRadius) * scene.screenResInv.y; + + float worldRadiusX = (clipRadiusX * z) / scene.project[0][0]; + float worldRadiusY = (clipRadiusY * z) / scene.project[1][1]; + return min(worldRadiusX, worldRadiusY); + } + +int worldToPixel(const vec3 pos, float R) { + vec4 aabb = vec4(0); + float depthMin=0, depthMax=0; + if(!projectSphere(pos, R, aabb, depthMin, depthMax)) + return 0; + ivec4 area = ivec4(aabb.xy * scene.screenRes, aabb.zw * scene.screenRes); + vec2 sz = area.zw - area.xy; + return int( ceil(max(sz.x, sz.y)*0.5) ); + } + +void main() { + const uint surfelId = gl_GlobalInvocationID.x; + if(surfelId >= header.count) + return; + + const Surfel s = surfels[surfelId]; + + const vec4 pos4 = scene.viewProject * vec4(s.pos, 1.0); + const vec2 posNdc = ((pos4.xy/pos4.w)*0.5+0.5); + const ivec2 fragCoord = ivec2(posNdc*scene.screenRes + 0.5); + const float rMin = pixelToWorld(MinCoverage, pos4.z/pos4.w); + const float rMax = pixelToWorld(DefaultCoverage, pos4.z/pos4.w); + const float radiusMean = max(rMin, min(s.radiusMean, rMax)); + const int radiusPix = DefaultCoverage; //min(worldToPixel(s.pos, s.radiusMean), DefaultCoverage); + + surfels[surfelId].fragCoord = fragCoord; + surfels[surfelId].radiusPix = radiusPix; + surfels[surfelId].radius = rMax; + surfels[surfelId].radiusMean = radiusMean; + } From 6405bc90c24348fc5328ebddca73f89692d86741 Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 30 Jun 2026 15:25:41 +0200 Subject: [PATCH 48/52] debug counter for surfels --- game/graphics/renderer.cpp | 1 + shader/common.glsl | 24 +++++++++++++++++++++ shader/lighting/ambient_light.frag | 8 +++++++ shader/lighting/surfels/surf_culling.comp | 2 ++ shader/rtsm/rtsm_dbg.frag | 24 --------------------- shader/virtual_shadow/vsm_direct_light.frag | 24 --------------------- 6 files changed, 35 insertions(+), 48 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 4095925b7..31bc31bd2 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -2510,6 +2510,7 @@ void Renderer::drawAmbient(Encoder& cmd, const WorldView& view) { auto& ao = (settings.zCloudShadowScale ? textureCast(ssao.ssaoBlur) : Resources::fallbackBlack()); cmd.setBinding(3, surf.irrImage, Sampler::nearest(ClampMode::ClampToEdge)); cmd.setBinding(4, ao, Sampler::nearest(ClampMode::ClampToEdge)); + cmd.setBinding(5, surf.surfels); cmd.setPipeline(shaders.ambientLightSurf); } else if(settings.giMethod==GiMethod::Probes && settings.zCloudShadowScale) { diff --git a/shader/common.glsl b/shader/common.glsl index 0b3d99feb..27b2ca928 100644 --- a/shader/common.glsl +++ b/shader/common.glsl @@ -394,4 +394,28 @@ vec3 dither(vec2 fragCoords, uvec3 targetBits) { return nrnd / divisionSteps; } +float drawInt(in vec2 where, in int n) { + const float RESOLUTION = 0.5; + int i=int((where*=RESOLUTION).y); + if(00 || n>0; n/=10) + if ((j+=4)<3 && j>=0) { + int x = 0; + if(i>4) + x = 972980223; + else if(i>3) + x = 690407533; + else if(i>2) + x = 704642687; + else if(i>1) + x = 696556137; + else + x = 972881535; + return float(x >> (29-j-(n%10)*3)&1); + } + } + return 0; + } + #endif diff --git a/shader/lighting/ambient_light.frag b/shader/lighting/ambient_light.frag index a63808b35..ee8fce61e 100644 --- a/shader/lighting/ambient_light.frag +++ b/shader/lighting/ambient_light.frag @@ -16,6 +16,7 @@ layout(binding = 2) uniform usampler2D gbufNormal; #if defined(SURFEL_GI) layout(binding = 3) uniform sampler2D surfGi; layout(binding = 4) uniform sampler2D ssao; +layout(binding = 5, std430) readonly buffer SB0 { uint count; } surf; #elif defined(SSAO) layout(binding = 3) uniform texture2D irradiance; layout(binding = 4) uniform sampler2D ssao; @@ -91,6 +92,13 @@ void main() { color *= scene.exposure; #endif +#if defined(SURFEL_GI) && 1 + if(drawInt(fragCoord.xy-ivec2(100,100), int(surf.count))>0) { + outColor = vec4(1); + return; + } +#endif + outColor = vec4(color, 1); // outColor = vec4(vec3(ao), 0); // outColor = vec4(linear, 0); diff --git a/shader/lighting/surfels/surf_culling.comp b/shader/lighting/surfels/surf_culling.comp index f10c89ee2..c1e57e92e 100644 --- a/shader/lighting/surfels/surf_culling.comp +++ b/shader/lighting/surfels/surf_culling.comp @@ -99,6 +99,7 @@ bool isSurfelVisible(const vec4 p, float radiusMean, ivec2 fragCoord) { if(!frustrumTest(p)) return false; +#if 0 const vec3 viewPos = (scene.viewProject * vec4(p.xyz, 1)).xyz; if(0<=fragCoord.x && fragCoord.x0 || n>0; n/=10) - if ((j+=4)<3 && j>=0) { - int x = 0; - if(i>4) - x = 972980223; - else if(i>3) - x = 690407533; - else if(i>2) - x = 704642687; - else if(i>1) - x = 696556137; - else - x = 972881535; - return float(x >> (29-j-(n%10)*3)&1); - } - } - return 0; - } - void main() { ivec2 fragCoord = ivec2(gl_FragCoord.xy); ivec2 tileSz = ivec2(32); diff --git a/shader/virtual_shadow/vsm_direct_light.frag b/shader/virtual_shadow/vsm_direct_light.frag index 7fca1923c..e2ddb7001 100644 --- a/shader/virtual_shadow/vsm_direct_light.frag +++ b/shader/virtual_shadow/vsm_direct_light.frag @@ -26,30 +26,6 @@ layout(binding = 8, r32ui) uniform readonly uimage2D dbg; layout(location = 0) out vec4 outColor; -float drawInt(in vec2 where, in int n) { - const float RESOLUTION = 0.5; - int i=int((where*=RESOLUTION).y); - if(00 || n>0; n/=10) - if ((j+=4)<3 && j>=0) { - int x = 0; - if(i>4) - x = 972980223; - else if(i>3) - x = 690407533; - else if(i>2) - x = 704642687; - else if(i>1) - x = 696556137; - else - x = 972881535; - return float(x >> (29-j-(n%10)*3)&1); - } - } - return 0; - } - uint hash(uvec3 src) { const uint M = 0x5bd1e995u; uint h = 1190494759u; From 911123a860ab2bc86107022927d88b1b40609156 Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 30 Jun 2026 19:28:21 +0200 Subject: [PATCH 49/52] fixup surfel culling --- shader/lighting/surfels/surf_alloc.comp | 7 ++++++- shader/lighting/surfels/surf_culling.comp | 11 +++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/shader/lighting/surfels/surf_alloc.comp b/shader/lighting/surfels/surf_alloc.comp index 360a6eba8..08aad1bb4 100644 --- a/shader/lighting/surfels/surf_alloc.comp +++ b/shader/lighting/surfels/surf_alloc.comp @@ -102,12 +102,17 @@ void storeSurfels() { SurfelAlloc p = pointQueue[laneID]; float r = pointRMax[laneID]; + const vec4 pos4 = scene.viewProject * vec4(p.pos.xyz, 1.0); + const vec2 posNdc = ((pos4.xy/pos4.w)*0.5+0.5); + const ivec2 fragCoord = ivec2(posNdc*scene.screenRes + 0.5); + Surfel sx; sx.pos = p.pos.xyz; sx.norm = encodeNormal(p.norm); + sx.fragCoord = fragCoord; sx.radius = r; sx.radiusMean = p.pos.w; - sx.irradiance = debugColors[(gl_WorkGroupID.x*32+gl_WorkGroupID.y)%debugColors.length()] * scene.exposure; + sx.irradiance = debugColors[(gl_WorkGroupID.x*32+gl_WorkGroupID.y)%debugColors.length()] / scene.exposure; sx.radiusPix = DefaultCoverage; surf.surfels[ptr] = sx; } diff --git a/shader/lighting/surfels/surf_culling.comp b/shader/lighting/surfels/surf_culling.comp index c1e57e92e..fdd0c4222 100644 --- a/shader/lighting/surfels/surf_culling.comp +++ b/shader/lighting/surfels/surf_culling.comp @@ -62,6 +62,7 @@ bool projectSphere(const vec3 c, float R, out vec4 aabb, out float depthMin, out depthMax = scene.project[3][2]/max(c.z + R, znear) + scene.project[2][2]; if (c.z + R < 0.0) { + // aabb = vec4(0,0,1,1); return false; } @@ -99,19 +100,21 @@ bool isSurfelVisible(const vec4 p, float radiusMean, ivec2 fragCoord) { if(!frustrumTest(p)) return false; -#if 0 - const vec3 viewPos = (scene.viewProject * vec4(p.xyz, 1)).xyz; + const vec3 viewPos = (scene.view * vec4(p.xyz, 1)).xyz; + +#if 1 if(0<=fragCoord.x && fragCoord.x radiusMean) { + if((lz-viewPos.z) > radiusMean) { + // TODO: two-sided HiZ return false; } } #endif -#if 0 +#if 1 vec4 aabb = vec4(0); float depthMin=0, depthMax=0; if(!projectSphere(viewPos, p.w, aabb, depthMin, depthMax)) From e821422f98e557e613546acfaad21a9b6df96b62 Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 30 Jun 2026 21:06:51 +0200 Subject: [PATCH 50/52] simplify surfel gc --- game/graphics/renderer.cpp | 53 +++++++++------------- game/graphics/renderer.h | 2 +- shader/lighting/surfels/surf_compact.comp | 10 +--- shader/lighting/surfels/surf_decimate.comp | 31 ++----------- shader/lighting/surfels/surf_update.comp | 46 +------------------ 5 files changed, 31 insertions(+), 111 deletions(-) diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index 31bc31bd2..a62f0707b 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1954,7 +1954,6 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor return; const uint32_t maxSurfels = surf.maxSurfels; - const uint32_t usageWords = (maxSurfels+32-1)/32; const int32_t tileSize = 128; const int32_t DefaultCoverage = 128; const auto binCount = tileCount(zbuffer.size(), DefaultCoverage); @@ -1962,9 +1961,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor auto& scene = wview.sceneGlobals(); auto& dbgImage = usesImage2d (surf.dbgImage, TextureFormat::RGBA8, zbuffer.size()); auto& irrImage = usesImage2d (surf.irrImage, TextureFormat::RGBA16F, zbuffer.size()); - - auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc.sizeofBuffer(4, maxSurfels)); - auto& surfUsage = usesSsboInit(surf.surfUsage, usageWords*sizeof(uint32_t)); + auto& surfels = usesSsboInit(surf.surfels, shaders.surfAlloc.sizeofBuffer(4, maxSurfels)); auto& surfCnts = usesImage2d(surf.surfCnts, TextureFormat::R32U, binCount); auto& surfBins = usesImage2d(surf.surfBins, TextureFormat::R32U, binCount); @@ -1983,48 +1980,37 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor // prev-frame { - float znear = scene.znear; - cmd.setPushData(znear); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, hiz.hiZ); - cmd.setBinding(2, zbuffer); - cmd.setBinding(3, surfels); + cmd.setBinding(1, zbuffer); + cmd.setBinding(2, surfels); cmd.setPipeline(shaders.surfUpdate); cmd.dispatchThreads(maxSurfels); - - cmd.setPipeline(shaders.surfCulling); - cmd.dispatchThreads(maxSurfels); } static bool gc = true; if(gc) { surfelsBinning(cmd, wview, tileSize, false); - struct PushGc { - uint32_t pass; - uint32_t tileSize; - } pushGc = {}; - cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, hiz.hiZ); + cmd.setBinding(2, zbuffer); + cmd.setBinding(3, surfels); // - cmd.setBinding(4, surfels); - cmd.setBinding(5, surfUsage); cmd.setBinding(6, surfCnts); cmd.setBinding(7, surfBins); cmd.setBinding(8, surfList); + cmd.setPushData(scene.znear); + cmd.setPipeline(shaders.surfCulling); + cmd.dispatchThreads(maxSurfels); + + cmd.setPushData(push); cmd.setPipeline(shaders.surfBinSort); // assist with stable GC cmd.dispatch(surfBins.size()); cmd.setPipeline(shaders.surfDecimate); - for(uint32_t pass=0; pass<3; ++pass) { - pushGc.pass = pass; - pushGc.tileSize = uint32_t(tileSize); - cmd.setPushData(pushGc); - cmd.dispatchThreads(maxSurfels); - } + cmd.dispatchThreads(maxSurfels); cmd.setPipeline(shaders.surfCompact); cmd.dispatch(1); @@ -2045,7 +2031,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor cmd.setBinding(2, gbufNormal); cmd.setBinding(3, zbuffer); cmd.setBinding(4, surfels); - cmd.setBinding(5, surfUsage); + // cmd.setBinding(6, surfCnts); cmd.setBinding(7, surfBins); cmd.setBinding(8, surfList); @@ -2087,11 +2073,11 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor push.pass = 1; cmd.setPushData(push); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); - cmd.setBinding(1, irrImage, Sampler::nearest()); - cmd.setBinding(2, gbufNormal, Sampler::nearest()); - cmd.setBinding(3, zbuffer, Sampler::nearest()); + cmd.setBinding(1, irrImage); + cmd.setBinding(2, gbufNormal); + cmd.setBinding(3, zbuffer); cmd.setBinding(4, surfels); - cmd.setBinding(5, surfUsage); + // cmd.setBinding(6, surfCnts); cmd.setBinding(7, surfBins); cmd.setBinding(8, surfList); @@ -2149,7 +2135,7 @@ void Renderer::surfelsBinning(Tempest::Encoder& cmd, Wor void Renderer::surfelsTrace(Tempest::Encoder& cmd, WorldView& wview, StorageBuffer& surfels, bool postPass) { auto& scene = wview.sceneGlobals(); - uint32_t pass = 1; + const uint32_t pass = postPass ? 1 : 0; cmd.setPushData(pass); cmd.setBinding(0, scene.uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, surfels); @@ -2449,7 +2435,10 @@ void Renderer::drawRayQueryDbg(Tempest::Encoder& cmd, co } void Renderer::drawSurfelsDbg(Encoder& cmd, const WorldView& wview) { - static bool enable = true; + if(settings.giMethod!=GiMethod::IrrC) + return; + + static bool enable = false; if(!enable) return; diff --git a/game/graphics/renderer.h b/game/graphics/renderer.h index ec9ca79c0..576b74f8b 100644 --- a/game/graphics/renderer.h +++ b/game/graphics/renderer.h @@ -214,7 +214,7 @@ class Renderer final { struct { const uint32_t maxSurfels = 16*1024; - Tempest::StorageBuffer surfels, surfUsage; + Tempest::StorageBuffer surfels; Tempest::StorageImage irrImage; Tempest::StorageImage surfCnts, surfBins; diff --git a/shader/lighting/surfels/surf_compact.comp b/shader/lighting/surfels/surf_compact.comp index 7b2919f33..e7b06d16f 100644 --- a/shader/lighting/surfels/surf_compact.comp +++ b/shader/lighting/surfels/surf_compact.comp @@ -8,8 +8,7 @@ layout(local_size_x = 256) in; const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; -layout(binding = 4, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; } surf; -layout(binding = 5, std430) buffer SB1 { uint usage[]; }; +layout(binding = 3, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; } surf; shared uint wPtr; @@ -22,8 +21,7 @@ void main() { Surfel sx; for(uint ix=0; ix0; if(keep) { sx = surf.surfels[i]; } @@ -42,8 +40,4 @@ void main() { surf.header.one2 = 1; surf.header.added = 0; } - - for(uint i=laneID; i= header.count) @@ -52,8 +43,6 @@ void main() { const vec3 norm = decodeNormal(p.norm); const ivec2 tileId = (p.fragCoord/int(tileSize)); - if(passId(tileId)!=pass) - return; const ivec2 cTileId = clamp(tileId, ivec2(0), imageSize(surfCnts)-1); const uint cnt = imageLoad(surfCnts, cTileId).x; @@ -66,29 +55,19 @@ void main() { break; // surfels are sorted const Surfel s = surfels[sId]; -#if 1 - const ivec2 sTileId = (s.fragCoord/int(tileSize)); - if(passId(sTileId) < pass) { - const bool kept = (atomicOr(usage[sId/32],0x0) & (1u << (sId%32)))!=0; - if(!kept) - continue; - } -#else const ivec2 sTileId = (s.fragCoord/int(tileSize)); if(sTileId.x!=tileId.x && tileId.x%2==0) continue; if(sTileId.y!=tileId.y && tileId.y%2==0) continue; -#endif const float w = calculteWeight(s.pos, decodeNormal(s.norm), s.radiusMean, s.radius, wpos, norm); weight += w; if(weight>edge) { - // too dense + // too dense - can be removed + surfels[surfelId].radius = 0; return; } } - - atomicOr(usage[surfelId/32], 1u << (surfelId%32)); } diff --git a/shader/lighting/surfels/surf_update.comp b/shader/lighting/surfels/surf_update.comp index 67540be99..bdfefd2e7 100644 --- a/shader/lighting/surfels/surf_update.comp +++ b/shader/lighting/surfels/surf_update.comp @@ -6,44 +6,12 @@ layout(local_size_x = 64) in; -layout(push_constant, std140) uniform Push { - float znear; - }; layout(binding = 0, std140) uniform UboScene { SceneDesc scene; }; -layout(binding = 1) uniform texture2D hiZ; -layout(binding = 2) uniform texture2D depth; -layout(binding = 3, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; }; - - -bool projectSphere(const vec3 c, float R, out vec4 aabb, out float depthMin, out float depthMax) { - // https://jcgt.org/published/0002/02/05/paper.pdf - depthMin = scene.project[3][2]/max(c.z - R, znear) + scene.project[2][2]; - depthMax = scene.project[3][2]/max(c.z + R, znear) + scene.project[2][2]; - - if (c.z + R < 0.0) { - return false; - } - - const float P00 = scene.project[0][0]; // fx - const float P11 = scene.project[1][1]; // fy - - vec3 cr = c * R; - float czr2 = c.z * c.z - R * R; +layout(binding = 1) uniform texture2D depth; +layout(binding = 2, std430) buffer SB0 { SurfHeader header; Surfel surfels[]; }; - float vx = sqrt(c.x * c.x + czr2); - float minx = (vx * c.x - cr.z) / (vx * c.z + cr.x); - float maxx = (vx * c.x + cr.z) / (vx * c.z - cr.x); - - float vy = sqrt(c.y * c.y + czr2); - float miny = (vy * c.y - cr.z) / (vy * c.z + cr.y); - float maxy = (vy * c.y + cr.z) / (vy * c.z - cr.y); - - aabb = vec4(minx * P00, miny * P11, maxx * P00, maxy * P11); - aabb = aabb*0.5 + vec4(0.5); - return true; - } float pixelToWorld(float pixelRadius, float z) { z = linearDepth(z, scene.clipInfo); @@ -56,16 +24,6 @@ float pixelToWorld(float pixelRadius, float z) { return min(worldRadiusX, worldRadiusY); } -int worldToPixel(const vec3 pos, float R) { - vec4 aabb = vec4(0); - float depthMin=0, depthMax=0; - if(!projectSphere(pos, R, aabb, depthMin, depthMax)) - return 0; - ivec4 area = ivec4(aabb.xy * scene.screenRes, aabb.zw * scene.screenRes); - vec2 sz = area.zw - area.xy; - return int( ceil(max(sz.x, sz.y)*0.5) ); - } - void main() { const uint surfelId = gl_GlobalInvocationID.x; if(surfelId >= header.count) From 3323e946220b83de0a4ff14fada3d38e9b142da0 Mon Sep 17 00:00:00 2001 From: Try Date: Tue, 30 Jun 2026 22:26:33 +0200 Subject: [PATCH 51/52] cleanup --- game/commandline.cpp | 2 +- game/graphics/shaders.cpp | 4 +-- shader/lighting/surfels/surf_alloc.comp | 45 +++++++++++------------- shader/lighting/surfels/surf_common.glsl | 14 ++------ 4 files changed, 26 insertions(+), 39 deletions(-) diff --git a/game/commandline.cpp b/game/commandline.cpp index 587a5b9bf..c59b2ed79 100644 --- a/game/commandline.cpp +++ b/game/commandline.cpp @@ -43,7 +43,7 @@ static bool boolArg(std::string_view v) { static int intArg(std::string_view v) { if(v=="false") return 0; - return (std::stol(std::string(v))); + return (std::stoi(std::string(v))); } CommandLine::CommandLine(int argc, const char** argv) { diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index f1714dbd0..8617079a2 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -401,10 +401,10 @@ bool Shaders::isGi1Supported() { bool Shaders::isGi2Supported() { auto& gpu = Resources::device().properties(); if(!gpu.raytracing.rayQuery) - return false; + return false; //TODO: splatting if(gpu.compute.maxInvocations<256 || !gpu.descriptors.nonUniformIndexing) return false; - if(!gpu.hasStorageFormat(R11G11B10UF) || !gpu.hasStorageFormat(R32F)) + if(!gpu.hasStorageFormat(RGBA16F)) return false; return true; } diff --git a/shader/lighting/surfels/surf_alloc.comp b/shader/lighting/surfels/surf_alloc.comp index 08aad1bb4..8a680cdbb 100644 --- a/shader/lighting/surfels/surf_alloc.comp +++ b/shader/lighting/surfels/surf_alloc.comp @@ -8,7 +8,6 @@ layout(local_size_x = 16, local_size_y = 16) in; const uint NumThreads = gl_WorkGroupSize.x*gl_WorkGroupSize.y*gl_WorkGroupSize.z; -const ivec2 TileSize = ivec2(128); const float NormalBias = 0.0030; const uint Salt = 0x9D; const float MaxAttempts = 1; @@ -16,6 +15,7 @@ const int MaxQueue = 256; layout(std140, push_constant) uniform Push { vec3 originLwc; + uint tileSize; }; layout(binding = 0, std140) uniform UboScene { SceneDesc scene; @@ -31,9 +31,8 @@ layout(binding = 8, std430) readonly buffer SB2 { uint surfelList[]; }; // layout(binding = 11, rgba8) uniform image2D dbgImage; -shared SurfelAlloc pointQueue[MaxQueue]; -shared float pointRMax [MaxQueue]; -shared int pointQueueSize; +shared Candidate pointQueue[MaxQueue]; +shared int pointQueueSize; shared uint fragVote; @@ -55,14 +54,15 @@ float pixelToWorld(float pixelRadius, float z) { return min(worldRadiusX, worldRadiusY); } -float calculteWeight(const SurfelAlloc s, float rMax, const vec3 wpos, const vec3 norm) { - return calculteWeight(s.pos.xyz, s.norm, s.pos.w, rMax, wpos, norm); +float calculteWeight(const Candidate s, const vec3 wpos, const vec3 norm) { + float rMean = s.pos.w * 2.0; + float rMax = s.pos.w; + return calculteWeight(s.pos.xyz, s.norm.xyz, rMean, rMax, wpos, norm); } float amendCoverage(const ivec2 fragCoord, const vec3 wpos, const vec3 norm) { const int i = pointQueueSize-1; - const SurfelAlloc s = pointQueue[i]; - return calculteWeight(s,pointRMax[i],wpos,norm); + return calculteWeight(pointQueue[i], wpos, norm); } float estimateCoverage(const ivec2 fragCoord, const vec3 wpos, const vec3 norm, const uint accounted) { @@ -72,8 +72,7 @@ float estimateCoverage(const ivec2 fragCoord, const vec3 wpos, const vec3 norm, for(int i=pointQueueSize; i>accounted;) { --i; - const SurfelAlloc s = pointQueue[i]; - wSum += calculteWeight(s,pointRMax[i],wpos,norm); + wSum += calculteWeight(pointQueue[i], wpos, norm); if(wSum > 1.0) return 1.0; } @@ -99,19 +98,18 @@ void storeSurfels() { if(laneID Date: Tue, 30 Jun 2026 22:56:13 +0200 Subject: [PATCH 52/52] cleanup --- game/graphics/renderer.cpp | 7 +++---- game/graphics/shaders.cpp | 2 -- game/graphics/shaders.h | 1 - shader/CMakeLists.txt | 2 -- shader/lighting/ambient_light.frag | 4 ++-- shader/lighting/surfels/surf_init.comp | 16 ---------------- 6 files changed, 5 insertions(+), 27 deletions(-) delete mode 100644 shader/lighting/surfels/surf_init.comp diff --git a/game/graphics/renderer.cpp b/game/graphics/renderer.cpp index a62f0707b..d9ac74264 100644 --- a/game/graphics/renderer.cpp +++ b/game/graphics/renderer.cpp @@ -1950,7 +1950,7 @@ void Renderer::prepareSurfels(Tempest::Encoder& cmd, Wor if(!enable) return; - if(settings.giMethod!=GiMethod::IrrC) + if(settings.giMethod!=GiMethod::IrrC || !settings.zCloudShadowScale) return; const uint32_t maxSurfels = surf.maxSurfels; @@ -2495,10 +2495,9 @@ void Renderer::drawAmbient(Encoder& cmd, const WorldView& view) { cmd.setBinding(0, view.sceneGlobals().uboGlobal[SceneGlobals::V_Main]); cmd.setBinding(1, gbufDiffuse, Sampler::nearest()); cmd.setBinding(2, gbufNormal, Sampler::nearest()); - if(settings.giMethod==GiMethod::IrrC) { - auto& ao = (settings.zCloudShadowScale ? textureCast(ssao.ssaoBlur) : Resources::fallbackBlack()); + if(settings.giMethod==GiMethod::IrrC && settings.zCloudShadowScale) { cmd.setBinding(3, surf.irrImage, Sampler::nearest(ClampMode::ClampToEdge)); - cmd.setBinding(4, ao, Sampler::nearest(ClampMode::ClampToEdge)); + cmd.setBinding(4, ssao.ssaoBlur, Sampler::nearest(ClampMode::ClampToEdge)); //TODO: remove once splatting is working cmd.setBinding(5, surf.surfels); cmd.setPipeline(shaders.ambientLightSurf); } diff --git a/game/graphics/shaders.cpp b/game/graphics/shaders.cpp index 8617079a2..38062e8ee 100644 --- a/game/graphics/shaders.cpp +++ b/game/graphics/shaders.cpp @@ -254,8 +254,6 @@ void Shaders::compileShaders() { surfBinAlloc = computeShader("surf_bin_alloc.comp.sprv"); surfBinSort = computeShader("surf_bin_sort.comp.sprv"); - surfInit = computeShader("surf_init.comp.sprv"); - surfUpdate = computeShader("surf_update.comp.sprv"); surfCulling = computeShader("surf_culling.comp.sprv"); surfDecimate = computeShader("surf_decimate.comp.sprv"); diff --git a/game/graphics/shaders.h b/game/graphics/shaders.h index dfee816f4..1d2f50e79 100644 --- a/game/graphics/shaders.h +++ b/game/graphics/shaders.h @@ -90,7 +90,6 @@ class Shaders { Tempest::RenderPipeline surfDbg; Tempest::ComputePipeline surfBinClear, surfBinPass, surfBinAlloc, surfBinSort; - Tempest::ComputePipeline surfInit; Tempest::ComputePipeline surfAlloc, surfApply; Tempest::ComputePipeline surfUpdate, surfCulling, surfDecimate, surfCompact; diff --git a/shader/CMakeLists.txt b/shader/CMakeLists.txt index 6d634ecd1..ec2f3736a 100644 --- a/shader/CMakeLists.txt +++ b/shader/CMakeLists.txt @@ -312,8 +312,6 @@ add_shader(probe_ambient.frag lighting/rt/probe_ambient.frag) add_shader(surf_dbg.vert lighting/surfels/surf_dbg.vert) add_shader(surf_dbg.frag lighting/surfels/surf_dbg.frag) -add_shader(surf_init.comp lighting/surfels/surf_init.comp) - add_shader(surf_update.comp lighting/surfels/surf_update.comp) add_shader(surf_culling.comp lighting/surfels/surf_culling.comp) add_shader(surf_decimate.comp lighting/surfels/surf_decimate.comp) diff --git a/shader/lighting/ambient_light.frag b/shader/lighting/ambient_light.frag index ee8fce61e..1ad95cbf9 100644 --- a/shader/lighting/ambient_light.frag +++ b/shader/lighting/ambient_light.frag @@ -85,8 +85,8 @@ void main() { vec3 color = linear; color *= luminance(norm); #if defined(SURFEL_GI) - // preexposed already - //color *= ao; + //NOTE: pre-exposed already + color *= ao; #else color *= ao; color *= scene.exposure; diff --git a/shader/lighting/surfels/surf_init.comp b/shader/lighting/surfels/surf_init.comp deleted file mode 100644 index 2a32a1836..000000000 --- a/shader/lighting/surfels/surf_init.comp +++ /dev/null @@ -1,16 +0,0 @@ -#version 450 - -#include "lighting/surfels/surf_common.glsl" - -layout(local_size_x = 1) in; - -layout(binding = 4, std430) buffer SB0 { SurfHeader header; } surf; -layout(binding = 5, std430) buffer SB2 { uvec4 count; } alloc; - -void main() { - surf.header.count = 0; - surf.header.one1 = 1; - surf.header.one2 = 1; - - alloc.count = uvec4(0,1,1,0); - }