Remove the old GPU raytracer

This commit is contained in:
Magnus Norddahl 2022-08-31 06:22:02 +02:00
parent 59c58b75f1
commit 8ed96484c2
16 changed files with 817 additions and 2683 deletions

View file

@ -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

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

View file

@ -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";

File diff suppressed because it is too large Load diff

View file

@ -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<VulkanImage> Image;
std::unique_ptr<VulkanImageView> View;
std::unique_ptr<VulkanFramebuffer> Framebuffer;
} raytrace;
struct
{
std::unique_ptr<VulkanImage> Image;
std::unique_ptr<VulkanImageView> View;
std::unique_ptr<VulkanFramebuffer> Framebuffer;
} resolve;
std::unique_ptr<VulkanBuffer> Transfer;
};
struct SceneVertex
{
vec2 Position;
};
class GPURaytracer
@ -66,31 +86,34 @@ public:
void Raytrace(LevelMesh* level);
private:
void CreateTasks(std::vector<TraceTask>& tasks);
void CreateVulkanObjects();
void CreateVertexAndIndexBuffers();
void CreateBottomLevelAccelerationStructure();
void CreateTopLevelAccelerationStructure();
void CreateShaders();
std::unique_ptr<VulkanShader> CompileRayGenShader(const char* code, const char* name);
std::unique_ptr<VulkanShader> CompileClosestHitShader(const char* code, const char* name);
std::unique_ptr<VulkanShader> 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<SurfaceInfo> 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<VulkanDevice> device;
static const int SceneVertexBufferSize = 1 * 1024 * 1024;
std::unique_ptr<VulkanBuffer> sceneVertexBuffer;
SceneVertex* sceneVertices = nullptr;
int sceneVertexPos = 0;
static const int SceneLightBufferSize = 2 * 1024 * 1024;
std::unique_ptr<VulkanBuffer> sceneLightBuffer;
LightInfo* sceneLights = nullptr;
int sceneLightPos = 0;
std::unique_ptr<VulkanBuffer> vertexBuffer;
std::unique_ptr<VulkanBuffer> indexBuffer;
std::unique_ptr<VulkanBuffer> transferBuffer;
std::unique_ptr<VulkanBuffer> surfaceIndexBuffer;
std::unique_ptr<VulkanBuffer> surfaceBuffer;
std::unique_ptr<VulkanBuffer> lightBuffer;
std::unique_ptr<VulkanBuffer> blScratchBuffer;
std::unique_ptr<VulkanBuffer> blAccelStructBuffer;
@ -118,32 +150,38 @@ private:
std::unique_ptr<VulkanBuffer> tlAccelStructBuffer;
std::unique_ptr<VulkanAccelerationStructure> tlAccelStruct;
std::unique_ptr<VulkanShader> rgenBounce, rgenLight, rgenAmbient;
std::unique_ptr<VulkanShader> rmissBounce, rmissLight, rmissSun, rmissAmbient;
std::unique_ptr<VulkanShader> rchitBounce, rchitLight, rchitSun, rchitAmbient;
std::unique_ptr<VulkanShader> vertShader;
std::unique_ptr<VulkanShader> fragShader;
std::unique_ptr<VulkanShader> fragResolveShader;
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
struct
{
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
std::unique_ptr<VulkanPipeline> pipeline;
std::unique_ptr<VulkanRenderPass> renderPass;
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
std::unique_ptr<VulkanDescriptorSet> descriptorSet;
} raytrace;
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
std::unique_ptr<VulkanPipeline> pipeline;
std::unique_ptr<VulkanBuffer> shaderBindingTable;
std::unique_ptr<VulkanBuffer> sbtTransferBuffer;
VkStridedDeviceAddressRegionKHR rgenBounceRegion = {}, rgenLightRegion = {}, rgenAmbientRegion = {};
VkStridedDeviceAddressRegionKHR missRegion = {};
VkStridedDeviceAddressRegionKHR hitRegion = {};
VkStridedDeviceAddressRegionKHR callRegion = {};
std::unique_ptr<VulkanImage> startPositionsImage, positionsImage, outputImage;
std::unique_ptr<VulkanImageView> startPositionsImageView, positionsImageView, outputImageView;
std::unique_ptr<VulkanBuffer> imageTransferBuffer;
struct
{
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
std::unique_ptr<VulkanPipeline> pipeline;
std::unique_ptr<VulkanRenderPass> renderPass;
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
std::vector<std::unique_ptr<VulkanDescriptorSet>> descriptorSets;
std::unique_ptr<VulkanSampler> sampler;
} resolve;
std::unique_ptr<VulkanBuffer> uniformBuffer;
std::unique_ptr<VulkanBuffer> uniformTransferBuffer;
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
std::unique_ptr<VulkanDescriptorSet> descriptorSet;
std::unique_ptr<VulkanFence> submitFence;
std::unique_ptr<VulkanCommandPool> cmdpool;
std::unique_ptr<VulkanCommandBuffer> cmdbuffer;
std::vector<LightmapImage> atlasImages;
static const int atlasImageSize = 2048;
};

View file

@ -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 <map>
#include <vector>
#include <algorithm>
#include <limits>
#include <condition_variable>
#include <mutex>
#include <thread>
#include "glsl_frag.h"
#include "glsl_frag_resolve.h"
#include "glsl_vert.h"
extern bool VKDebug;
GPURaytracer2::GPURaytracer2()
{
device = std::make_unique<VulkanDevice>(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<Uniforms2*>(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, &region);
}
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<VulkanFence>(device.get());
cmdpool = std::make_unique<VulkanCommandPool>(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<uint64_t>::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<SurfaceInfo2> 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<SurfaceInfo2> GPURaytracer2::CreateSurfaceInfo()
{
std::vector<SurfaceInfo2> 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;
}

View file

@ -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<VulkanImage> Image;
std::unique_ptr<VulkanImageView> View;
std::unique_ptr<VulkanFramebuffer> Framebuffer;
} raytrace;
struct
{
std::unique_ptr<VulkanImage> Image;
std::unique_ptr<VulkanImageView> View;
std::unique_ptr<VulkanFramebuffer> Framebuffer;
} resolve;
std::unique_ptr<VulkanBuffer> 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<SurfaceInfo2> 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<VulkanDevice> device;
static const int SceneVertexBufferSize = 1 * 1024 * 1024;
std::unique_ptr<VulkanBuffer> sceneVertexBuffer;
SceneVertex* sceneVertices = nullptr;
int sceneVertexPos = 0;
static const int SceneLightBufferSize = 2 * 1024 * 1024;
std::unique_ptr<VulkanBuffer> sceneLightBuffer;
LightInfo2* sceneLights = nullptr;
int sceneLightPos = 0;
std::unique_ptr<VulkanBuffer> vertexBuffer;
std::unique_ptr<VulkanBuffer> indexBuffer;
std::unique_ptr<VulkanBuffer> transferBuffer;
std::unique_ptr<VulkanBuffer> surfaceIndexBuffer;
std::unique_ptr<VulkanBuffer> surfaceBuffer;
std::unique_ptr<VulkanBuffer> blScratchBuffer;
std::unique_ptr<VulkanBuffer> blAccelStructBuffer;
std::unique_ptr<VulkanAccelerationStructure> blAccelStruct;
std::unique_ptr<VulkanBuffer> tlTransferBuffer;
std::unique_ptr<VulkanBuffer> tlScratchBuffer;
std::unique_ptr<VulkanBuffer> tlInstanceBuffer;
std::unique_ptr<VulkanBuffer> tlAccelStructBuffer;
std::unique_ptr<VulkanAccelerationStructure> tlAccelStruct;
std::unique_ptr<VulkanShader> vertShader;
std::unique_ptr<VulkanShader> fragShader;
std::unique_ptr<VulkanShader> fragResolveShader;
struct
{
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
std::unique_ptr<VulkanPipeline> pipeline;
std::unique_ptr<VulkanRenderPass> renderPass;
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
std::unique_ptr<VulkanDescriptorSet> descriptorSet;
} raytrace;
struct
{
std::unique_ptr<VulkanDescriptorSetLayout> descriptorSetLayout;
std::unique_ptr<VulkanPipelineLayout> pipelineLayout;
std::unique_ptr<VulkanPipeline> pipeline;
std::unique_ptr<VulkanRenderPass> renderPass;
std::unique_ptr<VulkanDescriptorPool> descriptorPool;
std::vector<std::unique_ptr<VulkanDescriptorSet>> descriptorSets;
std::unique_ptr<VulkanSampler> sampler;
} resolve;
std::unique_ptr<VulkanBuffer> uniformBuffer;
std::unique_ptr<VulkanBuffer> uniformTransferBuffer;
std::unique_ptr<VulkanFence> submitFence;
std::unique_ptr<VulkanCommandPool> cmdpool;
std::unique_ptr<VulkanCommandBuffer> cmdbuffer;
std::vector<LightmapImage> atlasImages;
static const int atlasImageSize = 2048;
};