Skip to content

Commit afe456c

Browse files
committed
Add Vulkan rendering backend
Implement a Vulkan 1.1 renderer that replaces the previous stub with a fully functional backend, mostly matching the OpenGL backend's rendering capabilities. Core rendering infrastructure: - `VulkanMemory`: Custom allocator with sub-allocation from device-local and host-visible memory pools - `VulkanBuffer`: Per-frame bump allocator for streaming uniform/vertex/index data (persistently mapped, double-buffered, auto-growing) - `VulkanTexture`: Full texture management including 2D, 2D-array, 3D, and cubemap types with automatic mipmap generation and sampler caching - `VulkanPipeline`: Lazy pipeline creation from hashed render state, with persistent VkPipelineCache for cross-session reuse - `VulkanShader`: SPIR-V shader loading (main, deferred, effects, post-processing, shadows, decals, fog, MSAA resolve, etc.) - `VulkanDescriptorManager`: 3-set descriptor layout (Global/Material/PerDraw) with per-frame pool allocation, auto-grow, and batched updates - `VulkanDeletionQueue`: Deferred resource destruction synchronized to frame-in-flight fences Design choices: - Two frames in flight with fence-based synchronization - Asynchronous texture upload, no `waitIdle` in hot path - Single command buffer per frame; render passes begun/ended as needed for the multi-pass deferred pipeline - Per-frame descriptor pools - All descriptor bindings pre-initialized with fallback resources (zero UBO + 1x1 white texture) so partial updates never leave undefined state - Streaming data uses a bump allocator (one large VkBuffer per frame) - Pipeline cache persisted to disk for fast startup on subsequent runs Some notable Vulkan vs OpenGL differences are: - Depth range is [0,1] not [-1,1]: shadow projection matrices adjusted, shaders that linearize depth need isinf/zero guards at depth boundaries where OpenGL gives finite values - gl_ClipDistance is always evaluated: must write 1.0 when clipping is disabled (OpenGL allows leaving it uninitialized) - Swap chain is B8G8R8A8: screenshot/save_screen paths swizzle to RGBA - Vulkan render target is "upside down", y-flip for render target is handled through negative viewport height, as is common - Texture addressing for AABITMAP/INTERFACE/CUBEMAP forced to clamp (OpenGL's sampler state happens to do this implicitly) - Render pass architecture requires explicit transitions between G-buffer, shadow, decal, light accumulation, fog, and post-processing passes (OpenGL just switches FBO bindings)
1 parent 1108a18 commit afe456c

137 files changed

Lines changed: 23526 additions & 705 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

code/graphics/2d.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,8 @@ enum shader_type {
214214

215215
SDR_TYPE_IRRADIANCE_MAP_GEN,
216216

217+
SDR_TYPE_SHADOW_MAP,
218+
217219
NUM_SHADER_TYPES
218220
};
219221

code/graphics/matrix.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,18 @@ static void create_perspective_projection_matrix(matrix4 *out, float left, float
5353
out->a1d[5] = 2.0f * near_dist / (top - bottom);
5454
out->a1d[8] = (right + left) / (right - left);
5555
out->a1d[9] = (top + bottom) / (top - bottom);
56-
out->a1d[10] = -(far_dist + near_dist) / (far_dist - near_dist);
5756
out->a1d[11] = -1.0f;
58-
out->a1d[14] = -2.0f * far_dist * near_dist / (far_dist - near_dist);
57+
58+
if (gr_screen.mode == GR_VULKAN) {
59+
// Vulkan NDC Z range is [0, 1] (OpenGL is [-1, 1])
60+
// Y-flip is handled by negative viewport height (VK_KHR_maintenance1)
61+
out->a1d[10] = -far_dist / (far_dist - near_dist);
62+
out->a1d[14] = -far_dist * near_dist / (far_dist - near_dist);
63+
} else {
64+
// OpenGL NDC Z range is [-1, 1]
65+
out->a1d[10] = -(far_dist + near_dist) / (far_dist - near_dist);
66+
out->a1d[14] = -2.0f * far_dist * near_dist / (far_dist - near_dist);
67+
}
5968
}
6069

6170
static void create_orthographic_projection_matrix(matrix4* out, float left, float right, float bottom, float top, float near_dist, float far_dist)
@@ -64,11 +73,20 @@ static void create_orthographic_projection_matrix(matrix4* out, float left, floa
6473

6574
out->a1d[0] = 2.0f / (right - left);
6675
out->a1d[5] = 2.0f / (top - bottom);
67-
out->a1d[10] = -2.0f / (far_dist - near_dist);
6876
out->a1d[12] = -(right + left) / (right - left);
6977
out->a1d[13] = -(top + bottom) / (top - bottom);
70-
out->a1d[14] = -(far_dist + near_dist) / (far_dist - near_dist);
7178
out->a1d[15] = 1.0f;
79+
80+
if (gr_screen.mode == GR_VULKAN) {
81+
// Vulkan NDC Z range is [0, 1] (OpenGL is [-1, 1])
82+
// Y-flip is handled by negative viewport height (VK_KHR_maintenance1)
83+
out->a1d[10] = -1.0f / (far_dist - near_dist);
84+
out->a1d[14] = -near_dist / (far_dist - near_dist);
85+
} else {
86+
// OpenGL NDC Z range is [-1, 1]
87+
out->a1d[10] = -2.0f / (far_dist - near_dist);
88+
out->a1d[14] = -(far_dist + near_dist) / (far_dist - near_dist);
89+
}
7290
}
7391

7492
void gr_start_instance_matrix(const vec3d *offset, const matrix *rotation)

code/graphics/shaders/batched.frag

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#version 450
2+
#extension GL_ARB_separate_shader_objects : enable
3+
4+
#include "gamma.sdr"
5+
6+
// Inputs from vertex shader
7+
layout (location = 0) in vec4 fragTexCoord;
8+
layout (location = 1) in vec4 fragColor;
9+
10+
// Output
11+
layout (location = 0) out vec4 fragOut0;
12+
13+
// Texture sampler array (binding 1 in Material set)
14+
layout (set = 1, binding = 1) uniform sampler2DArray baseMap;
15+
16+
// Uniform buffer: GenericData (binding 0 in PerDraw set)
17+
// Must match the layout used by vulkan_set_default_material_uniforms()
18+
layout (set = 2, binding = 0, std140) uniform genericData {
19+
mat4 modelMatrix;
20+
21+
vec4 color;
22+
23+
vec4 clipEquation;
24+
25+
int baseMapIndex;
26+
int alphaTexture;
27+
int noTexturing;
28+
int srgb;
29+
30+
float intensity;
31+
float alphaThreshold;
32+
uint clipEnabled;
33+
};
34+
35+
void main()
36+
{
37+
float y = fragTexCoord.y / fragTexCoord.w;
38+
vec4 baseColor = texture(baseMap, vec3(fragTexCoord.x, y, fragTexCoord.z));
39+
40+
baseColor.rgb = srgb_to_linear(baseColor.rgb);
41+
vec4 blendColor = vec4(srgb_to_linear(fragColor.rgb), fragColor.a);
42+
43+
fragOut0 = baseColor * blendColor * intensity;
44+
}

code/graphics/shaders/batched.vert

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#version 450
2+
#extension GL_ARB_separate_shader_objects : enable
3+
4+
// Vertex inputs
5+
layout (location = 0) in vec4 vertPosition;
6+
layout (location = 1) in vec4 vertColor;
7+
layout (location = 2) in vec4 vertTexCoord;
8+
9+
// Outputs to fragment shader
10+
layout (location = 0) out vec4 fragTexCoord;
11+
layout (location = 1) out vec4 fragColor;
12+
13+
// Uniform buffer: Matrices (binding 1 in PerDraw set)
14+
layout (set = 2, binding = 1, std140) uniform matrixData {
15+
mat4 modelViewMatrix;
16+
mat4 projMatrix;
17+
};
18+
19+
// Uniform buffer: GenericData (binding 0 in PerDraw set)
20+
// Must match the layout used by vulkan_set_default_material_uniforms()
21+
layout (set = 2, binding = 0, std140) uniform genericData {
22+
mat4 modelMatrix;
23+
24+
vec4 color;
25+
26+
vec4 clipEquation;
27+
28+
int baseMapIndex;
29+
int alphaTexture;
30+
int noTexturing;
31+
int srgb;
32+
33+
float intensity;
34+
float alphaThreshold;
35+
uint clipEnabled;
36+
};
37+
38+
void main()
39+
{
40+
fragColor = vertColor * color;
41+
gl_Position = projMatrix * modelViewMatrix * vertPosition;
42+
fragTexCoord = vertTexCoord;
43+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#version 450
2+
#extension GL_ARB_separate_shader_objects : enable
3+
4+
layout(location = 0) in vec2 fragTexCoord;
5+
layout(location = 0) out vec4 fragOut0;
6+
7+
layout(set = 1, binding = 1) uniform sampler2D bloomed;
8+
9+
layout(std140, set = 2, binding = 0) uniform genericData {
10+
float bloom_intensity;
11+
int levels;
12+
};
13+
14+
void main()
15+
{
16+
vec4 color_out = vec4(0.0, 0.0, 0.0, 1.0);
17+
float factor = 0.0;
18+
for (int mipmap = 0; mipmap < levels; ++mipmap) {
19+
float scale = 1.0 / exp2(float(mipmap));
20+
factor += scale;
21+
color_out.rgb += textureLod(bloomed, fragTexCoord, float(mipmap)).rgb * scale;
22+
}
23+
color_out.rgb /= factor;
24+
color_out.rgb *= bloom_intensity;
25+
fragOut0 = color_out;
26+
}

code/graphics/shaders/blur.frag

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#version 450
2+
#extension GL_ARB_separate_shader_objects : enable
3+
4+
layout(location = 0) in vec2 fragTexCoord;
5+
layout(location = 0) out vec4 fragOut0;
6+
7+
layout(set = 1, binding = 1) uniform sampler2D tex;
8+
9+
layout(std140, set = 2, binding = 0) uniform genericData {
10+
float texSize;
11+
int level;
12+
int direction; // 0 = horizontal, 1 = vertical
13+
};
14+
15+
void main()
16+
{
17+
float BlurWeights[6];
18+
BlurWeights[0] = 0.1362;
19+
BlurWeights[1] = 0.1297;
20+
BlurWeights[2] = 0.1120;
21+
BlurWeights[3] = 0.0877;
22+
BlurWeights[4] = 0.0623;
23+
BlurWeights[5] = 0.0402;
24+
25+
vec4 sum = textureLod(tex, fragTexCoord, float(level)) * BlurWeights[0];
26+
27+
for (int i = 1; i < 6; i++) {
28+
float offset = float(i) * texSize;
29+
if (direction == 0) {
30+
sum += textureLod(tex, vec2(clamp(fragTexCoord.x - offset, 0.0, 1.0), fragTexCoord.y), float(level)) * BlurWeights[i];
31+
sum += textureLod(tex, vec2(clamp(fragTexCoord.x + offset, 0.0, 1.0), fragTexCoord.y), float(level)) * BlurWeights[i];
32+
} else {
33+
sum += textureLod(tex, vec2(fragTexCoord.x, clamp(fragTexCoord.y - offset, 0.0, 1.0)), float(level)) * BlurWeights[i];
34+
sum += textureLod(tex, vec2(fragTexCoord.x, clamp(fragTexCoord.y + offset, 0.0, 1.0)), float(level)) * BlurWeights[i];
35+
}
36+
}
37+
38+
fragOut0 = sum;
39+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#version 450
2+
#extension GL_ARB_separate_shader_objects : enable
3+
4+
layout(location = 0) in vec2 fragTexCoord;
5+
layout(location = 0) out vec4 fragOut0;
6+
7+
layout(set = 1, binding = 1) uniform sampler2D tex;
8+
9+
void main()
10+
{
11+
vec4 color = texture(tex, fragTexCoord);
12+
fragOut0 = vec4(max(vec3(0.0), color.rgb - vec3(1.0)), 1.0);
13+
}
4.37 KB
Binary file not shown.
3.53 KB
Binary file not shown.
3.07 KB
Binary file not shown.

0 commit comments

Comments
 (0)