From 8ed96484c2e598465e9e71e51fc469c52d301d9c Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Wed, 31 Aug 2022 06:22:02 +0200 Subject: [PATCH] Remove the old GPU raytracer --- CMakeLists.txt | 13 - src/lightmap/glsl_rchit_ambient.h | 43 - src/lightmap/glsl_rchit_bounce.h | 37 - src/lightmap/glsl_rchit_light.h | 36 - src/lightmap/glsl_rchit_sun.h | 35 - src/lightmap/glsl_rgen_ambient.h | 112 --- src/lightmap/glsl_rgen_bounce.h | 155 --- src/lightmap/glsl_rgen_light.h | 203 ---- src/lightmap/glsl_rmiss_ambient.h | 20 - src/lightmap/glsl_rmiss_bounce.h | 20 - src/lightmap/glsl_rmiss_light.h | 20 - src/lightmap/glsl_rmiss_sun.h | 20 - src/lightmap/gpuraytracer.cpp | 1548 ++++++++++++++--------------- src/lightmap/gpuraytracer.h | 128 ++- src/lightmap/gpuraytracer2.cpp | 923 ----------------- src/lightmap/gpuraytracer2.h | 187 ---- 16 files changed, 817 insertions(+), 2683 deletions(-) delete mode 100644 src/lightmap/glsl_rchit_ambient.h delete mode 100644 src/lightmap/glsl_rchit_bounce.h delete mode 100644 src/lightmap/glsl_rchit_light.h delete mode 100644 src/lightmap/glsl_rchit_sun.h delete mode 100644 src/lightmap/glsl_rgen_ambient.h delete mode 100644 src/lightmap/glsl_rgen_bounce.h delete mode 100644 src/lightmap/glsl_rgen_light.h delete mode 100644 src/lightmap/glsl_rmiss_ambient.h delete mode 100644 src/lightmap/glsl_rmiss_bounce.h delete mode 100644 src/lightmap/glsl_rmiss_light.h delete mode 100644 src/lightmap/glsl_rmiss_sun.h delete mode 100644 src/lightmap/gpuraytracer2.cpp delete mode 100644 src/lightmap/gpuraytracer2.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f38bb2..a35d0ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -186,19 +186,6 @@ set( SOURCES src/lightmap/surfaceclip.h src/lightmap/gpuraytracer.cpp src/lightmap/gpuraytracer.h - src/lightmap/gpuraytracer2.cpp - src/lightmap/gpuraytracer2.h - src/lightmap/glsl_rchit_bounce.h - src/lightmap/glsl_rchit_light.h - src/lightmap/glsl_rchit_sun.h - src/lightmap/glsl_rchit_ambient.h - src/lightmap/glsl_rgen_bounce.h - src/lightmap/glsl_rgen_light.h - src/lightmap/glsl_rgen_ambient.h - src/lightmap/glsl_rmiss_bounce.h - src/lightmap/glsl_rmiss_light.h - src/lightmap/glsl_rmiss_sun.h - src/lightmap/glsl_rmiss_ambient.h src/lightmap/glsl_frag.h src/lightmap/glsl_vert.h src/lightmap/glsl_frag_resolve.h diff --git a/src/lightmap/glsl_rchit_ambient.h b/src/lightmap/glsl_rchit_ambient.h deleted file mode 100644 index e9c6585..0000000 --- a/src/lightmap/glsl_rchit_ambient.h +++ /dev/null @@ -1,43 +0,0 @@ -static const char* glsl_rchit_ambient = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -struct hitPayload -{ - vec3 hitPosition; - float hitAttenuation; - int hitSurfaceIndex; -}; - -struct SurfaceInfo -{ - vec3 Normal; - float EmissiveDistance; - vec3 EmissiveColor; - float EmissiveIntensity; - float Sky; - float SamplingDistance; - float Padding1, Padding2; -}; - -layout(location = 0) rayPayloadInEXT hitPayload payload; - -layout(set = 0, binding = 5) buffer SurfaceIndexBuffer { int surfaceIndices[]; }; -layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; - -void main() -{ - SurfaceInfo surface = surfaces[surfaceIndices[gl_PrimitiveID]]; - - if(surface.Sky > 0.0) - { - payload.hitAttenuation = 100000.0; - } - else - { - payload.hitAttenuation = gl_HitTEXT; - } -} - -)glsl"; diff --git a/src/lightmap/glsl_rchit_bounce.h b/src/lightmap/glsl_rchit_bounce.h deleted file mode 100644 index 54938bb..0000000 --- a/src/lightmap/glsl_rchit_bounce.h +++ /dev/null @@ -1,37 +0,0 @@ -static const char* glsl_rchit_bounce = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -struct hitPayload -{ - vec3 hitPosition; - float hitAttenuation; - int hitSurfaceIndex; -}; - -struct SurfaceInfo -{ - vec3 Normal; - float EmissiveDistance; - vec3 EmissiveColor; - float EmissiveIntensity; - float Sky; - float SamplingDistance; - float Padding1, Padding2; -}; - -layout(location = 0) rayPayloadInEXT hitPayload payload; - -layout(set = 0, binding = 5) buffer SurfaceIndexBuffer { int surfaceIndices[]; }; -layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; - -void main() -{ - int surfaceIndex = surfaceIndices[gl_PrimitiveID]; - payload.hitPosition = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; - payload.hitSurfaceIndex = surfaceIndex; - payload.hitAttenuation = 1.0; -} - -)glsl"; diff --git a/src/lightmap/glsl_rchit_light.h b/src/lightmap/glsl_rchit_light.h deleted file mode 100644 index 488958f..0000000 --- a/src/lightmap/glsl_rchit_light.h +++ /dev/null @@ -1,36 +0,0 @@ -static const char* glsl_rchit_light = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -struct hitPayload -{ - vec3 hitPosition; - float hitAttenuation; - int hitSurfaceIndex; -}; - -struct SurfaceInfo -{ - vec3 Normal; - float EmissiveDistance; - vec3 EmissiveColor; - float EmissiveIntensity; - float Sky; - float SamplingDistance; - float Padding1, Padding2; -}; - -layout(location = 0) rayPayloadInEXT hitPayload payload; - -layout(set = 0, binding = 5) buffer SurfaceIndexBuffer { uint surfaceIndices[]; }; -layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; - -void main() -{ - //SurfaceInfo surface = surfaces[surfaceIndices[gl_PrimitiveID]]; - - payload.hitAttenuation = 0.0; -} - -)glsl"; diff --git a/src/lightmap/glsl_rchit_sun.h b/src/lightmap/glsl_rchit_sun.h deleted file mode 100644 index 82ceef7..0000000 --- a/src/lightmap/glsl_rchit_sun.h +++ /dev/null @@ -1,35 +0,0 @@ -static const char* glsl_rchit_sun = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -struct hitPayload -{ - vec3 hitPosition; - float hitAttenuation; - int hitSurfaceIndex; -}; - -struct SurfaceInfo -{ - vec3 Normal; - float EmissiveDistance; - vec3 EmissiveColor; - float EmissiveIntensity; - float Sky; - float SamplingDistance; - float Padding1, Padding2; -}; - -layout(location = 0) rayPayloadInEXT hitPayload payload; - -layout(set = 0, binding = 5) buffer SurfaceIndexBuffer { int surfaceIndices[]; }; -layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; - -void main() -{ - SurfaceInfo surface = surfaces[surfaceIndices[gl_PrimitiveID]]; - payload.hitAttenuation = surface.Sky; -} - -)glsl"; diff --git a/src/lightmap/glsl_rgen_ambient.h b/src/lightmap/glsl_rgen_ambient.h deleted file mode 100644 index 04002d6..0000000 --- a/src/lightmap/glsl_rgen_ambient.h +++ /dev/null @@ -1,112 +0,0 @@ -static const char* glsl_rgen_ambient = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -struct hitPayload -{ - vec3 hitPosition; - float hitAttenuation; - int hitSurfaceIndex; -}; - -layout(location = 0) rayPayloadEXT hitPayload payload; - -layout(set = 0, binding = 0) uniform accelerationStructureEXT acc; -layout(set = 0, binding = 1, rgba32f) uniform image2D startpositions; -layout(set = 0, binding = 2, rgba32f) uniform image2D positions; -layout(set = 0, binding = 3, rgba32f) uniform image2D outputs; - -layout(set = 0, binding = 4) uniform Uniforms -{ - uint SampleIndex; - uint SampleCount; - uint PassType; - uint Padding0; - vec3 SunDir; - float Padding1; - vec3 SunColor; - float SunIntensity; - vec3 HemisphereVec; - float Padding2; -}; - -struct SurfaceInfo -{ - vec3 Normal; - float EmissiveDistance; - vec3 EmissiveColor; - float EmissiveIntensity; - float Sky; - float SamplingDistance; - float Padding1, Padding2; -}; - -layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; - -layout(push_constant) uniform PushConstants -{ - uint LightStart; - uint LightEnd; - ivec2 pushPadding; -}; - -vec2 Hammersley(uint i, uint N); -float RadicalInverse_VdC(uint bits); - -void main() -{ - ivec2 texelPos = ivec2(gl_LaunchIDEXT.xy); - - vec4 data0 = imageLoad(startpositions, texelPos); - vec4 incoming = imageLoad(outputs, texelPos); - - if (PassType == 1) - incoming.rgb = vec3(1.0); // For debugging - - vec3 origin = data0.xyz; - int surfaceIndex = int(data0.w); - - if (surfaceIndex >= 0) - { - const float minDistance = 0.05; - const float aoDistance = 100; - - vec3 N = surfaces[surfaceIndex].Normal; - vec3 up = abs(N.x) < abs(N.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0); - vec3 tangent = normalize(cross(up, N)); - vec3 bitangent = cross(N, tangent); - - float ambience = 0.0f; - for (uint i = 0; i < SampleCount; i++) - { - vec2 Xi = Hammersley(i, SampleCount); - vec3 H = normalize(vec3(Xi.x * 2.0f - 1.0f, Xi.y * 2.0f - 1.0f, 1.5 - length(Xi))); - vec3 L = H.x * tangent + H.y * bitangent + H.z * N; - traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 3, 0, 3, origin, minDistance, L, 32768, 0); - ambience += clamp(payload.hitAttenuation / aoDistance, 0.0, 1.0); - } - ambience /= float(SampleCount); - - incoming.rgb = incoming.rgb * ambience; - } - - imageStore(outputs, texelPos, incoming); -} - -vec2 Hammersley(uint i, uint N) -{ - return vec2(float(i) / float(N), RadicalInverse_VdC(i)); -} - -float RadicalInverse_VdC(uint bits) -{ - bits = (bits << 16u) | (bits >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - return float(bits) * 2.3283064365386963e-10f; // / 0x100000000 -} - -)glsl"; diff --git a/src/lightmap/glsl_rgen_bounce.h b/src/lightmap/glsl_rgen_bounce.h deleted file mode 100644 index 25de9da..0000000 --- a/src/lightmap/glsl_rgen_bounce.h +++ /dev/null @@ -1,155 +0,0 @@ -static const char* glsl_rgen_bounce = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -struct hitPayload -{ - vec3 hitPosition; - float hitAttenuation; - int hitSurfaceIndex; -}; - -layout(location = 0) rayPayloadEXT hitPayload payload; - -layout(set = 0, binding = 0) uniform accelerationStructureEXT acc; -layout(set = 0, binding = 1, rgba32f) uniform image2D startpositions; -layout(set = 0, binding = 2, rgba32f) uniform image2D positions; -layout(set = 0, binding = 3, rgba32f) uniform image2D outputs; - -layout(set = 0, binding = 4) uniform Uniforms -{ - uint SampleIndex; - uint SampleCount; - uint PassType; - uint Padding0; - vec3 SunDir; - float Padding1; - vec3 SunColor; - float SunIntensity; - vec3 HemisphereVec; - float Padding2; -}; - -struct SurfaceInfo -{ - vec3 Normal; - float EmissiveDistance; - vec3 EmissiveColor; - float EmissiveIntensity; - float Sky; - float SamplingDistance; - float Padding1, Padding2; -}; - -layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; - -layout(push_constant) uniform PushConstants -{ - uint LightStart; - uint LightEnd; - ivec2 pushPadding; -}; - -vec3 ImportanceSample(vec3 N); - -void main() -{ - ivec2 texelPos = ivec2(gl_LaunchIDEXT.xy); - - vec4 data0; - if (PassType == 2) - data0 = imageLoad(positions, texelPos); - else - data0 = imageLoad(startpositions, texelPos); - - vec4 incoming = vec4(0.0, 0.0, 0.0, 1.0); - if (PassType != 0) - incoming = imageLoad(outputs, texelPos); - - vec3 origin = data0.xyz; - int surfaceIndex = int(data0.w); - if (surfaceIndex != -1) - { - if (PassType == 0) - { - if (surfaceIndex >= 0) - { - SurfaceInfo surface = surfaces[surfaceIndex]; - incoming.rgb = surface.EmissiveColor * surface.EmissiveIntensity; - } - } - else - { - if (PassType == 1) - incoming.w = 1.0f / float(SampleCount); - - vec3 normal; - if (surfaceIndex >= 0) - { - normal = surfaces[surfaceIndex].Normal; - } - else - { - switch (SampleIndex % 6) - { - case 0: normal = vec3( 1.0f, 0.0f, 0.0f); break; - case 1: normal = vec3(-1.0f, 0.0f, 0.0f); break; - case 2: normal = vec3( 0.0f, 1.0f, 0.0f); break; - case 3: normal = vec3( 0.0f, -1.0f, 0.0f); break; - case 4: normal = vec3( 0.0f, 0.0f, 1.0f); break; - case 5: normal = vec3( 0.0f, 0.0f, -1.0f); break; - } - } - - vec3 H = ImportanceSample(normal); - vec3 L = normalize(H * (2.0f * dot(normal, H)) - normal); - - float NdotL = max(dot(normal, L), 0.0); - - const float p = 1 / (2 * 3.14159265359); - incoming.w *= NdotL / p; - - surfaceIndex = -1; - if (NdotL > 0.0f) - { - const float minDistance = 0.1; - - traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 0, 0, 0, origin + normal * 0.1, minDistance, L, 32768, 0); - if (payload.hitAttenuation == 1.0) - { - surfaceIndex = payload.hitSurfaceIndex; - SurfaceInfo surface = surfaces[surfaceIndex]; - if (surface.EmissiveDistance > 0.0) - { - float hitDistance = distance(origin, payload.hitPosition); - float attenuation = max(1.0 - (hitDistance / surface.EmissiveDistance), 0.0f); - incoming.rgb += surface.EmissiveColor * (surface.EmissiveIntensity * attenuation * incoming.w); - } - origin = payload.hitPosition; - } - } - - incoming.w *= 0.25; // the amount of incoming light the surfaces emit - } - } - - data0.xyz = origin; - data0.w = float(surfaceIndex); - - imageStore(positions, texelPos, data0); - imageStore(outputs, texelPos, incoming); -} - -vec3 ImportanceSample(vec3 N) -{ - // from tangent-space vector to world-space sample vector - vec3 up = abs(N.x) < abs(N.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0); - vec3 tangent = normalize(cross(up, N)); - vec3 bitangent = cross(N, tangent); - - vec3 sampleVec = tangent * HemisphereVec.x + bitangent * HemisphereVec.y + N * HemisphereVec.z; - return normalize(sampleVec); -} - -)glsl"; diff --git a/src/lightmap/glsl_rgen_light.h b/src/lightmap/glsl_rgen_light.h deleted file mode 100644 index 9c511e5..0000000 --- a/src/lightmap/glsl_rgen_light.h +++ /dev/null @@ -1,203 +0,0 @@ -static const char* glsl_rgen_light = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -struct hitPayload -{ - vec3 hitPosition; - float hitAttenuation; - int hitSurfaceIndex; -}; - -layout(location = 0) rayPayloadEXT hitPayload payload; - -layout(set = 0, binding = 0) uniform accelerationStructureEXT acc; -layout(set = 0, binding = 1, rgba32f) uniform image2D startpositions; -layout(set = 0, binding = 2, rgba32f) uniform image2D positions; -layout(set = 0, binding = 3, rgba32f) uniform image2D outputs; - -layout(set = 0, binding = 4) uniform Uniforms -{ - uint SampleIndex; - uint SampleCount; - uint PassType; - uint Padding0; - vec3 SunDir; - float Padding1; - vec3 SunColor; - float SunIntensity; - vec3 HemisphereVec; - float Padding2; -}; - -struct SurfaceInfo -{ - vec3 Normal; - float EmissiveDistance; - vec3 EmissiveColor; - float EmissiveIntensity; - float Sky; - float SamplingDistance; - float Padding1, Padding2; -}; - -struct LightInfo -{ - vec3 Origin; - float Padding0; - float Radius; - float Intensity; - float InnerAngleCos; - float OuterAngleCos; - vec3 SpotDir; - float Padding1; - vec3 Color; - float Padding2; -}; - -layout(set = 0, binding = 6) buffer SurfaceBuffer { SurfaceInfo surfaces[]; }; -layout(set = 0, binding = 7) buffer LightBuffer { LightInfo lights[]; }; - -layout(push_constant) uniform PushConstants -{ - uint LightStart; - uint LightEnd; - ivec2 pushPadding; -}; - -vec2 Hammersley(uint i, uint N); -float RadicalInverse_VdC(uint bits); - -void main() -{ - ivec2 texelPos = ivec2(gl_LaunchIDEXT.xy); - vec4 incoming = imageLoad(outputs, texelPos); - vec4 data0 = imageLoad(positions, texelPos); - int surfaceIndex = int(data0.w); - if (surfaceIndex == -1 || incoming.w <= 0.0) - return; - - vec3 origin = data0.xyz; - vec3 normal; - if (surfaceIndex >= 0) - { - normal = surfaces[surfaceIndex].Normal; - origin += normal * 0.1; - } - - const float minDistance = 0.01; - - if (LightStart == 0) // Sun light - { - const float dist = 32768.0; - - float attenuation = 0.0; - if (PassType == 0 && surfaceIndex >= 0) - { - if(dot(normal, SunDir) > 0.0) - { - vec3 e0 = normalize(cross(normal, abs(normal.x) < abs(normal.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0))); - vec3 e1 = cross(normal, e0); - e0 = cross(normal, e1); - - for (uint i = 0; i < SampleCount; i++) - { - vec2 offset = (Hammersley(i, SampleCount) - 0.5) * surfaces[surfaceIndex].SamplingDistance; - vec3 origin2 = origin + offset.x * e0 + offset.y * e1; - - traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 2, 0, 2, origin2, minDistance, SunDir, dist, 0); - attenuation += payload.hitAttenuation; - } - attenuation *= 1.0 / float(SampleCount); - incoming.rgb += SunColor * (attenuation * SunIntensity * incoming.w); - } - } - else - { - traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 2, 0, 2, origin, minDistance, SunDir, dist, 0); - attenuation = payload.hitAttenuation; - incoming.rgb += SunColor * (attenuation * SunIntensity * incoming.w); - } - } - - for (uint j = LightStart; j < LightEnd; j++) - { - LightInfo light = lights[j]; - - float dist = distance(light.Origin, origin); - if (dist > minDistance && dist < light.Radius) - { - vec3 dir = normalize(light.Origin - origin); - if(surfaceIndex < 0 || dot(normal, dir) > 0.0) - { - float distAttenuation = max(1.0 - (dist / light.Radius), 0.0); - float angleAttenuation = 1.0f; - if (surfaceIndex >= 0) - { - angleAttenuation = max(dot(normal, dir), 0.0); - } - float spotAttenuation = 1.0; - if (light.OuterAngleCos > -1.0) - { - float cosDir = dot(dir, light.SpotDir); - spotAttenuation = smoothstep(light.OuterAngleCos, light.InnerAngleCos, cosDir); - spotAttenuation = max(spotAttenuation, 0.0); - } - - float attenuation = distAttenuation * angleAttenuation * spotAttenuation; - if (attenuation > 0.0) - { - float shadowAttenuation = 0.0; - - if (PassType == 0 && surfaceIndex >= 0) - { - vec3 e0 = normalize(cross(normal, abs(normal.x) < abs(normal.y) ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0))); - vec3 e1 = cross(normal, e0); - e0 = cross(normal, e1); - for (uint i = 0; i < SampleCount; i++) - { - vec2 offset = (Hammersley(i, SampleCount) - 0.5) * surfaces[surfaceIndex].SamplingDistance; - vec3 origin2 = origin + offset.x * e0 + offset.y * e1; - - float dist2 = distance(light.Origin, origin2); - vec3 dir2 = normalize(light.Origin - origin2); - - traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 1, 0, 1, origin2, minDistance, dir2, dist2, 0); - shadowAttenuation += payload.hitAttenuation; - } - shadowAttenuation *= 1.0 / float(SampleCount); - } - else - { - traceRayEXT(acc, gl_RayFlagsOpaqueEXT, 0xff, 1, 0, 1, origin, minDistance, dir, dist, 0); - shadowAttenuation = payload.hitAttenuation; - } - - attenuation *= shadowAttenuation; - - incoming.rgb += light.Color * (attenuation * light.Intensity) * incoming.w; - } - } - } - } - - imageStore(outputs, texelPos, incoming); -} - -float RadicalInverse_VdC(uint bits) -{ - bits = (bits << 16u) | (bits >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - return float(bits) * 2.3283064365386963e-10f; // / 0x100000000 -} - -vec2 Hammersley(uint i, uint N) -{ - return vec2(float(i) / float(N), RadicalInverse_VdC(i)); -} - -)glsl"; diff --git a/src/lightmap/glsl_rmiss_ambient.h b/src/lightmap/glsl_rmiss_ambient.h deleted file mode 100644 index d50ab09..0000000 --- a/src/lightmap/glsl_rmiss_ambient.h +++ /dev/null @@ -1,20 +0,0 @@ -static const char* glsl_rmiss_ambient = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -struct hitPayload -{ - vec3 hitPosition; - float hitAttenuation; - int hitSurfaceIndex; -}; - -layout(location = 0) rayPayloadInEXT hitPayload payload; - -void main() -{ - payload.hitAttenuation = 100000.0; -} - -)glsl"; diff --git a/src/lightmap/glsl_rmiss_bounce.h b/src/lightmap/glsl_rmiss_bounce.h deleted file mode 100644 index 3ed3b45..0000000 --- a/src/lightmap/glsl_rmiss_bounce.h +++ /dev/null @@ -1,20 +0,0 @@ -static const char* glsl_rmiss_bounce = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -struct hitPayload -{ - vec3 hitPosition; - float hitAttenuation; - int hitSurfaceIndex; -}; - -layout(location = 0) rayPayloadInEXT hitPayload payload; - -void main() -{ - payload.hitAttenuation = 0.0; -} - -)glsl"; diff --git a/src/lightmap/glsl_rmiss_light.h b/src/lightmap/glsl_rmiss_light.h deleted file mode 100644 index 412abad..0000000 --- a/src/lightmap/glsl_rmiss_light.h +++ /dev/null @@ -1,20 +0,0 @@ -static const char* glsl_rmiss_light = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -struct hitPayload -{ - vec3 hitPosition; - float hitAttenuation; - int hitSurfaceIndex; -}; - -layout(location = 0) rayPayloadInEXT hitPayload payload; - -void main() -{ - payload.hitAttenuation = 1.0; -} - -)glsl"; diff --git a/src/lightmap/glsl_rmiss_sun.h b/src/lightmap/glsl_rmiss_sun.h deleted file mode 100644 index 29df593..0000000 --- a/src/lightmap/glsl_rmiss_sun.h +++ /dev/null @@ -1,20 +0,0 @@ -static const char* glsl_rmiss_sun = R"glsl( - -#version 460 -#extension GL_EXT_ray_tracing : require - -struct hitPayload -{ - vec3 hitPosition; - float hitAttenuation; - int hitSurfaceIndex; -}; - -layout(location = 0) rayPayloadInEXT hitPayload payload; - -void main() -{ - payload.hitAttenuation = 0.0; -} - -)glsl"; diff --git a/src/lightmap/gpuraytracer.cpp b/src/lightmap/gpuraytracer.cpp index 62b8326..1381f3e 100644 --- a/src/lightmap/gpuraytracer.cpp +++ b/src/lightmap/gpuraytracer.cpp @@ -7,7 +7,6 @@ #include "framework/templates.h" #include "framework/halffloat.h" #include "vulkanbuilders.h" -#include "surfaceclip.h" #include #include #include @@ -15,24 +14,12 @@ #include #include #include -#include "glsl_rgen_bounce.h" -#include "glsl_rgen_light.h" -#include "glsl_rgen_ambient.h" -#include "glsl_rchit_bounce.h" -#include "glsl_rchit_light.h" -#include "glsl_rchit_sun.h" -#include "glsl_rchit_ambient.h" -#include "glsl_rmiss_bounce.h" -#include "glsl_rmiss_light.h" -#include "glsl_rmiss_sun.h" -#include "glsl_rmiss_ambient.h" +#include "glsl_frag.h" +#include "glsl_frag_resolve.h" +#include "glsl_vert.h" extern bool VKDebug; -extern int coverageSampleCount; -extern int bounceSampleCount; -extern int ambientSampleCount; - GPURaytracer::GPURaytracer() { device = std::make_unique(0, VKDebug); @@ -54,77 +41,41 @@ void GPURaytracer::Raytrace(LevelMesh* level) CreateVulkanObjects(); - std::vector tasks; - CreateTasks(tasks); - - std::vector HemisphereVectors; - HemisphereVectors.reserve(bounceSampleCount); - for (int i = 0; i < bounceSampleCount; i++) - { - vec2 Xi = Hammersley(i, bounceSampleCount); - vec3 H; - H.x = Xi.x * 2.0f - 1.0f; - H.y = Xi.y * 2.0f - 1.0f; - H.z = 1.5f - length(Xi); - H = normalize(H); - HemisphereVectors.push_back(H); - } - - //printf("Ray tracing with %d bounce(s)\n", mesh->map->LightBounce); printf("Ray tracing in progress...\n"); - size_t maxTasks = (size_t)rayTraceImageSize * rayTraceImageSize; - for (size_t startTask = 0; startTask < tasks.size(); startTask += maxTasks) + CreateAtlasImages(); + + BeginCommands(); + UploadUniforms(); + + for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++) { - printf("\r%.1f%%\t%llu/%llu", double(startTask) / double(tasks.size()) * 100, startTask, tasks.size()); - size_t numTasks = std::min(tasks.size() - startTask, maxTasks); - UploadTasks(tasks.data() + startTask, numTasks); - - BeginTracing(); - - Uniforms uniforms = {}; - uniforms.SunDir = mesh->map->GetSunDirection(); - uniforms.SunColor = mesh->map->GetSunColor(); - uniforms.SunIntensity = 1.0f; - - uniforms.PassType = 0; - uniforms.SampleIndex = 0; - uniforms.SampleCount = bounceSampleCount; - RunTrace(uniforms, rgenBounceRegion); - - uniforms.SampleCount = coverageSampleCount; - RunTrace(uniforms, rgenLightRegion, 0, mesh->map->ThingLights.Size()); - - for (uint32_t i = 0; i < (uint32_t)bounceSampleCount; i++) - { - uniforms.PassType = 1; - uniforms.SampleIndex = i; - uniforms.SampleCount = bounceSampleCount; - uniforms.HemisphereVec = HemisphereVectors[uniforms.SampleIndex]; - RunTrace(uniforms, rgenBounceRegion); - - for (int bounce = 0; bounce < mesh->map->LightBounce; bounce++) - { - uniforms.SampleCount = coverageSampleCount; - RunTrace(uniforms, rgenLightRegion, 0, mesh->map->ThingLights.Size()); - - uniforms.PassType = 2; - uniforms.SampleIndex = (i + bounce) % uniforms.SampleCount; - uniforms.SampleCount = bounceSampleCount; - uniforms.HemisphereVec = HemisphereVectors[uniforms.SampleIndex]; - RunTrace(uniforms, rgenBounceRegion); - } - } - - uniforms.PassType = 0; - uniforms.SampleIndex = 0; - uniforms.SampleCount = ambientSampleCount; - RunTrace(uniforms, rgenAmbientRegion); - - EndTracing(); - DownloadTasks(tasks.data() + startTask, numTasks); + RenderAtlasImage(pageIndex); + } + + for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++) + { + ResolveAtlasImage(pageIndex); + } + +#ifdef WIN32 + LARGE_INTEGER s; + QueryPerformanceCounter(&s); +#endif + + FinishCommands(); + +#ifdef WIN32 + LARGE_INTEGER e, f; + QueryPerformanceCounter(&e); + QueryPerformanceFrequency(&f); + printf("GPU ray tracing time was %.3f seconds.\n", double(e.QuadPart - s.QuadPart) / double(f.QuadPart)); +#endif + + for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++) + { + DownloadAtlasImage(pageIndex); } - printf("\r%.1f%%\t%llu/%llu\n", 100.0, tasks.size(), tasks.size()); if (device->renderdoc) device->renderdoc->EndFrameCapture(0, 0); @@ -132,206 +83,316 @@ void GPURaytracer::Raytrace(LevelMesh* level) printf("Ray trace complete\n"); } -void GPURaytracer::CreateTasks(std::vector& tasks) +void GPURaytracer::RenderAtlasImage(size_t pageIndex) { - tasks.reserve(mesh->lightProbes.size()); + LightmapImage& img = atlasImages[pageIndex]; - for (size_t i = 0; i < mesh->lightProbes.size(); i++) - { - TraceTask task; - task.id = -(int)(i + 2); - task.x = 0; - task.y = 0; - tasks.push_back(task); - } + RenderPassBegin() + .RenderPass(raytrace.renderPass.get()) + .RenderArea(0, 0, atlasImageSize, atlasImageSize) + .Framebuffer(img.raytrace.Framebuffer.get()) + .Execute(cmdbuffer.get()); - size_t fullTaskCount = mesh->lightProbes.size(); + VkDeviceSize offset = 0; + cmdbuffer->bindVertexBuffers(0, 1, &sceneVertexBuffer->buffer, &offset); + cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipeline.get()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 0, raytrace.descriptorSet.get()); for (size_t i = 0; i < mesh->surfaces.size(); i++) { - if (i % 4096 == 0) - printf("\rGathering surface trace tasks: %llu / %llu", i, mesh->surfaces.size()); + Surface* targetSurface = mesh->surfaces[i].get(); + if (targetSurface->atlasPageIndex != pageIndex) + continue; + VkViewport viewport = {}; + viewport.maxDepth = 1; + viewport.x = (float)targetSurface->atlasX - 1; + viewport.y = (float)targetSurface->atlasY - 1; + viewport.width = (float)(targetSurface->texWidth + 2); + viewport.height = (float)(targetSurface->texHeight + 2); + cmdbuffer->setViewport(0, 1, &viewport); + + // Paint all surfaces part of the smoothing group into the surface + for (const auto& surface : mesh->surfaces) + { + if (surface->smoothingGroupIndex != targetSurface->smoothingGroupIndex) + continue; + + vec2 minUV = ToUV(surface->bounds.min, targetSurface); + vec2 maxUV = ToUV(surface->bounds.max, targetSurface); + if (surface.get() != targetSurface && (maxUV.x < 0.0f || maxUV.y < 0.0f || minUV.x > 1.0f || minUV.y > 1.0f)) + continue; // Bounding box not visible + + int firstLight = sceneLightPos; + int lightCount = (int)surface->LightList.size(); + if (sceneLightPos + lightCount > SceneLightBufferSize) + throw std::runtime_error("SceneLightBuffer is too small!"); + sceneLightPos += lightCount; + + LightInfo* lightinfo = &sceneLights[firstLight]; + for (ThingLight* light : surface->LightList) + { + lightinfo->Origin = light->LightOrigin(); + lightinfo->Radius = light->LightRadius(); + lightinfo->Intensity = light->intensity; + lightinfo->InnerAngleCos = light->innerAngleCos; + lightinfo->OuterAngleCos = light->outerAngleCos; + lightinfo->SpotDir = light->SpotDir(); + lightinfo->Color = light->rgb; + lightinfo++; + } + + PushConstants pc; + pc.LightStart = firstLight; + pc.LightEnd = firstLight + lightCount; + pc.SurfaceIndex = (int32_t)i; + pc.LightmapOrigin = targetSurface->worldOrigin - targetSurface->worldStepX - targetSurface->worldStepY; + pc.LightmapStepX = targetSurface->worldStepX * viewport.width; + pc.LightmapStepY = targetSurface->worldStepY * viewport.height; + cmdbuffer->pushConstants(raytrace.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants), &pc); + + int firstVertex = sceneVertexPos; + int vertexCount = (int)surface->verts.size(); + if (sceneVertexPos + vertexCount > SceneVertexBufferSize) + throw std::runtime_error("SceneVertexBuffer is too small!"); + sceneVertexPos += vertexCount; + SceneVertex* vertex = &sceneVertices[firstVertex]; + + if (surface->type == ST_FLOOR || surface->type == ST_CEILING) + { + for (int idx = 0; idx < vertexCount; idx++) + { + (vertex++)->Position = ToUV(surface->verts[idx], targetSurface); + } + } + else + { + (vertex++)->Position = ToUV(surface->verts[0], targetSurface); + (vertex++)->Position = ToUV(surface->verts[2], targetSurface); + (vertex++)->Position = ToUV(surface->verts[3], targetSurface); + (vertex++)->Position = ToUV(surface->verts[1], targetSurface); + } + + cmdbuffer->draw(vertexCount, 1, firstVertex, 0); + } + } + + cmdbuffer->endRenderPass(); +} + +void GPURaytracer::CreateAtlasImages() +{ + const int spacing = 3; // Note: the spacing is here to avoid that the resolve sampler finds data from other surface tiles + RectPacker packer(atlasImageSize, atlasImageSize, RectPacker::Spacing(spacing)); + + for (size_t i = 0; i < mesh->surfaces.size(); i++) + { Surface* surface = mesh->surfaces[i].get(); - if (!surface->bSky) + auto result = packer.insert(surface->texWidth + 2, surface->texHeight + 2); + surface->atlasX = result.pos.x + 1; + surface->atlasY = result.pos.y + 1; + surface->atlasPageIndex = (int)result.pageIndex; + } + + for (size_t pageIndex = 0; pageIndex < packer.getNumPages(); pageIndex++) + { + atlasImages.push_back(CreateImage(atlasImageSize, atlasImageSize)); + } +} + +void GPURaytracer::UploadUniforms() +{ + Uniforms uniforms = {}; + uniforms.SunDir = mesh->map->GetSunDirection(); + uniforms.SunColor = mesh->map->GetSunColor(); + uniforms.SunIntensity = 1.0f; + + mappedUniforms = (uint8_t*)uniformTransferBuffer->Map(0, uniformStructs * uniformStructStride); + *reinterpret_cast(mappedUniforms + uniformStructStride * uniformsIndex) = uniforms; + uniformTransferBuffer->Unmap(); + + cmdbuffer->copyBuffer(uniformTransferBuffer.get(), uniformBuffer.get()); + PipelineBarrier() + .AddBuffer(uniformBuffer.get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) + .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); +} + +void GPURaytracer::ResolveAtlasImage(size_t i) +{ + LightmapImage& img = atlasImages[i]; + + PipelineBarrier() + .AddImage(img.raytrace.Image.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) + .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); + + RenderPassBegin() + .RenderPass(resolve.renderPass.get()) + .RenderArea(0, 0, atlasImageSize, atlasImageSize) + .Framebuffer(img.resolve.Framebuffer.get()) + .Execute(cmdbuffer.get()); + + VkDeviceSize offset = 0; + cmdbuffer->bindVertexBuffers(0, 1, &sceneVertexBuffer->buffer, &offset); + cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipeline.get()); + + auto descriptorSet = resolve.descriptorPool->allocate(resolve.descriptorSetLayout.get()); + descriptorSet->SetDebugName("resolve.descriptorSet"); + WriteDescriptors() + .AddCombinedImageSampler(descriptorSet.get(), 0, img.raytrace.View.get(), resolve.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + .Execute(device.get()); + cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipelineLayout.get(), 0, descriptorSet.get()); + resolve.descriptorSets.push_back(std::move(descriptorSet)); + + VkViewport viewport = {}; + viewport.maxDepth = 1; + viewport.width = (float)atlasImageSize; + viewport.height = (float)atlasImageSize; + cmdbuffer->setViewport(0, 1, &viewport); + + PushConstants pc; + pc.LightStart = 0; + pc.LightEnd = 0; + pc.SurfaceIndex = 0; + pc.LightmapOrigin = vec3(0.0f); + pc.LightmapStepX = vec3(0.0f); + pc.LightmapStepY = vec3(0.0f); + cmdbuffer->pushConstants(resolve.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstants), &pc); + + int firstVertex = sceneVertexPos; + int vertexCount = 4; + sceneVertexPos += vertexCount; + SceneVertex* vertex = &sceneVertices[firstVertex]; + vertex[0].Position = vec2(0.0f, 0.0f); + vertex[1].Position = vec2(1.0f, 0.0f); + vertex[2].Position = vec2(1.0f, 1.0f); + vertex[3].Position = vec2(0.0f, 1.0f); + cmdbuffer->draw(vertexCount, 1, firstVertex, 0); + + cmdbuffer->endRenderPass(); + + PipelineBarrier() + .AddImage(img.resolve.Image.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT) + .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.layerCount = 1; + region.imageExtent.width = atlasImageSize; + region.imageExtent.height = atlasImageSize; + region.imageExtent.depth = 1; + cmdbuffer->copyImageToBuffer(img.resolve.Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, img.Transfer->buffer, 1, ®ion); +} + +void GPURaytracer::DownloadAtlasImage(size_t pageIndex) +{ + struct hvec4 + { + unsigned short x, y, z, w; + vec3 xyz() { return vec3(halfToFloat(x), halfToFloat(y), halfToFloat(z)); } + }; + + hvec4* pixels = (hvec4*)atlasImages[pageIndex].Transfer->Map(0, atlasImageSize * atlasImageSize * sizeof(hvec4)); + + for (size_t i = 0; i < mesh->surfaces.size(); i++) + { + Surface* surface = mesh->surfaces[i].get(); + if (surface->atlasPageIndex != pageIndex) + continue; + + int atlasX = surface->atlasX; + int atlasY = surface->atlasY; + int sampleWidth = surface->texWidth; + int sampleHeight = surface->texHeight; + + for (int y = 0; y < sampleHeight; y++) { - int sampleWidth = surface->texWidth; - int sampleHeight = surface->texHeight; - - fullTaskCount += size_t(sampleHeight) * size_t(sampleWidth); - - SurfaceClip surfaceClip(surface); - - for (int y = 0; y < sampleHeight; y++) + vec3* dest = &surface->texPixels[y * sampleWidth]; + hvec4* src = &pixels[atlasX + (atlasY + y) * atlasImageSize]; + for (int x = 0; x < sampleWidth; x++) { - for (int x = 0; x < sampleWidth; x++) - { - if (surfaceClip.SampleIsInBounds(float(x), float(y))) - { - TraceTask task; - task.id = (int)i; - task.x = x; - task.y = y; - tasks.push_back(task); - } - } + dest[x] = src[x].xyz(); } } } - printf("\rGathering surface trace tasks: %llu / %llu\n", mesh->surfaces.size(), mesh->surfaces.size()); - printf("\tDiscarded %.3f%% of all tasks\n", (1.0 - double(tasks.size()) / fullTaskCount) * 100.0); + atlasImages[pageIndex].Transfer->Unmap(); +} + +vec2 GPURaytracer::ToUV(const vec3& vert, const Surface* targetSurface) +{ + vec3 localPos = vert - targetSurface->translateWorldToLocal; + float u = (1.0f + dot(localPos, targetSurface->projLocalToU)) / (targetSurface->texWidth + 2); + float v = (1.0f + dot(localPos, targetSurface->projLocalToV)) / (targetSurface->texHeight + 2); + return vec2(u, v); } void GPURaytracer::CreateVulkanObjects() { + submitFence = std::make_unique(device.get()); cmdpool = std::make_unique(device.get(), device->graphicsFamily); - cmdbuffer = cmdpool->createBuffer(); - cmdbuffer->begin(); + BeginCommands(); + + CreateSceneVertexBuffer(); + CreateSceneLightBuffer(); CreateVertexAndIndexBuffers(); + CreateUniformBuffer(); CreateBottomLevelAccelerationStructure(); CreateTopLevelAccelerationStructure(); CreateShaders(); - CreatePipeline(); - CreateDescriptorSet(); + CreateRaytracePipeline(); + CreateResolvePipeline(); - PipelineBarrier() - .AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); + FinishCommands(); } -void GPURaytracer::UploadTasks(const TraceTask* tasks, size_t size) +void GPURaytracer::CreateSceneVertexBuffer() { - if (!cmdbuffer) - { - cmdbuffer = cmdpool->createBuffer(); - cmdbuffer->begin(); - } + size_t size = sizeof(SceneVertex) * SceneVertexBufferSize; - size_t maxTasks = (size_t)rayTraceImageSize * rayTraceImageSize; - if (size > maxTasks) - throw std::runtime_error("Ray trace task count is too large"); + sceneVertexBuffer = BufferBuilder() + .Usage( + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, + VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT) + .MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + .Size(size) + .DebugName("SceneVertexBuffer") + .Create(device.get()); - size_t imageSize = sizeof(vec4) * rayTraceImageSize * rayTraceImageSize; - uint8_t* imageData = (uint8_t*)imageTransferBuffer->Map(0, imageSize); - vec4* startPositions = (vec4*)imageData; - for (size_t i = 0; i < size; i++) - { - const TraceTask& task = tasks[i]; - - if (task.id >= 0) - { - Surface* surface = mesh->surfaces[task.id].get(); - vec3 pos = surface->worldOrigin + surface->worldStepX * (task.x + 0.5f) + surface->worldStepY * (task.y + 0.5f); - startPositions[i] = vec4(pos, (float)task.id); - } - else - { - LightProbeSample& probe = mesh->lightProbes[(size_t)(-task.id) - 2]; - startPositions[i] = vec4(probe.Position, (float)-2); - } - - } - for (size_t i = size; i < maxTasks; i++) - { - startPositions[i] = vec4(0.0f, 0.0f, 0.0f, -1.0f); - } - imageTransferBuffer->Unmap(); - - PipelineBarrier() - .AddImage(startPositionsImage.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkBufferImageCopy region = {}; - region.bufferOffset = 0; - region.imageExtent.width = rayTraceImageSize; - region.imageExtent.height = rayTraceImageSize; - region.imageExtent.depth = 1; - region.imageSubresource.layerCount = 1; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - cmdbuffer->copyBufferToImage(imageTransferBuffer->buffer, startPositionsImage->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - PipelineBarrier() - .AddBuffer(uniformBuffer.get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) - .AddImage(startPositionsImage.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) - .AddImage(positionsImage.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, 0, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT) - .AddImage(outputImage.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_GENERAL, 0, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); + sceneVertices = (SceneVertex*)sceneVertexBuffer->Map(0, size); + sceneVertexPos = 0; } -void GPURaytracer::BeginTracing() +void GPURaytracer::CreateSceneLightBuffer() { - uniformsIndex = 0; - mappedUniforms = (uint8_t*)uniformTransferBuffer->Map(0, uniformStructs * uniformStructStride); + size_t size = sizeof(LightInfo) * SceneLightBufferSize; - cmdbuffer->copyBuffer(uniformTransferBuffer.get(), uniformBuffer.get()); - cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipeline.get()); + sceneLightBuffer = BufferBuilder() + .Usage( + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT) + .MemoryType( + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) + .Size(size) + .DebugName("SceneLightBuffer") + .Create(device.get()); + + sceneLights = (LightInfo*)sceneLightBuffer->Map(0, size); + sceneLightPos = 0; } -void GPURaytracer::RunTrace(const Uniforms& uniforms, const VkStridedDeviceAddressRegionKHR& rgenShader, int lightStart, int lightEnd) +void GPURaytracer::BeginCommands() { - if (uniformsIndex == uniformStructs) - { - EndTracing(); - BeginTracing(); - } - - *reinterpret_cast(mappedUniforms + uniformStructStride * uniformsIndex) = uniforms; - - uint32_t offset = (uint32_t)(uniformsIndex * uniformStructStride); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, pipelineLayout.get(), 0, descriptorSet.get(), 1, &offset); - - bool needbarrier = true; - if (uniformsIndex == 0) - { - PipelineBarrier() - .AddBuffer(uniformBuffer.get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) - .AddImage(positionsImage.get(), VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); - needbarrier = false; - } - uniformsIndex++; - - const int maxLights = 50; - - do - { - int count = std::min(lightEnd - lightStart, maxLights); - - if (needbarrier) - { - PipelineBarrier() - .AddImage(positionsImage.get(), VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR); - } - - PushConstants constants = {}; - constants.LightStart = lightStart; - constants.LightEnd = lightStart + count; - cmdbuffer->pushConstants(pipelineLayout.get(), VK_SHADER_STAGE_RAYGEN_BIT_KHR, 0, (uint32_t)sizeof(PushConstants), &constants); - cmdbuffer->traceRays(&rgenShader, &missRegion, &hitRegion, &callRegion, rayTraceImageSize, rayTraceImageSize, 1); - - needbarrier = true; - lightStart += count; - } while (lightStart < lightEnd); -} - -void GPURaytracer::EndTracing() -{ - mappedUniforms = nullptr; - uniformTransferBuffer->Unmap(); - cmdbuffer->end(); - - SubmitCommands(); - cmdbuffer = cmdpool->createBuffer(); cmdbuffer->begin(); } -void GPURaytracer::SubmitCommands() +void GPURaytracer::FinishCommands() { - auto submitFence = std::make_unique(device.get()); + cmdbuffer->end(); QueueSubmit() .AddCommandBuffer(cmdbuffer.get()) @@ -346,46 +407,435 @@ void GPURaytracer::SubmitCommands() cmdbuffer.reset(); } -void GPURaytracer::DownloadTasks(const TraceTask* tasks, size_t size) +void GPURaytracer::CreateVertexAndIndexBuffers() { + std::vector surfaces = CreateSurfaceInfo(); + + if (surfaces.empty()) // vulkan doesn't support zero byte buffers + surfaces.push_back(SurfaceInfo()); + + size_t vertexbuffersize = (size_t)mesh->MeshVertices.Size() * sizeof(vec3); + size_t indexbuffersize = (size_t)mesh->MeshElements.Size() * sizeof(uint32_t); + size_t surfaceindexbuffersize = (size_t)mesh->MeshSurfaces.Size() * sizeof(uint32_t); + size_t surfacebuffersize = (size_t)surfaces.size() * sizeof(SurfaceInfo); + size_t transferbuffersize = vertexbuffersize + indexbuffersize + surfaceindexbuffersize + surfacebuffersize; + size_t vertexoffset = 0; + size_t indexoffset = vertexoffset + vertexbuffersize; + size_t surfaceindexoffset = indexoffset + indexbuffersize; + size_t surfaceoffset = surfaceindexoffset + surfaceindexbuffersize; + size_t lightoffset = surfaceoffset + surfacebuffersize; + + vertexBuffer = BufferBuilder() + .Usage( + VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) + .Size(vertexbuffersize) + .DebugName("vertexBuffer") + .Create(device.get()); + + indexBuffer = BufferBuilder() + .Usage( + VK_BUFFER_USAGE_INDEX_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | + VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) + .Size(indexbuffersize) + .DebugName("indexBuffer") + .Create(device.get()); + + surfaceIndexBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) + .Size(surfaceindexbuffersize) + .DebugName("surfaceIndexBuffer") + .Create(device.get()); + + surfaceBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) + .Size(surfacebuffersize) + .DebugName("surfaceBuffer") + .Create(device.get()); + + transferBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .Size(transferbuffersize) + .DebugName("transferBuffer") + .Create(device.get()); + + uint8_t* data = (uint8_t*)transferBuffer->Map(0, transferbuffersize); + memcpy(data + vertexoffset, mesh->MeshVertices.Data(), vertexbuffersize); + memcpy(data + indexoffset, mesh->MeshElements.Data(), indexbuffersize); + memcpy(data + surfaceindexoffset, mesh->MeshSurfaces.Data(), surfaceindexbuffersize); + memcpy(data + surfaceoffset, surfaces.data(), surfacebuffersize); + transferBuffer->Unmap(); + + cmdbuffer->copyBuffer(transferBuffer.get(), vertexBuffer.get(), vertexoffset); + cmdbuffer->copyBuffer(transferBuffer.get(), indexBuffer.get(), indexoffset); + cmdbuffer->copyBuffer(transferBuffer.get(), surfaceIndexBuffer.get(), surfaceindexoffset); + cmdbuffer->copyBuffer(transferBuffer.get(), surfaceBuffer.get(), surfaceoffset); + PipelineBarrier() - .AddImage(outputImage.get(), VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkBufferImageCopy region = {}; - region.bufferOffset = 0; - region.imageExtent.width = rayTraceImageSize; - region.imageExtent.height = rayTraceImageSize; - region.imageExtent.depth = 1; - region.imageSubresource.layerCount = 1; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - cmdbuffer->copyImageToBuffer(outputImage->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageTransferBuffer->buffer, 1, ®ion); - cmdbuffer->end(); - - SubmitCommands(); - - size_t imageSize = sizeof(vec4) * rayTraceImageSize * rayTraceImageSize; - uint8_t* imageData = (uint8_t*)imageTransferBuffer->Map(0, imageSize); - vec4* output = (vec4*)imageData; - for (size_t i = 0; i < size; i++) - { - const TraceTask& task = tasks[i]; - if (task.id >= 0) - { - Surface* surface = mesh->surfaces[task.id].get(); - size_t sampleWidth = surface->texWidth; - surface->texPixels[task.x + task.y * sampleWidth] = vec3(output[i].x, output[i].y, output[i].z); - } - else - { - LightProbeSample& probe = mesh->lightProbes[(size_t)(-task.id) - 2]; - probe.Color = vec3(output[i].x, output[i].y, output[i].z); - } - } - imageTransferBuffer->Unmap(); + .AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) + .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); } -void GPURaytracer::CreateVertexAndIndexBuffers() +void GPURaytracer::CreateBottomLevelAccelerationStructure() +{ + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR }; + VkAccelerationStructureGeometryKHR accelStructBLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR }; + VkAccelerationStructureGeometryKHR* geometries[] = { &accelStructBLDesc }; + VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {}; + VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo }; + + accelStructBLDesc.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; + accelStructBLDesc.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; + accelStructBLDesc.geometry.triangles = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR }; + accelStructBLDesc.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; + accelStructBLDesc.geometry.triangles.vertexData.deviceAddress = vertexBuffer->GetDeviceAddress(); + accelStructBLDesc.geometry.triangles.vertexStride = sizeof(vec3); + accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32; + accelStructBLDesc.geometry.triangles.indexData.deviceAddress = indexBuffer->GetDeviceAddress(); + accelStructBLDesc.geometry.triangles.maxVertex = mesh->MeshVertices.Size() - 1; + + buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; + buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; + buildInfo.geometryCount = 1; + buildInfo.pGeometries = &accelStructBLDesc; + + uint32_t maxPrimitiveCount = mesh->MeshElements.Size() / 3; + + VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR }; + vkGetAccelerationStructureBuildSizesKHR(device->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxPrimitiveCount, &sizeInfo); + + blAccelStructBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) + .Size(sizeInfo.accelerationStructureSize) + .DebugName("blAccelStructBuffer") + .Create(device.get()); + + blAccelStruct = AccelerationStructureBuilder() + .Type(VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) + .Buffer(blAccelStructBuffer.get(), sizeInfo.accelerationStructureSize) + .Create(device.get()); + + blScratchBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) + .Size(sizeInfo.buildScratchSize) + .DebugName("blScratchBuffer") + .Create(device.get()); + + buildInfo.dstAccelerationStructure = blAccelStruct->accelstruct; + buildInfo.scratchData.deviceAddress = blScratchBuffer->GetDeviceAddress(); + rangeInfo.primitiveCount = maxPrimitiveCount; + + cmdbuffer->buildAccelerationStructures(1, &buildInfo, rangeInfos); + + // Finish building before using it as input to a toplevel accel structure + PipelineBarrier() + .AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR) + .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); +} + +void GPURaytracer::CreateTopLevelAccelerationStructure() +{ + VkAccelerationStructureInstanceKHR instance = {}; + instance.transform.matrix[0][0] = 1.0f; + instance.transform.matrix[1][1] = 1.0f; + instance.transform.matrix[2][2] = 1.0f; + instance.mask = 0xff; + instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; + instance.accelerationStructureReference = blAccelStruct->GetDeviceAddress(); + + tlTransferBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .Size(sizeof(VkAccelerationStructureInstanceKHR)) + .DebugName("tlTransferBuffer") + .Create(device.get()); + + auto data = (uint8_t*)tlTransferBuffer->Map(0, sizeof(VkAccelerationStructureInstanceKHR)); + memcpy(data, &instance, sizeof(VkAccelerationStructureInstanceKHR)); + tlTransferBuffer->Unmap(); + + tlInstanceBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_DST_BIT) + .Size(sizeof(VkAccelerationStructureInstanceKHR)) + .DebugName("tlInstanceBuffer") + .Create(device.get()); + + cmdbuffer->copyBuffer(tlTransferBuffer.get(), tlInstanceBuffer.get()); + + PipelineBarrier() + .AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) + .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); + + VkAccelerationStructureGeometryKHR accelStructTLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR }; + VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR }; + VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {}; + VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo }; + + accelStructTLDesc.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; + accelStructTLDesc.geometry.instances = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR }; + accelStructTLDesc.geometry.instances.data.deviceAddress = tlInstanceBuffer->GetDeviceAddress(); + + buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; + buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; + buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; + buildInfo.geometryCount = 1; + buildInfo.pGeometries = &accelStructTLDesc; + + uint32_t maxInstanceCount = 1; + + VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR }; + vkGetAccelerationStructureBuildSizesKHR(device->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxInstanceCount, &sizeInfo); + + tlAccelStructBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) + .Size(sizeInfo.accelerationStructureSize) + .DebugName("tlAccelStructBuffer") + .Create(device.get()); + + tlAccelStruct = AccelerationStructureBuilder() + .Type(VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR) + .Buffer(tlAccelStructBuffer.get(), sizeInfo.accelerationStructureSize) + .DebugName("tlAccelStruct") + .Create(device.get()); + + tlScratchBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) + .Size(sizeInfo.buildScratchSize) + .DebugName("tlScratchBuffer") + .Create(device.get()); + + buildInfo.dstAccelerationStructure = tlAccelStruct->accelstruct; + buildInfo.scratchData.deviceAddress = tlScratchBuffer->GetDeviceAddress(); + rangeInfo.primitiveCount = maxInstanceCount; + + cmdbuffer->buildAccelerationStructures(1, &buildInfo, rangeInfos); + + PipelineBarrier() + .AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR) + .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); +} + +void GPURaytracer::CreateShaders() +{ + vertShader = ShaderBuilder() + .VertexShader(glsl_vert) + .DebugName("vertShader") + .Create("vertShader", device.get()); + + fragShader = ShaderBuilder() + .FragmentShader(glsl_frag) + .DebugName("fragShader") + .Create("fragShader", device.get()); + + fragResolveShader = ShaderBuilder() + .FragmentShader(glsl_frag_resolve) + .DebugName("fragResolveShader") + .Create("fragResolveShader", device.get()); +} + +void GPURaytracer::CreateRaytracePipeline() +{ + raytrace.descriptorSetLayout = DescriptorSetLayoutBuilder() + .AddBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT) + .AddBinding(1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) + .AddBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) + .AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) + .AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) + .DebugName("raytrace.descriptorSetLayout") + .Create(device.get()); + + raytrace.pipelineLayout = PipelineLayoutBuilder() + .AddSetLayout(raytrace.descriptorSetLayout.get()) + .AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants)) + .DebugName("raytrace.pipelineLayout") + .Create(device.get()); + + raytrace.renderPass = RenderPassBuilder() + .AddAttachment( + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_SAMPLE_COUNT_4_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + .AddSubpass() + .AddSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + .AddExternalSubpassDependency( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) + .DebugName("raytrace.renderpass") + .Create(device.get()); + + raytrace.pipeline = GraphicsPipelineBuilder() + .Layout(raytrace.pipelineLayout.get()) + .RenderPass(raytrace.renderPass.get()) + .AddVertexShader(vertShader.get()) + .AddFragmentShader(fragShader.get()) + .AddVertexBufferBinding(0, sizeof(SceneVertex)) + .AddVertexAttribute(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(SceneVertex, Position)) + .Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) + .AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT) + .RasterizationSamples(VK_SAMPLE_COUNT_4_BIT) + .Viewport(0.0f, 0.0f, 0.0f, 0.0f) + .Scissor(0, 0, 4096, 4096) + .DebugName("raytrace.pipeline") + .Create(device.get()); + + raytrace.descriptorPool = DescriptorPoolBuilder() + .AddPoolSize(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1) + .AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1) + .AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3) + .MaxSets(1) + .DebugName("raytrace.descriptorPool") + .Create(device.get()); + + raytrace.descriptorSet = raytrace.descriptorPool->allocate(raytrace.descriptorSetLayout.get()); + raytrace.descriptorSet->SetDebugName("raytrace.descriptorSet"); + + WriteDescriptors() + .AddAccelerationStructure(raytrace.descriptorSet.get(), 0, tlAccelStruct.get()) + .AddBuffer(raytrace.descriptorSet.get(), 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uniformBuffer.get(), 0, sizeof(Uniforms)) + .AddBuffer(raytrace.descriptorSet.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceIndexBuffer.get()) + .AddBuffer(raytrace.descriptorSet.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceBuffer.get()) + .AddBuffer(raytrace.descriptorSet.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, sceneLightBuffer.get()) + .Execute(device.get()); +} + +void GPURaytracer::CreateResolvePipeline() +{ + resolve.descriptorSetLayout = DescriptorSetLayoutBuilder() + .AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) + .DebugName("resolve.descriptorSetLayout") + .Create(device.get()); + + resolve.pipelineLayout = PipelineLayoutBuilder() + .AddSetLayout(resolve.descriptorSetLayout.get()) + .AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstants)) + .DebugName("resolve.pipelineLayout") + .Create(device.get()); + + resolve.renderPass = RenderPassBuilder() + .AddAttachment( + VK_FORMAT_R16G16B16A16_SFLOAT, + VK_SAMPLE_COUNT_1_BIT, + VK_ATTACHMENT_LOAD_OP_DONT_CARE, + VK_ATTACHMENT_STORE_OP_STORE, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + .AddSubpass() + .AddSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + .AddExternalSubpassDependency( + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) + .DebugName("resolve.renderpass") + .Create(device.get()); + + resolve.pipeline = GraphicsPipelineBuilder() + .Layout(resolve.pipelineLayout.get()) + .RenderPass(resolve.renderPass.get()) + .AddVertexShader(vertShader.get()) + .AddFragmentShader(fragResolveShader.get()) + .AddVertexBufferBinding(0, sizeof(SceneVertex)) + .AddVertexAttribute(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(SceneVertex, Position)) + .Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) + .AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT) + .Viewport(0.0f, 0.0f, 0.0f, 0.0f) + .Scissor(0, 0, 4096, 4096) + .DebugName("resolve.pipeline") + .Create(device.get()); + + resolve.descriptorPool = DescriptorPoolBuilder() + .AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 256) + .MaxSets(256) + .DebugName("resolve.descriptorPool") + .Create(device.get()); + + resolve.sampler = SamplerBuilder() + .DebugName("resolve.Sampler") + .Create(device.get()); +} + +LightmapImage GPURaytracer::CreateImage(int width, int height) +{ + LightmapImage img; + + img.raytrace.Image = ImageBuilder() + .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) + .Format(VK_FORMAT_R16G16B16A16_SFLOAT) + .Size(width, height) + .Samples(VK_SAMPLE_COUNT_4_BIT) + .DebugName("LightmapImage.raytrace.Image") + .Create(device.get()); + + img.raytrace.View = ImageViewBuilder() + .Image(img.raytrace.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) + .DebugName("LightmapImage.raytrace.View") + .Create(device.get()); + + img.raytrace.Framebuffer = FramebufferBuilder() + .RenderPass(raytrace.renderPass.get()) + .Size(width, height) + .AddAttachment(img.raytrace.View.get()) + .DebugName("LightmapImage.raytrace.Framebuffer") + .Create(device.get()); + + img.resolve.Image = ImageBuilder() + .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) + .Format(VK_FORMAT_R16G16B16A16_SFLOAT) + .Size(width, height) + .DebugName("LightmapImage.resolve.Image") + .Create(device.get()); + + img.resolve.View = ImageViewBuilder() + .Image(img.resolve.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) + .DebugName("LightmapImage.resolve.View") + .Create(device.get()); + + img.resolve.Framebuffer = FramebufferBuilder() + .RenderPass(resolve.renderPass.get()) + .Size(width, height) + .AddAttachment(img.resolve.View.get()) + .DebugName("LightmapImage.resolve.Framebuffer") + .Create(device.get()); + + img.Transfer = BufferBuilder() + .Size(width * height * sizeof(vec4)) + .Usage(VK_IMAGE_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_CPU_ONLY) + .DebugName("LightmapImage.Transfer") + .Create(device.get()); + + return img; +} + +void GPURaytracer::CreateUniformBuffer() +{ + VkDeviceSize align = device->physicalDevice.properties.limits.minUniformBufferOffsetAlignment; + uniformStructStride = (sizeof(Uniforms) + align - 1) / align * align; + + uniformBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) + .Size(uniformStructs * uniformStructStride) + .DebugName("uniformBuffer") + .Create(device.get()); + + uniformTransferBuffer = BufferBuilder() + .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU) + .Size(uniformStructs * uniformStructStride) + .DebugName("uniformTransferBuffer") + .Create(device.get()); +} + +std::vector GPURaytracer::CreateSurfaceInfo() { std::vector surfaces; surfaces.reserve(mesh->surfaces.size()); @@ -437,531 +887,7 @@ void GPURaytracer::CreateVertexAndIndexBuffers() info.SamplingDistance = float(surface->sampleDimension); surfaces.push_back(info); } - - std::vector lights; - for (ThingLight& light : mesh->map->ThingLights) - { - LightInfo info; - info.Origin = light.LightOrigin(); - info.Radius = light.LightRadius(); - info.Intensity = light.intensity; - info.InnerAngleCos = light.innerAngleCos; - info.OuterAngleCos = light.outerAngleCos; - info.SpotDir = light.SpotDir(); - info.Color = light.rgb; - lights.push_back(info); - } - - if (lights.empty()) // vulkan doesn't support zero byte buffers - lights.push_back(LightInfo()); - - size_t vertexbuffersize = (size_t)mesh->MeshVertices.Size() * sizeof(vec3); - size_t indexbuffersize = (size_t)mesh->MeshElements.Size() * sizeof(uint32_t); - size_t surfaceindexbuffersize = (size_t)mesh->MeshSurfaces.Size() * sizeof(uint32_t); - size_t surfacebuffersize = (size_t)surfaces.size() * sizeof(SurfaceInfo); - size_t lightbuffersize = (size_t)lights.size() * sizeof(LightInfo); - size_t transferbuffersize = vertexbuffersize + indexbuffersize + surfaceindexbuffersize + surfacebuffersize + lightbuffersize; - size_t vertexoffset = 0; - size_t indexoffset = vertexoffset + vertexbuffersize; - size_t surfaceindexoffset = indexoffset + indexbuffersize; - size_t surfaceoffset = surfaceindexoffset + surfaceindexbuffersize; - size_t lightoffset = surfaceoffset + surfacebuffersize; - - vertexBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) - .Size(vertexbuffersize) - .DebugName("vertexBuffer") - .Create(device.get()); - - indexBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) - .Size(indexbuffersize) - .DebugName("indexBuffer") - .Create(device.get()); - - surfaceIndexBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(surfaceindexbuffersize) - .DebugName("surfaceIndexBuffer") - .Create(device.get()); - - surfaceBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(surfacebuffersize) - .DebugName("surfaceBuffer") - .Create(device.get()); - - lightBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(lightbuffersize) - .DebugName("lightBuffer") - .Create(device.get()); - - transferBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) - .Size(transferbuffersize) - .DebugName("transferBuffer") - .Create(device.get()); - - uint8_t* data = (uint8_t*)transferBuffer->Map(0, transferbuffersize); - memcpy(data + vertexoffset, mesh->MeshVertices.Data(), vertexbuffersize); - memcpy(data + indexoffset, mesh->MeshElements.Data(), indexbuffersize); - memcpy(data + surfaceindexoffset, mesh->MeshSurfaces.Data(), surfaceindexbuffersize); - memcpy(data + surfaceoffset, surfaces.data(), surfacebuffersize); - memcpy(data + lightoffset, lights.data(), lightbuffersize); - transferBuffer->Unmap(); - - cmdbuffer->copyBuffer(transferBuffer.get(), vertexBuffer.get(), vertexoffset); - cmdbuffer->copyBuffer(transferBuffer.get(), indexBuffer.get(), indexoffset); - cmdbuffer->copyBuffer(transferBuffer.get(), surfaceIndexBuffer.get(), surfaceindexoffset); - cmdbuffer->copyBuffer(transferBuffer.get(), surfaceBuffer.get(), surfaceoffset); - cmdbuffer->copyBuffer(transferBuffer.get(), lightBuffer.get(), lightoffset); - - VkMemoryBarrier barrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER }; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; - cmdbuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, 0, 1, &barrier, 0, nullptr, 0, nullptr); -} - -void GPURaytracer::CreateBottomLevelAccelerationStructure() -{ - VkBufferDeviceAddressInfo info = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO }; - info.buffer = vertexBuffer->buffer; - VkDeviceAddress vertexAddress = vkGetBufferDeviceAddress(device->device, &info); - - info = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO }; - info.buffer = indexBuffer->buffer; - VkDeviceAddress indexAddress = vkGetBufferDeviceAddress(device->device, &info); - - VkAccelerationStructureGeometryTrianglesDataKHR triangles = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR }; - triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; - triangles.vertexData.deviceAddress = vertexAddress; - triangles.vertexStride = sizeof(vec3); - triangles.indexType = VK_INDEX_TYPE_UINT32; - triangles.indexData.deviceAddress = indexAddress; - triangles.maxVertex = mesh->MeshVertices.Size(); - - VkAccelerationStructureGeometryKHR accelStructBLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR }; - accelStructBLDesc.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - accelStructBLDesc.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - accelStructBLDesc.geometry.triangles = triangles; - - VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {}; - rangeInfo.primitiveCount = mesh->MeshElements.Size() / 3; - - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR }; - buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - buildInfo.flags = accelStructBLDesc.flags | VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - buildInfo.geometryCount = 1; - buildInfo.pGeometries = &accelStructBLDesc; - - uint32_t maxPrimitiveCount = rangeInfo.primitiveCount; - - VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR }; - vkGetAccelerationStructureBuildSizesKHR(device->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxPrimitiveCount, &sizeInfo); - - blAccelStructBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) - .Size(sizeInfo.accelerationStructureSize) - .DebugName("blAccelStructBuffer") - .Create(device.get()); - - VkAccelerationStructureKHR blAccelStructHandle = {}; - VkAccelerationStructureCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR }; - createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - createInfo.buffer = blAccelStructBuffer->buffer; - createInfo.size = sizeInfo.accelerationStructureSize; - VkResult result = vkCreateAccelerationStructureKHR(device->device, &createInfo, nullptr, &blAccelStructHandle); - if (result != VK_SUCCESS) - throw std::runtime_error("vkCreateAccelerationStructureKHR failed"); - blAccelStruct = std::make_unique(device.get(), blAccelStructHandle); - - blScratchBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) - .Size(sizeInfo.buildScratchSize) - .DebugName("blScratchBuffer") - .Create(device.get()); - - info = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO }; - info.buffer = blScratchBuffer->buffer; - VkDeviceAddress scratchAddress = vkGetBufferDeviceAddress(device->device, &info); - - buildInfo.dstAccelerationStructure = blAccelStruct->accelstruct; - buildInfo.scratchData.deviceAddress = scratchAddress; - VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo }; - cmdbuffer->buildAccelerationStructures(1, &buildInfo, rangeInfos); -} - -void GPURaytracer::CreateTopLevelAccelerationStructure() -{ - VkAccelerationStructureDeviceAddressInfoKHR addressInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_DEVICE_ADDRESS_INFO_KHR }; - addressInfo.accelerationStructure = blAccelStruct->accelstruct; - VkDeviceAddress blAccelStructAddress = vkGetAccelerationStructureDeviceAddressKHR(device->device, &addressInfo); - - VkAccelerationStructureInstanceKHR instance = {}; - instance.transform.matrix[0][0] = 1.0f; - instance.transform.matrix[1][1] = 1.0f; - instance.transform.matrix[2][2] = 1.0f; - instance.instanceCustomIndex = 0; - instance.accelerationStructureReference = blAccelStructAddress; - instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - instance.mask = 0xff; - instance.instanceShaderBindingTableRecordOffset = 0; - - tlTransferBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) - .Size(sizeof(VkAccelerationStructureInstanceKHR)) - .DebugName("tlTransferBuffer") - .Create(device.get()); - - auto data = (uint8_t*)tlTransferBuffer->Map(0, sizeof(VkAccelerationStructureInstanceKHR)); - memcpy(data, &instance, sizeof(VkAccelerationStructureInstanceKHR)); - tlTransferBuffer->Unmap(); - - tlInstanceBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(sizeof(VkAccelerationStructureInstanceKHR)) - .DebugName("tlInstanceBuffer") - .Create(device.get()); - - cmdbuffer->copyBuffer(tlTransferBuffer.get(), tlInstanceBuffer.get()); - - VkMemoryBarrier barrier = { VK_STRUCTURE_TYPE_MEMORY_BARRIER }; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR; - cmdbuffer->pipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, 0, 1, &barrier, 0, nullptr, 0, nullptr); - - VkBufferDeviceAddressInfo info = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO }; - info.buffer = tlInstanceBuffer->buffer; - VkDeviceAddress instanceBufferAddress = vkGetBufferDeviceAddress(device->device, &info); - - VkAccelerationStructureGeometryInstancesDataKHR instances = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR }; - instances.data.deviceAddress = instanceBufferAddress; - - VkAccelerationStructureGeometryKHR accelStructTLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR }; - accelStructTLDesc.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - accelStructTLDesc.geometry.instances = instances; - - VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {}; - rangeInfo.primitiveCount = 1; - - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR }; - buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - buildInfo.geometryCount = 1; - buildInfo.pGeometries = &accelStructTLDesc; - buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - buildInfo.srcAccelerationStructure = VK_NULL_HANDLE; - - uint32_t maxInstanceCount = 1; - - VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR }; - vkGetAccelerationStructureBuildSizesKHR(device->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxInstanceCount, &sizeInfo); - - tlAccelStructBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) - .Size(sizeInfo.accelerationStructureSize) - .DebugName("tlAccelStructBuffer") - .Create(device.get()); - - VkAccelerationStructureKHR tlAccelStructHandle = {}; - VkAccelerationStructureCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_KHR }; - createInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - createInfo.buffer = tlAccelStructBuffer->buffer; - createInfo.size = sizeInfo.accelerationStructureSize; - VkResult result = vkCreateAccelerationStructureKHR(device->device, &createInfo, nullptr, &tlAccelStructHandle); - if (result != VK_SUCCESS) - throw std::runtime_error("vkCreateAccelerationStructureKHR failed"); - tlAccelStruct = std::make_unique(device.get(), tlAccelStructHandle); - - tlScratchBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) - .Size(sizeInfo.buildScratchSize) - .DebugName("tlScratchBuffer") - .Create(device.get()); - - info = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO }; - info.buffer = tlScratchBuffer->buffer; - VkDeviceAddress scratchAddress = vkGetBufferDeviceAddress(device->device, &info); - - buildInfo.dstAccelerationStructure = tlAccelStruct->accelstruct; - buildInfo.scratchData.deviceAddress = scratchAddress; - - VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo }; - cmdbuffer->buildAccelerationStructures(1, &buildInfo, rangeInfos); -} - -void GPURaytracer::CreateShaders() -{ - rgenBounce = CompileRayGenShader(glsl_rgen_bounce, "rgen.bounce"); - rgenLight = CompileRayGenShader(glsl_rgen_light, "rgen.light"); - rgenAmbient = CompileRayGenShader(glsl_rgen_ambient, "rgen.ambient"); - rchitBounce = CompileClosestHitShader(glsl_rchit_bounce, "rchit.bounce"); - rchitLight = CompileClosestHitShader(glsl_rchit_light, "rchit.light"); - rchitSun = CompileClosestHitShader(glsl_rchit_sun, "rchit.sun"); - rchitAmbient = CompileClosestHitShader(glsl_rchit_ambient, "rchit.ambient"); - rmissBounce = CompileMissShader(glsl_rmiss_bounce, "rmiss.bounce"); - rmissLight = CompileMissShader(glsl_rmiss_light, "rmiss.light"); - rmissSun = CompileMissShader(glsl_rmiss_sun, "rmiss.sun"); - rmissAmbient = CompileMissShader(glsl_rmiss_ambient, "rmiss.ambient"); -} - -std::unique_ptr GPURaytracer::CompileRayGenShader(const char* code, const char* name) -{ - try - { - return ShaderBuilder() - .RayGenShader(code) - .DebugName(name) - .Create(name, device.get()); - } - catch (const std::exception& e) - { - throw std::runtime_error(std::string("Could not compile ") + name + ": " + e.what()); - } -} - -std::unique_ptr GPURaytracer::CompileClosestHitShader(const char* code, const char* name) -{ - try - { - return ShaderBuilder() - .ClosestHitShader(code) - .DebugName(name) - .Create(name, device.get()); - } - catch (const std::exception& e) - { - throw std::runtime_error(std::string("Could not compile ") + name + ": " + e.what()); - } -} - -std::unique_ptr GPURaytracer::CompileMissShader(const char* code, const char* name) -{ - try - { - return ShaderBuilder() - .MissShader(code) - .DebugName(name) - .Create(name, device.get()); - } - catch (const std::exception& e) - { - throw std::runtime_error(std::string("Could not compile ") + name + ": " + e.what()); - } -} - -void GPURaytracer::CreatePipeline() -{ - descriptorSetLayout = DescriptorSetLayoutBuilder() - .AddBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR) - .AddBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR) - .AddBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR) - .AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR) - .AddBinding(4, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR) - .AddBinding(5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR) - .AddBinding(6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR) - .AddBinding(7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_RAYGEN_BIT_KHR) - .DebugName("descriptorSetLayout") - .Create(device.get()); - - pipelineLayout = PipelineLayoutBuilder() - .AddSetLayout(descriptorSetLayout.get()) - .AddPushConstantRange(VK_SHADER_STAGE_RAYGEN_BIT_KHR, 0, sizeof(PushConstants)) - .DebugName("pipelineLayout") - .Create(device.get()); - - pipeline = RayTracingPipelineBuilder() - .Layout(pipelineLayout.get()) - .MaxPipelineRayRecursionDepth(1) - .AddShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenBounce.get()) - .AddShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenLight.get()) - .AddShader(VK_SHADER_STAGE_RAYGEN_BIT_KHR, rgenAmbient.get()) - .AddShader(VK_SHADER_STAGE_MISS_BIT_KHR, rmissBounce.get()) - .AddShader(VK_SHADER_STAGE_MISS_BIT_KHR, rmissLight.get()) - .AddShader(VK_SHADER_STAGE_MISS_BIT_KHR, rmissSun.get()) - .AddShader(VK_SHADER_STAGE_MISS_BIT_KHR, rmissAmbient.get()) - .AddShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, rchitBounce.get()) - .AddShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, rchitLight.get()) - .AddShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, rchitSun.get()) - .AddShader(VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR, rchitAmbient.get()) - .AddRayGenGroup(0) - .AddRayGenGroup(1) - .AddRayGenGroup(2) - .AddMissGroup(3) - .AddMissGroup(4) - .AddMissGroup(5) - .AddMissGroup(6) - .AddTrianglesHitGroup(7) - .AddTrianglesHitGroup(8) - .AddTrianglesHitGroup(9) - .AddTrianglesHitGroup(10) - .DebugName("pipeline") - .Create(device.get()); - - const auto& rtProperties = device->physicalDevice.rayTracingProperties; - - auto align_up = [](VkDeviceSize value, VkDeviceSize alignment) - { - if (alignment != 0) - return (value + alignment - 1) / alignment * alignment; - else - return value; - }; - - VkDeviceSize raygenCount = 3; - VkDeviceSize missCount = 4; - VkDeviceSize hitCount = 4; - - VkDeviceSize handleSize = rtProperties.shaderGroupHandleSize; - VkDeviceSize handleSizeAligned = align_up(handleSize, rtProperties.shaderGroupHandleAlignment); - - VkDeviceSize rgenStride = align_up(handleSizeAligned, rtProperties.shaderGroupBaseAlignment); - VkDeviceSize rgenSize = rgenStride * raygenCount; - - missRegion.stride = handleSizeAligned; - missRegion.size = align_up(missCount * handleSizeAligned, rtProperties.shaderGroupBaseAlignment); - - hitRegion.stride = handleSizeAligned; - hitRegion.size = align_up(hitCount * handleSizeAligned, rtProperties.shaderGroupBaseAlignment); - - VkDeviceSize rgenOffset = 0; - VkDeviceSize missOffset = rgenOffset + rgenSize; - VkDeviceSize hitOffset = missOffset + missRegion.size; - - VkDeviceSize sbtBufferSize = rgenSize + missRegion.size + hitRegion.size; - - shaderBindingTable = BufferBuilder() - .Usage(VK_BUFFER_USAGE_SHADER_BINDING_TABLE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(sbtBufferSize) - .DebugName("shaderBindingTable") - .Create(device.get()); - - sbtTransferBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) - .Size(sbtBufferSize) - .DebugName("sbtTransferBuffer") - .Create(device.get()); - - uint8_t* src = (uint8_t*)pipeline->shaderGroupHandles.data(); - uint8_t* dest = (uint8_t*)sbtTransferBuffer->Map(0, sbtBufferSize); - for (VkDeviceSize i = 0; i < raygenCount; i++) - { - memcpy(dest + rgenOffset + i * rgenStride, src, handleSize); - src += handleSize; - } - for (VkDeviceSize i = 0; i < missCount; i++) - { - memcpy(dest + missOffset + i * missRegion.stride, src, handleSize); - src += handleSize; - } - for (VkDeviceSize i = 0; i < hitCount; i++) - { - memcpy(dest + hitOffset + i * hitRegion.stride, src, handleSize); - src += handleSize; - } - sbtTransferBuffer->Unmap(); - - cmdbuffer->copyBuffer(sbtTransferBuffer.get(), shaderBindingTable.get()); - - VkBufferDeviceAddressInfo info = { VK_STRUCTURE_TYPE_BUFFER_DEVICE_ADDRESS_INFO }; - info.buffer = shaderBindingTable->buffer; - VkDeviceAddress sbtAddress = vkGetBufferDeviceAddress(device->device, &info); - - int i = 0; - for (VkStridedDeviceAddressRegionKHR* region : { &rgenBounceRegion, &rgenLightRegion, &rgenAmbientRegion }) - { - region->stride = rgenStride; - region->size = rgenStride; - region->deviceAddress = sbtAddress + rgenOffset + rgenStride * i; - i++; - } - missRegion.deviceAddress = sbtAddress + missOffset; - hitRegion.deviceAddress = sbtAddress + hitOffset; -} - -void GPURaytracer::CreateDescriptorSet() -{ - VkDeviceSize align = device->physicalDevice.properties.limits.minUniformBufferOffsetAlignment; - uniformStructStride = (sizeof(Uniforms) + align - 1) / align * align; - - uniformBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(uniformStructs * uniformStructStride) - .DebugName("uniformBuffer") - .Create(device.get()); - - uniformTransferBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU) - .Size(uniformStructs * uniformStructStride) - .DebugName("uniformTransferBuffer") - .Create(device.get()); - - imageTransferBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) - .Size(2 * sizeof(vec4) * rayTraceImageSize * rayTraceImageSize) - .DebugName("imageTransferBuffer") - .Create(device.get()); - - startPositionsImage = ImageBuilder() - .Usage(VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) - .Format(VK_FORMAT_R32G32B32A32_SFLOAT) - .Size(rayTraceImageSize, rayTraceImageSize) - .DebugName("startPositionsImage") - .Create(device.get()); - - positionsImage = ImageBuilder() - .Usage(VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT) - .Format(VK_FORMAT_R32G32B32A32_SFLOAT) - .Size(rayTraceImageSize, rayTraceImageSize) - .DebugName("positionsImage") - .Create(device.get()); - - outputImage = ImageBuilder() - .Usage(VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) - .Format(VK_FORMAT_R32G32B32A32_SFLOAT) - .Size(rayTraceImageSize, rayTraceImageSize) - .DebugName("outputImage") - .Create(device.get()); - - startPositionsImageView = ImageViewBuilder() - .Image(startPositionsImage.get(), VK_FORMAT_R32G32B32A32_SFLOAT) - .DebugName("startPositionsImageView") - .Create(device.get()); - - positionsImageView = ImageViewBuilder() - .Image(positionsImage.get(), VK_FORMAT_R32G32B32A32_SFLOAT) - .DebugName("positionsImageView") - .Create(device.get()); - - outputImageView = ImageViewBuilder() - .Image(outputImage.get(), VK_FORMAT_R32G32B32A32_SFLOAT) - .DebugName("outputImageView") - .Create(device.get()); - - descriptorPool = DescriptorPoolBuilder() - .AddPoolSize(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1) - .AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 3) - .AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1) - .AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3) - .MaxSets(1) - .DebugName("descriptorPool") - .Create(device.get()); - - descriptorSet = descriptorPool->allocate(descriptorSetLayout.get()); - descriptorSet->SetDebugName("descriptorSet"); - - WriteDescriptors() - .AddAccelerationStructure(descriptorSet.get(), 0, tlAccelStruct.get()) - .AddStorageImage(descriptorSet.get(), 1, startPositionsImageView.get(), VK_IMAGE_LAYOUT_GENERAL) - .AddStorageImage(descriptorSet.get(), 2, positionsImageView.get(), VK_IMAGE_LAYOUT_GENERAL) - .AddStorageImage(descriptorSet.get(), 3, outputImageView.get(), VK_IMAGE_LAYOUT_GENERAL) - .AddBuffer(descriptorSet.get(), 4, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, uniformBuffer.get(), 0, sizeof(Uniforms)) - .AddBuffer(descriptorSet.get(), 5, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceIndexBuffer.get()) - .AddBuffer(descriptorSet.get(), 6, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceBuffer.get()) - .AddBuffer(descriptorSet.get(), 7, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, lightBuffer.get()) - .Execute(device.get()); + return surfaces; } void GPURaytracer::PrintVulkanInfo() @@ -987,17 +913,11 @@ void GPURaytracer::PrintVulkanInfo() printf("Vulkan version: %s (api) %s (driver)\n", apiVersion.c_str(), driverVersion.c_str()); } -vec2 GPURaytracer::Hammersley(uint32_t i, uint32_t N) +bool GPURaytracer::IsNegativelyOriented(const vec2& v1, const vec2& v2, const vec2& v3) { - return vec2(float(i) / float(N), RadicalInverse_VdC(i)); -} - -float GPURaytracer::RadicalInverse_VdC(uint32_t bits) -{ - bits = (bits << 16u) | (bits >> 16u); - bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); - bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); - bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); - bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); - return float(bits) * 2.3283064365386963e-10f; // / 0x100000000 + float A = + v1.x * v2.y - v2.x * v1.y + + v2.x * v3.y - v3.x * v2.y + + v3.x * v1.y - v1.x * v3.y; + return A < 0.0f; } diff --git a/src/lightmap/gpuraytracer.h b/src/lightmap/gpuraytracer.h index 4767da7..b33d04d 100644 --- a/src/lightmap/gpuraytracer.h +++ b/src/lightmap/gpuraytracer.h @@ -8,23 +8,24 @@ class LevelMesh; struct Uniforms { - uint32_t SampleIndex; - uint32_t SampleCount; - uint32_t PassType; - uint32_t Padding0; vec3 SunDir; float Padding1; vec3 SunColor; float SunIntensity; - vec3 HemisphereVec; - float Padding2; }; struct PushConstants { uint32_t LightStart; uint32_t LightEnd; - ivec2 pushPadding; + int32_t SurfaceIndex; + int32_t PushPadding1; + vec3 LightmapOrigin; + float PushPadding2; + vec3 LightmapStepX; + float PushPadding3; + vec3 LightmapStepY; + float PushPadding4; }; struct SurfaceInfo @@ -52,9 +53,28 @@ struct LightInfo float Padding2; }; -struct TraceTask +struct LightmapImage { - int id, x, y; + struct + { + std::unique_ptr Image; + std::unique_ptr View; + std::unique_ptr Framebuffer; + } raytrace; + + struct + { + std::unique_ptr Image; + std::unique_ptr View; + std::unique_ptr Framebuffer; + } resolve; + + std::unique_ptr Transfer; +}; + +struct SceneVertex +{ + vec2 Position; }; class GPURaytracer @@ -66,31 +86,34 @@ public: void Raytrace(LevelMesh* level); private: - void CreateTasks(std::vector& tasks); void CreateVulkanObjects(); void CreateVertexAndIndexBuffers(); void CreateBottomLevelAccelerationStructure(); void CreateTopLevelAccelerationStructure(); void CreateShaders(); - std::unique_ptr CompileRayGenShader(const char* code, const char* name); - std::unique_ptr CompileClosestHitShader(const char* code, const char* name); - std::unique_ptr CompileMissShader(const char* code, const char* name); - void CreatePipeline(); - void CreateDescriptorSet(); + void CreateRaytracePipeline(); + void CreateResolvePipeline(); + void CreateUniformBuffer(); + void CreateSceneVertexBuffer(); + void CreateSceneLightBuffer(); - void UploadTasks(const TraceTask* tasks, size_t size); - void BeginTracing(); - void RunTrace(const Uniforms& uniforms, const VkStridedDeviceAddressRegionKHR& rgenShader, int lightStart = 0, int lightEnd = 0); - void EndTracing(); - void DownloadTasks(const TraceTask* tasks, size_t size); - void SubmitCommands(); + void UploadUniforms(); + void CreateAtlasImages(); + void RenderAtlasImage(size_t pageIndex); + void ResolveAtlasImage(size_t pageIndex); + void DownloadAtlasImage(size_t pageIndex); + + LightmapImage CreateImage(int width, int height); + + void BeginCommands(); + void FinishCommands(); void PrintVulkanInfo(); - static float RadicalInverse_VdC(uint32_t bits); - static vec2 Hammersley(uint32_t i, uint32_t N); + std::vector CreateSurfaceInfo(); - int rayTraceImageSize = 1024; + static vec2 ToUV(const vec3& vert, const Surface* targetSurface); + static bool IsNegativelyOriented(const vec2& v1, const vec2& v2, const vec2& v3); LevelMesh* mesh = nullptr; @@ -101,12 +124,21 @@ private: std::unique_ptr device; + static const int SceneVertexBufferSize = 1 * 1024 * 1024; + std::unique_ptr sceneVertexBuffer; + SceneVertex* sceneVertices = nullptr; + int sceneVertexPos = 0; + + static const int SceneLightBufferSize = 2 * 1024 * 1024; + std::unique_ptr sceneLightBuffer; + LightInfo* sceneLights = nullptr; + int sceneLightPos = 0; + std::unique_ptr vertexBuffer; std::unique_ptr indexBuffer; std::unique_ptr transferBuffer; std::unique_ptr surfaceIndexBuffer; std::unique_ptr surfaceBuffer; - std::unique_ptr lightBuffer; std::unique_ptr blScratchBuffer; std::unique_ptr blAccelStructBuffer; @@ -118,32 +150,38 @@ private: std::unique_ptr tlAccelStructBuffer; std::unique_ptr tlAccelStruct; - std::unique_ptr rgenBounce, rgenLight, rgenAmbient; - std::unique_ptr rmissBounce, rmissLight, rmissSun, rmissAmbient; - std::unique_ptr rchitBounce, rchitLight, rchitSun, rchitAmbient; + std::unique_ptr vertShader; + std::unique_ptr fragShader; + std::unique_ptr fragResolveShader; - std::unique_ptr descriptorSetLayout; + struct + { + std::unique_ptr descriptorSetLayout; + std::unique_ptr pipelineLayout; + std::unique_ptr pipeline; + std::unique_ptr renderPass; + std::unique_ptr descriptorPool; + std::unique_ptr descriptorSet; + } raytrace; - std::unique_ptr pipelineLayout; - std::unique_ptr pipeline; - std::unique_ptr shaderBindingTable; - std::unique_ptr sbtTransferBuffer; - - VkStridedDeviceAddressRegionKHR rgenBounceRegion = {}, rgenLightRegion = {}, rgenAmbientRegion = {}; - VkStridedDeviceAddressRegionKHR missRegion = {}; - VkStridedDeviceAddressRegionKHR hitRegion = {}; - VkStridedDeviceAddressRegionKHR callRegion = {}; - - std::unique_ptr startPositionsImage, positionsImage, outputImage; - std::unique_ptr startPositionsImageView, positionsImageView, outputImageView; - std::unique_ptr imageTransferBuffer; + struct + { + std::unique_ptr descriptorSetLayout; + std::unique_ptr pipelineLayout; + std::unique_ptr pipeline; + std::unique_ptr renderPass; + std::unique_ptr descriptorPool; + std::vector> descriptorSets; + std::unique_ptr sampler; + } resolve; std::unique_ptr uniformBuffer; std::unique_ptr uniformTransferBuffer; - std::unique_ptr descriptorPool; - std::unique_ptr descriptorSet; - + std::unique_ptr submitFence; std::unique_ptr cmdpool; std::unique_ptr cmdbuffer; + + std::vector atlasImages; + static const int atlasImageSize = 2048; }; diff --git a/src/lightmap/gpuraytracer2.cpp b/src/lightmap/gpuraytracer2.cpp deleted file mode 100644 index 292dd28..0000000 --- a/src/lightmap/gpuraytracer2.cpp +++ /dev/null @@ -1,923 +0,0 @@ - -#include "math/mathlib.h" -#include "levelmesh.h" -#include "level/level.h" -#include "gpuraytracer2.h" -#include "framework/binfile.h" -#include "framework/templates.h" -#include "framework/halffloat.h" -#include "vulkanbuilders.h" -#include -#include -#include -#include -#include -#include -#include -#include "glsl_frag.h" -#include "glsl_frag_resolve.h" -#include "glsl_vert.h" - -extern bool VKDebug; - -GPURaytracer2::GPURaytracer2() -{ - device = std::make_unique(0, VKDebug); - PrintVulkanInfo(); -} - -GPURaytracer2::~GPURaytracer2() -{ -} - -void GPURaytracer2::Raytrace(LevelMesh* level) -{ - mesh = level; - - printf("Building Vulkan acceleration structures\n"); - - if (device->renderdoc) - device->renderdoc->StartFrameCapture(0, 0); - - CreateVulkanObjects(); - - printf("Ray tracing in progress...\n"); - - CreateAtlasImages(); - - BeginCommands(); - UploadUniforms(); - - for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++) - { - RenderAtlasImage(pageIndex); - } - - for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++) - { - ResolveAtlasImage(pageIndex); - } - -#ifdef WIN32 - LARGE_INTEGER s; - QueryPerformanceCounter(&s); -#endif - - FinishCommands(); - -#ifdef WIN32 - LARGE_INTEGER e, f; - QueryPerformanceCounter(&e); - QueryPerformanceFrequency(&f); - printf("GPU ray tracing time was %.3f seconds.\n", double(e.QuadPart - s.QuadPart) / double(f.QuadPart)); -#endif - - for (size_t pageIndex = 0; pageIndex < atlasImages.size(); pageIndex++) - { - DownloadAtlasImage(pageIndex); - } - - if (device->renderdoc) - device->renderdoc->EndFrameCapture(0, 0); - - printf("Ray trace complete\n"); -} - -void GPURaytracer2::RenderAtlasImage(size_t pageIndex) -{ - LightmapImage& img = atlasImages[pageIndex]; - - RenderPassBegin() - .RenderPass(raytrace.renderPass.get()) - .RenderArea(0, 0, atlasImageSize, atlasImageSize) - .Framebuffer(img.raytrace.Framebuffer.get()) - .Execute(cmdbuffer.get()); - - VkDeviceSize offset = 0; - cmdbuffer->bindVertexBuffers(0, 1, &sceneVertexBuffer->buffer, &offset); - cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipeline.get()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, raytrace.pipelineLayout.get(), 0, raytrace.descriptorSet.get()); - - for (size_t i = 0; i < mesh->surfaces.size(); i++) - { - Surface* targetSurface = mesh->surfaces[i].get(); - if (targetSurface->atlasPageIndex != pageIndex) - continue; - - VkViewport viewport = {}; - viewport.maxDepth = 1; - viewport.x = (float)targetSurface->atlasX - 1; - viewport.y = (float)targetSurface->atlasY - 1; - viewport.width = (float)(targetSurface->texWidth + 2); - viewport.height = (float)(targetSurface->texHeight + 2); - cmdbuffer->setViewport(0, 1, &viewport); - - // Paint all surfaces part of the smoothing group into the surface - for (const auto& surface : mesh->surfaces) - { - if (surface->smoothingGroupIndex != targetSurface->smoothingGroupIndex) - continue; - - vec2 minUV = ToUV(surface->bounds.min, targetSurface); - vec2 maxUV = ToUV(surface->bounds.max, targetSurface); - if (surface.get() != targetSurface && (maxUV.x < 0.0f || maxUV.y < 0.0f || minUV.x > 1.0f || minUV.y > 1.0f)) - continue; // Bounding box not visible - - int firstLight = sceneLightPos; - int lightCount = (int)surface->LightList.size(); - if (sceneLightPos + lightCount > SceneLightBufferSize) - throw std::runtime_error("SceneLightBuffer is too small!"); - sceneLightPos += lightCount; - - LightInfo2* lightinfo = &sceneLights[firstLight]; - for (ThingLight* light : surface->LightList) - { - lightinfo->Origin = light->LightOrigin(); - lightinfo->Radius = light->LightRadius(); - lightinfo->Intensity = light->intensity; - lightinfo->InnerAngleCos = light->innerAngleCos; - lightinfo->OuterAngleCos = light->outerAngleCos; - lightinfo->SpotDir = light->SpotDir(); - lightinfo->Color = light->rgb; - lightinfo++; - } - - PushConstants2 pc; - pc.LightStart = firstLight; - pc.LightEnd = firstLight + lightCount; - pc.SurfaceIndex = (int32_t)i; - pc.LightmapOrigin = targetSurface->worldOrigin - targetSurface->worldStepX - targetSurface->worldStepY; - pc.LightmapStepX = targetSurface->worldStepX * viewport.width; - pc.LightmapStepY = targetSurface->worldStepY * viewport.height; - cmdbuffer->pushConstants(raytrace.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants2), &pc); - - int firstVertex = sceneVertexPos; - int vertexCount = (int)surface->verts.size(); - if (sceneVertexPos + vertexCount > SceneVertexBufferSize) - throw std::runtime_error("SceneVertexBuffer is too small!"); - sceneVertexPos += vertexCount; - SceneVertex* vertex = &sceneVertices[firstVertex]; - - if (surface->type == ST_FLOOR || surface->type == ST_CEILING) - { - for (int idx = 0; idx < vertexCount; idx++) - { - (vertex++)->Position = ToUV(surface->verts[idx], targetSurface); - } - } - else - { - (vertex++)->Position = ToUV(surface->verts[0], targetSurface); - (vertex++)->Position = ToUV(surface->verts[2], targetSurface); - (vertex++)->Position = ToUV(surface->verts[3], targetSurface); - (vertex++)->Position = ToUV(surface->verts[1], targetSurface); - } - - cmdbuffer->draw(vertexCount, 1, firstVertex, 0); - } - } - - cmdbuffer->endRenderPass(); -} - -void GPURaytracer2::CreateAtlasImages() -{ - const int spacing = 3; // Note: the spacing is here to avoid that the resolve sampler finds data from other surface tiles - RectPacker packer(atlasImageSize, atlasImageSize, RectPacker::Spacing(spacing)); - - for (size_t i = 0; i < mesh->surfaces.size(); i++) - { - Surface* surface = mesh->surfaces[i].get(); - - auto result = packer.insert(surface->texWidth + 2, surface->texHeight + 2); - surface->atlasX = result.pos.x + 1; - surface->atlasY = result.pos.y + 1; - surface->atlasPageIndex = (int)result.pageIndex; - } - - for (size_t pageIndex = 0; pageIndex < packer.getNumPages(); pageIndex++) - { - atlasImages.push_back(CreateImage(atlasImageSize, atlasImageSize)); - } -} - -void GPURaytracer2::UploadUniforms() -{ - Uniforms2 uniforms = {}; - uniforms.SunDir = mesh->map->GetSunDirection(); - uniforms.SunColor = mesh->map->GetSunColor(); - uniforms.SunIntensity = 1.0f; - - mappedUniforms = (uint8_t*)uniformTransferBuffer->Map(0, uniformStructs * uniformStructStride); - *reinterpret_cast(mappedUniforms + uniformStructStride * uniformsIndex) = uniforms; - uniformTransferBuffer->Unmap(); - - cmdbuffer->copyBuffer(uniformTransferBuffer.get(), uniformBuffer.get()); - PipelineBarrier() - .AddBuffer(uniformBuffer.get(), VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); -} - -void GPURaytracer2::ResolveAtlasImage(size_t i) -{ - LightmapImage& img = atlasImages[i]; - - PipelineBarrier() - .AddImage(img.raytrace.Image.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); - - RenderPassBegin() - .RenderPass(resolve.renderPass.get()) - .RenderArea(0, 0, atlasImageSize, atlasImageSize) - .Framebuffer(img.resolve.Framebuffer.get()) - .Execute(cmdbuffer.get()); - - VkDeviceSize offset = 0; - cmdbuffer->bindVertexBuffers(0, 1, &sceneVertexBuffer->buffer, &offset); - cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipeline.get()); - - auto descriptorSet = resolve.descriptorPool->allocate(resolve.descriptorSetLayout.get()); - descriptorSet->SetDebugName("resolve.descriptorSet"); - WriteDescriptors() - .AddCombinedImageSampler(descriptorSet.get(), 0, img.raytrace.View.get(), resolve.sampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - .Execute(device.get()); - cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, resolve.pipelineLayout.get(), 0, descriptorSet.get()); - resolve.descriptorSets.push_back(std::move(descriptorSet)); - - VkViewport viewport = {}; - viewport.maxDepth = 1; - viewport.width = (float)atlasImageSize; - viewport.height = (float)atlasImageSize; - cmdbuffer->setViewport(0, 1, &viewport); - - PushConstants2 pc; - pc.LightStart = 0; - pc.LightEnd = 0; - pc.SurfaceIndex = 0; - pc.LightmapOrigin = vec3(0.0f); - pc.LightmapStepX = vec3(0.0f); - pc.LightmapStepY = vec3(0.0f); - cmdbuffer->pushConstants(resolve.pipelineLayout.get(), VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstants2), &pc); - - int firstVertex = sceneVertexPos; - int vertexCount = 4; - sceneVertexPos += vertexCount; - SceneVertex* vertex = &sceneVertices[firstVertex]; - vertex[0].Position = vec2(0.0f, 0.0f); - vertex[1].Position = vec2(1.0f, 0.0f); - vertex[2].Position = vec2(1.0f, 1.0f); - vertex[3].Position = vec2(0.0f, 1.0f); - cmdbuffer->draw(vertexCount, 1, firstVertex, 0); - - cmdbuffer->endRenderPass(); - - PipelineBarrier() - .AddImage(img.resolve.Image.get(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); - - VkBufferImageCopy region = {}; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.layerCount = 1; - region.imageExtent.width = atlasImageSize; - region.imageExtent.height = atlasImageSize; - region.imageExtent.depth = 1; - cmdbuffer->copyImageToBuffer(img.resolve.Image->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, img.Transfer->buffer, 1, ®ion); -} - -void GPURaytracer2::DownloadAtlasImage(size_t pageIndex) -{ - struct hvec4 - { - unsigned short x, y, z, w; - vec3 xyz() { return vec3(halfToFloat(x), halfToFloat(y), halfToFloat(z)); } - }; - - hvec4* pixels = (hvec4*)atlasImages[pageIndex].Transfer->Map(0, atlasImageSize * atlasImageSize * sizeof(hvec4)); - - for (size_t i = 0; i < mesh->surfaces.size(); i++) - { - Surface* surface = mesh->surfaces[i].get(); - if (surface->atlasPageIndex != pageIndex) - continue; - - int atlasX = surface->atlasX; - int atlasY = surface->atlasY; - int sampleWidth = surface->texWidth; - int sampleHeight = surface->texHeight; - - for (int y = 0; y < sampleHeight; y++) - { - vec3* dest = &surface->texPixels[y * sampleWidth]; - hvec4* src = &pixels[atlasX + (atlasY + y) * atlasImageSize]; - for (int x = 0; x < sampleWidth; x++) - { - dest[x] = src[x].xyz(); - } - } - } - atlasImages[pageIndex].Transfer->Unmap(); -} - -vec2 GPURaytracer2::ToUV(const vec3& vert, const Surface* targetSurface) -{ - vec3 localPos = vert - targetSurface->translateWorldToLocal; - float u = (1.0f + dot(localPos, targetSurface->projLocalToU)) / (targetSurface->texWidth + 2); - float v = (1.0f + dot(localPos, targetSurface->projLocalToV)) / (targetSurface->texHeight + 2); - return vec2(u, v); -} - -void GPURaytracer2::CreateVulkanObjects() -{ - submitFence = std::make_unique(device.get()); - cmdpool = std::make_unique(device.get(), device->graphicsFamily); - - BeginCommands(); - - CreateSceneVertexBuffer(); - CreateSceneLightBuffer(); - CreateVertexAndIndexBuffers(); - CreateUniformBuffer(); - CreateBottomLevelAccelerationStructure(); - CreateTopLevelAccelerationStructure(); - CreateShaders(); - CreateRaytracePipeline(); - CreateResolvePipeline(); - - FinishCommands(); -} - -void GPURaytracer2::CreateSceneVertexBuffer() -{ - size_t size = sizeof(SceneVertex) * SceneVertexBufferSize; - - sceneVertexBuffer = BufferBuilder() - .Usage( - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT) - .MemoryType( - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) - .Size(size) - .DebugName("SceneVertexBuffer") - .Create(device.get()); - - sceneVertices = (SceneVertex*)sceneVertexBuffer->Map(0, size); - sceneVertexPos = 0; -} - -void GPURaytracer2::CreateSceneLightBuffer() -{ - size_t size = sizeof(LightInfo2) * SceneLightBufferSize; - - sceneLightBuffer = BufferBuilder() - .Usage( - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, - VMA_MEMORY_USAGE_UNKNOWN, VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT) - .MemoryType( - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) - .Size(size) - .DebugName("SceneLightBuffer") - .Create(device.get()); - - sceneLights = (LightInfo2*)sceneLightBuffer->Map(0, size); - sceneLightPos = 0; -} - -void GPURaytracer2::BeginCommands() -{ - cmdbuffer = cmdpool->createBuffer(); - cmdbuffer->begin(); -} - -void GPURaytracer2::FinishCommands() -{ - cmdbuffer->end(); - - QueueSubmit() - .AddCommandBuffer(cmdbuffer.get()) - .Execute(device.get(), device->graphicsQueue, submitFence.get()); - - VkResult result = vkWaitForFences(device->device, 1, &submitFence->fence, VK_TRUE, std::numeric_limits::max()); - if (result != VK_SUCCESS) - throw std::runtime_error("vkWaitForFences failed"); - result = vkResetFences(device->device, 1, &submitFence->fence); - if (result != VK_SUCCESS) - throw std::runtime_error("vkResetFences failed"); - cmdbuffer.reset(); -} - -void GPURaytracer2::CreateVertexAndIndexBuffers() -{ - std::vector surfaces = CreateSurfaceInfo(); - - if (surfaces.empty()) // vulkan doesn't support zero byte buffers - surfaces.push_back(SurfaceInfo2()); - - size_t vertexbuffersize = (size_t)mesh->MeshVertices.Size() * sizeof(vec3); - size_t indexbuffersize = (size_t)mesh->MeshElements.Size() * sizeof(uint32_t); - size_t surfaceindexbuffersize = (size_t)mesh->MeshSurfaces.Size() * sizeof(uint32_t); - size_t surfacebuffersize = (size_t)surfaces.size() * sizeof(SurfaceInfo2); - size_t transferbuffersize = vertexbuffersize + indexbuffersize + surfaceindexbuffersize + surfacebuffersize; - size_t vertexoffset = 0; - size_t indexoffset = vertexoffset + vertexbuffersize; - size_t surfaceindexoffset = indexoffset + indexbuffersize; - size_t surfaceoffset = surfaceindexoffset + surfaceindexbuffersize; - size_t lightoffset = surfaceoffset + surfacebuffersize; - - vertexBuffer = BufferBuilder() - .Usage( - VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT | - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | - VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) - .Size(vertexbuffersize) - .DebugName("vertexBuffer") - .Create(device.get()); - - indexBuffer = BufferBuilder() - .Usage( - VK_BUFFER_USAGE_INDEX_BUFFER_BIT | - VK_BUFFER_USAGE_TRANSFER_DST_BIT | - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | - VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) - .Size(indexbuffersize) - .DebugName("indexBuffer") - .Create(device.get()); - - surfaceIndexBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(surfaceindexbuffersize) - .DebugName("surfaceIndexBuffer") - .Create(device.get()); - - surfaceBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(surfacebuffersize) - .DebugName("surfaceBuffer") - .Create(device.get()); - - transferBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) - .Size(transferbuffersize) - .DebugName("transferBuffer") - .Create(device.get()); - - uint8_t* data = (uint8_t*)transferBuffer->Map(0, transferbuffersize); - memcpy(data + vertexoffset, mesh->MeshVertices.Data(), vertexbuffersize); - memcpy(data + indexoffset, mesh->MeshElements.Data(), indexbuffersize); - memcpy(data + surfaceindexoffset, mesh->MeshSurfaces.Data(), surfaceindexbuffersize); - memcpy(data + surfaceoffset, surfaces.data(), surfacebuffersize); - transferBuffer->Unmap(); - - cmdbuffer->copyBuffer(transferBuffer.get(), vertexBuffer.get(), vertexoffset); - cmdbuffer->copyBuffer(transferBuffer.get(), indexBuffer.get(), indexoffset); - cmdbuffer->copyBuffer(transferBuffer.get(), surfaceIndexBuffer.get(), surfaceindexoffset); - cmdbuffer->copyBuffer(transferBuffer.get(), surfaceBuffer.get(), surfaceoffset); - - PipelineBarrier() - .AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); -} - -void GPURaytracer2::CreateBottomLevelAccelerationStructure() -{ - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR }; - VkAccelerationStructureGeometryKHR accelStructBLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR }; - VkAccelerationStructureGeometryKHR* geometries[] = { &accelStructBLDesc }; - VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {}; - VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo }; - - accelStructBLDesc.geometryType = VK_GEOMETRY_TYPE_TRIANGLES_KHR; - accelStructBLDesc.flags = VK_GEOMETRY_OPAQUE_BIT_KHR; - accelStructBLDesc.geometry.triangles = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR }; - accelStructBLDesc.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32_SFLOAT; - accelStructBLDesc.geometry.triangles.vertexData.deviceAddress = vertexBuffer->GetDeviceAddress(); - accelStructBLDesc.geometry.triangles.vertexStride = sizeof(vec3); - accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32; - accelStructBLDesc.geometry.triangles.indexData.deviceAddress = indexBuffer->GetDeviceAddress(); - accelStructBLDesc.geometry.triangles.maxVertex = mesh->MeshVertices.Size() - 1; - - buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR; - buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - buildInfo.geometryCount = 1; - buildInfo.pGeometries = &accelStructBLDesc; - - uint32_t maxPrimitiveCount = mesh->MeshElements.Size() / 3; - - VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR }; - vkGetAccelerationStructureBuildSizesKHR(device->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxPrimitiveCount, &sizeInfo); - - blAccelStructBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) - .Size(sizeInfo.accelerationStructureSize) - .DebugName("blAccelStructBuffer") - .Create(device.get()); - - blAccelStruct = AccelerationStructureBuilder() - .Type(VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_KHR) - .Buffer(blAccelStructBuffer.get(), sizeInfo.accelerationStructureSize) - .Create(device.get()); - - blScratchBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) - .Size(sizeInfo.buildScratchSize) - .DebugName("blScratchBuffer") - .Create(device.get()); - - buildInfo.dstAccelerationStructure = blAccelStruct->accelstruct; - buildInfo.scratchData.deviceAddress = blScratchBuffer->GetDeviceAddress(); - rangeInfo.primitiveCount = maxPrimitiveCount; - - cmdbuffer->buildAccelerationStructures(1, &buildInfo, rangeInfos); - - // Finish building before using it as input to a toplevel accel structure - PipelineBarrier() - .AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); -} - -void GPURaytracer2::CreateTopLevelAccelerationStructure() -{ - VkAccelerationStructureInstanceKHR instance = {}; - instance.transform.matrix[0][0] = 1.0f; - instance.transform.matrix[1][1] = 1.0f; - instance.transform.matrix[2][2] = 1.0f; - instance.mask = 0xff; - instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR; - instance.accelerationStructureReference = blAccelStruct->GetDeviceAddress(); - - tlTransferBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY) - .Size(sizeof(VkAccelerationStructureInstanceKHR)) - .DebugName("tlTransferBuffer") - .Create(device.get()); - - auto data = (uint8_t*)tlTransferBuffer->Map(0, sizeof(VkAccelerationStructureInstanceKHR)); - memcpy(data, &instance, sizeof(VkAccelerationStructureInstanceKHR)); - tlTransferBuffer->Unmap(); - - tlInstanceBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(sizeof(VkAccelerationStructureInstanceKHR)) - .DebugName("tlInstanceBuffer") - .Create(device.get()); - - cmdbuffer->copyBuffer(tlTransferBuffer.get(), tlInstanceBuffer.get()); - - PipelineBarrier() - .AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR); - - VkAccelerationStructureGeometryKHR accelStructTLDesc = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_KHR }; - VkAccelerationStructureBuildGeometryInfoKHR buildInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_GEOMETRY_INFO_KHR }; - VkAccelerationStructureBuildRangeInfoKHR rangeInfo = {}; - VkAccelerationStructureBuildRangeInfoKHR* rangeInfos[] = { &rangeInfo }; - - accelStructTLDesc.geometryType = VK_GEOMETRY_TYPE_INSTANCES_KHR; - accelStructTLDesc.geometry.instances = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_INSTANCES_DATA_KHR }; - accelStructTLDesc.geometry.instances.data.deviceAddress = tlInstanceBuffer->GetDeviceAddress(); - - buildInfo.type = VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR; - buildInfo.mode = VK_BUILD_ACCELERATION_STRUCTURE_MODE_BUILD_KHR; - buildInfo.flags = VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_KHR; - buildInfo.geometryCount = 1; - buildInfo.pGeometries = &accelStructTLDesc; - - uint32_t maxInstanceCount = 1; - - VkAccelerationStructureBuildSizesInfoKHR sizeInfo = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_BUILD_SIZES_INFO_KHR }; - vkGetAccelerationStructureBuildSizesKHR(device->device, VK_ACCELERATION_STRUCTURE_BUILD_TYPE_DEVICE_KHR, &buildInfo, &maxInstanceCount, &sizeInfo); - - tlAccelStructBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_STORAGE_BIT_KHR | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) - .Size(sizeInfo.accelerationStructureSize) - .DebugName("tlAccelStructBuffer") - .Create(device.get()); - - tlAccelStruct = AccelerationStructureBuilder() - .Type(VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_KHR) - .Buffer(tlAccelStructBuffer.get(), sizeInfo.accelerationStructureSize) - .DebugName("tlAccelStruct") - .Create(device.get()); - - tlScratchBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) - .Size(sizeInfo.buildScratchSize) - .DebugName("tlScratchBuffer") - .Create(device.get()); - - buildInfo.dstAccelerationStructure = tlAccelStruct->accelstruct; - buildInfo.scratchData.deviceAddress = tlScratchBuffer->GetDeviceAddress(); - rangeInfo.primitiveCount = maxInstanceCount; - - cmdbuffer->buildAccelerationStructures(1, &buildInfo, rangeInfos); - - PipelineBarrier() - .AddMemory(VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_KHR, VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR) - .Execute(cmdbuffer.get(), VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT); -} - -void GPURaytracer2::CreateShaders() -{ - vertShader = ShaderBuilder() - .VertexShader(glsl_vert) - .DebugName("vertShader") - .Create("vertShader", device.get()); - - fragShader = ShaderBuilder() - .FragmentShader(glsl_frag) - .DebugName("fragShader") - .Create("fragShader", device.get()); - - fragResolveShader = ShaderBuilder() - .FragmentShader(glsl_frag_resolve) - .DebugName("fragResolveShader") - .Create("fragResolveShader", device.get()); -} - -void GPURaytracer2::CreateRaytracePipeline() -{ - raytrace.descriptorSetLayout = DescriptorSetLayoutBuilder() - .AddBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT) - .AddBinding(1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT) - .AddBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) - .AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) - .AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) - .DebugName("raytrace.descriptorSetLayout") - .Create(device.get()); - - raytrace.pipelineLayout = PipelineLayoutBuilder() - .AddSetLayout(raytrace.descriptorSetLayout.get()) - .AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants2)) - .DebugName("raytrace.pipelineLayout") - .Create(device.get()); - - raytrace.renderPass = RenderPassBuilder() - .AddAttachment( - VK_FORMAT_R16G16B16A16_SFLOAT, - VK_SAMPLE_COUNT_4_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_STORE, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) - .AddSubpass() - .AddSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) - .AddExternalSubpassDependency( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) - .DebugName("raytrace.renderpass") - .Create(device.get()); - - raytrace.pipeline = GraphicsPipelineBuilder() - .Layout(raytrace.pipelineLayout.get()) - .RenderPass(raytrace.renderPass.get()) - .AddVertexShader(vertShader.get()) - .AddFragmentShader(fragShader.get()) - .AddVertexBufferBinding(0, sizeof(SceneVertex)) - .AddVertexAttribute(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(SceneVertex, Position)) - .Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) - .AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT) - .RasterizationSamples(VK_SAMPLE_COUNT_4_BIT) - .Viewport(0.0f, 0.0f, 0.0f, 0.0f) - .Scissor(0, 0, 4096, 4096) - .DebugName("raytrace.pipeline") - .Create(device.get()); - - raytrace.descriptorPool = DescriptorPoolBuilder() - .AddPoolSize(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1) - .AddPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1) - .AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3) - .MaxSets(1) - .DebugName("raytrace.descriptorPool") - .Create(device.get()); - - raytrace.descriptorSet = raytrace.descriptorPool->allocate(raytrace.descriptorSetLayout.get()); - raytrace.descriptorSet->SetDebugName("raytrace.descriptorSet"); - - WriteDescriptors() - .AddAccelerationStructure(raytrace.descriptorSet.get(), 0, tlAccelStruct.get()) - .AddBuffer(raytrace.descriptorSet.get(), 1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uniformBuffer.get(), 0, sizeof(Uniforms2)) - .AddBuffer(raytrace.descriptorSet.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceIndexBuffer.get()) - .AddBuffer(raytrace.descriptorSet.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceBuffer.get()) - .AddBuffer(raytrace.descriptorSet.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, sceneLightBuffer.get()) - .Execute(device.get()); -} - -void GPURaytracer2::CreateResolvePipeline() -{ - resolve.descriptorSetLayout = DescriptorSetLayoutBuilder() - .AddBinding(0, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT) - .DebugName("resolve.descriptorSetLayout") - .Create(device.get()); - - resolve.pipelineLayout = PipelineLayoutBuilder() - .AddSetLayout(resolve.descriptorSetLayout.get()) - .AddPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(PushConstants2)) - .DebugName("resolve.pipelineLayout") - .Create(device.get()); - - resolve.renderPass = RenderPassBuilder() - .AddAttachment( - VK_FORMAT_R16G16B16A16_SFLOAT, - VK_SAMPLE_COUNT_1_BIT, - VK_ATTACHMENT_LOAD_OP_DONT_CARE, - VK_ATTACHMENT_STORE_OP_STORE, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) - .AddSubpass() - .AddSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) - .AddExternalSubpassDependency( - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - VK_ACCESS_COLOR_ATTACHMENT_READ_BIT) - .DebugName("resolve.renderpass") - .Create(device.get()); - - resolve.pipeline = GraphicsPipelineBuilder() - .Layout(resolve.pipelineLayout.get()) - .RenderPass(resolve.renderPass.get()) - .AddVertexShader(vertShader.get()) - .AddFragmentShader(fragResolveShader.get()) - .AddVertexBufferBinding(0, sizeof(SceneVertex)) - .AddVertexAttribute(0, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(SceneVertex, Position)) - .Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN) - .AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT) - .Viewport(0.0f, 0.0f, 0.0f, 0.0f) - .Scissor(0, 0, 4096, 4096) - .DebugName("resolve.pipeline") - .Create(device.get()); - - resolve.descriptorPool = DescriptorPoolBuilder() - .AddPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 256) - .MaxSets(256) - .DebugName("resolve.descriptorPool") - .Create(device.get()); - - resolve.sampler = SamplerBuilder() - .DebugName("resolve.Sampler") - .Create(device.get()); -} - -LightmapImage GPURaytracer2::CreateImage(int width, int height) -{ - LightmapImage img; - - img.raytrace.Image = ImageBuilder() - .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT) - .Format(VK_FORMAT_R16G16B16A16_SFLOAT) - .Size(width, height) - .Samples(VK_SAMPLE_COUNT_4_BIT) - .DebugName("LightmapImage.raytrace.Image") - .Create(device.get()); - - img.raytrace.View = ImageViewBuilder() - .Image(img.raytrace.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) - .DebugName("LightmapImage.raytrace.View") - .Create(device.get()); - - img.raytrace.Framebuffer = FramebufferBuilder() - .RenderPass(raytrace.renderPass.get()) - .Size(width, height) - .AddAttachment(img.raytrace.View.get()) - .DebugName("LightmapImage.raytrace.Framebuffer") - .Create(device.get()); - - img.resolve.Image = ImageBuilder() - .Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT) - .Format(VK_FORMAT_R16G16B16A16_SFLOAT) - .Size(width, height) - .DebugName("LightmapImage.resolve.Image") - .Create(device.get()); - - img.resolve.View = ImageViewBuilder() - .Image(img.resolve.Image.get(), VK_FORMAT_R16G16B16A16_SFLOAT) - .DebugName("LightmapImage.resolve.View") - .Create(device.get()); - - img.resolve.Framebuffer = FramebufferBuilder() - .RenderPass(resolve.renderPass.get()) - .Size(width, height) - .AddAttachment(img.resolve.View.get()) - .DebugName("LightmapImage.resolve.Framebuffer") - .Create(device.get()); - - img.Transfer = BufferBuilder() - .Size(width * height * sizeof(vec4)) - .Usage(VK_IMAGE_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_CPU_ONLY) - .DebugName("LightmapImage.Transfer") - .Create(device.get()); - - return img; -} - -void GPURaytracer2::CreateUniformBuffer() -{ - VkDeviceSize align = device->physicalDevice.properties.limits.minUniformBufferOffsetAlignment; - uniformStructStride = (sizeof(Uniforms2) + align - 1) / align * align; - - uniformBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT) - .Size(uniformStructs * uniformStructStride) - .DebugName("uniformBuffer") - .Create(device.get()); - - uniformTransferBuffer = BufferBuilder() - .Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU) - .Size(uniformStructs * uniformStructStride) - .DebugName("uniformTransferBuffer") - .Create(device.get()); -} - -std::vector GPURaytracer2::CreateSurfaceInfo() -{ - std::vector surfaces; - surfaces.reserve(mesh->surfaces.size()); - for (const auto& surface : mesh->surfaces) - { - SurfaceLightDef* def = nullptr; - if (surface->type >= ST_MIDDLESIDE && surface->type <= ST_LOWERSIDE) - { - int lightdefidx = mesh->map->Sides[surface->typeIndex].lightdef; - if (lightdefidx != -1) - { - def = &mesh->map->SurfaceLights[lightdefidx]; - } - } - else if (surface->type == ST_FLOOR || surface->type == ST_CEILING) - { - MapSubsectorEx* sub = &mesh->map->GLSubsectors[surface->typeIndex]; - IntSector* sector = mesh->map->GetSectorFromSubSector(sub); - - if (sector && surface->verts.size() > 0) - { - if (sector->floorlightdef != -1 && surface->type == ST_FLOOR) - { - def = &mesh->map->SurfaceLights[sector->floorlightdef]; - } - else if (sector->ceilinglightdef != -1 && surface->type == ST_CEILING) - { - def = &mesh->map->SurfaceLights[sector->ceilinglightdef]; - } - } - } - - SurfaceInfo2 info; - info.Sky = surface->bSky ? 1.0f : 0.0f; - info.Normal = surface->plane.Normal(); - if (def) - { - info.EmissiveDistance = def->distance + def->distance; - info.EmissiveIntensity = def->intensity; - info.EmissiveColor = def->rgb; - } - else - { - info.EmissiveDistance = 0.0f; - info.EmissiveIntensity = 0.0f; - info.EmissiveColor = vec3(0.0f, 0.0f, 0.0f); - } - - info.SamplingDistance = float(surface->sampleDimension); - surfaces.push_back(info); - } - return surfaces; -} - -void GPURaytracer2::PrintVulkanInfo() -{ - const auto& props = device->physicalDevice.properties; - - std::string deviceType; - switch (props.deviceType) - { - case VK_PHYSICAL_DEVICE_TYPE_OTHER: deviceType = "other"; break; - case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: deviceType = "integrated gpu"; break; - case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: deviceType = "discrete gpu"; break; - case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: deviceType = "virtual gpu"; break; - case VK_PHYSICAL_DEVICE_TYPE_CPU: deviceType = "cpu"; break; - default: deviceType = std::to_string(props.deviceType); break; - } - - std::string apiVersion = std::to_string(VK_VERSION_MAJOR(props.apiVersion)) + "." + std::to_string(VK_VERSION_MINOR(props.apiVersion)) + "." + std::to_string(VK_VERSION_PATCH(props.apiVersion)); - std::string driverVersion = std::to_string(VK_VERSION_MAJOR(props.driverVersion)) + "." + std::to_string(VK_VERSION_MINOR(props.driverVersion)) + "." + std::to_string(VK_VERSION_PATCH(props.driverVersion)); - - printf("Vulkan device: %s\n", props.deviceName); - printf("Vulkan device type: %s\n", deviceType.c_str()); - printf("Vulkan version: %s (api) %s (driver)\n", apiVersion.c_str(), driverVersion.c_str()); -} - -bool GPURaytracer2::IsNegativelyOriented(const vec2& v1, const vec2& v2, const vec2& v3) -{ - float A = - v1.x * v2.y - v2.x * v1.y + - v2.x * v3.y - v3.x * v2.y + - v3.x * v1.y - v1.x * v3.y; - return A < 0.0f; -} diff --git a/src/lightmap/gpuraytracer2.h b/src/lightmap/gpuraytracer2.h deleted file mode 100644 index 40e35a9..0000000 --- a/src/lightmap/gpuraytracer2.h +++ /dev/null @@ -1,187 +0,0 @@ - -#pragma once - -#include "vulkandevice.h" -#include "vulkanobjects.h" - -class LevelMesh; - -struct Uniforms2 -{ - vec3 SunDir; - float Padding1; - vec3 SunColor; - float SunIntensity; -}; - -struct PushConstants2 -{ - uint32_t LightStart; - uint32_t LightEnd; - int32_t SurfaceIndex; - int32_t PushPadding1; - vec3 LightmapOrigin; - float PushPadding2; - vec3 LightmapStepX; - float PushPadding3; - vec3 LightmapStepY; - float PushPadding4; -}; - -struct SurfaceInfo2 -{ - vec3 Normal; - float EmissiveDistance; - vec3 EmissiveColor; - float EmissiveIntensity; - float Sky; - float SamplingDistance; - float Padding1, Padding2; -}; - -struct LightInfo2 -{ - vec3 Origin; - float Padding0; - float Radius; - float Intensity; - float InnerAngleCos; - float OuterAngleCos; - vec3 SpotDir; - float Padding1; - vec3 Color; - float Padding2; -}; - -struct LightmapImage -{ - struct - { - std::unique_ptr Image; - std::unique_ptr View; - std::unique_ptr Framebuffer; - } raytrace; - - struct - { - std::unique_ptr Image; - std::unique_ptr View; - std::unique_ptr Framebuffer; - } resolve; - - std::unique_ptr Transfer; -}; - -struct SceneVertex -{ - vec2 Position; -}; - -class GPURaytracer2 -{ -public: - GPURaytracer2(); - ~GPURaytracer2(); - - void Raytrace(LevelMesh* level); - -private: - void CreateVulkanObjects(); - void CreateVertexAndIndexBuffers(); - void CreateBottomLevelAccelerationStructure(); - void CreateTopLevelAccelerationStructure(); - void CreateShaders(); - void CreateRaytracePipeline(); - void CreateResolvePipeline(); - void CreateUniformBuffer(); - void CreateSceneVertexBuffer(); - void CreateSceneLightBuffer(); - - void UploadUniforms(); - void CreateAtlasImages(); - void RenderAtlasImage(size_t pageIndex); - void ResolveAtlasImage(size_t pageIndex); - void DownloadAtlasImage(size_t pageIndex); - - LightmapImage CreateImage(int width, int height); - - void BeginCommands(); - void FinishCommands(); - - void PrintVulkanInfo(); - - std::vector CreateSurfaceInfo(); - - static vec2 ToUV(const vec3& vert, const Surface* targetSurface); - static bool IsNegativelyOriented(const vec2& v1, const vec2& v2, const vec2& v3); - - LevelMesh* mesh = nullptr; - - uint8_t* mappedUniforms = nullptr; - int uniformsIndex = 0; - int uniformStructs = 256; - VkDeviceSize uniformStructStride = sizeof(Uniforms2); - - std::unique_ptr device; - - static const int SceneVertexBufferSize = 1 * 1024 * 1024; - std::unique_ptr sceneVertexBuffer; - SceneVertex* sceneVertices = nullptr; - int sceneVertexPos = 0; - - static const int SceneLightBufferSize = 2 * 1024 * 1024; - std::unique_ptr sceneLightBuffer; - LightInfo2* sceneLights = nullptr; - int sceneLightPos = 0; - - std::unique_ptr vertexBuffer; - std::unique_ptr indexBuffer; - std::unique_ptr transferBuffer; - std::unique_ptr surfaceIndexBuffer; - std::unique_ptr surfaceBuffer; - - std::unique_ptr blScratchBuffer; - std::unique_ptr blAccelStructBuffer; - std::unique_ptr blAccelStruct; - - std::unique_ptr tlTransferBuffer; - std::unique_ptr tlScratchBuffer; - std::unique_ptr tlInstanceBuffer; - std::unique_ptr tlAccelStructBuffer; - std::unique_ptr tlAccelStruct; - - std::unique_ptr vertShader; - std::unique_ptr fragShader; - std::unique_ptr fragResolveShader; - - struct - { - std::unique_ptr descriptorSetLayout; - std::unique_ptr pipelineLayout; - std::unique_ptr pipeline; - std::unique_ptr renderPass; - std::unique_ptr descriptorPool; - std::unique_ptr descriptorSet; - } raytrace; - - struct - { - std::unique_ptr descriptorSetLayout; - std::unique_ptr pipelineLayout; - std::unique_ptr pipeline; - std::unique_ptr renderPass; - std::unique_ptr descriptorPool; - std::vector> descriptorSets; - std::unique_ptr sampler; - } resolve; - - std::unique_ptr uniformBuffer; - std::unique_ptr uniformTransferBuffer; - - std::unique_ptr submitFence; - std::unique_ptr cmdpool; - std::unique_ptr cmdbuffer; - - std::vector atlasImages; - static const int atlasImageSize = 2048; -};