GUI: Box drawing

This commit is contained in:
2026-05-13 05:40:31 +02:00
parent 79c62141df
commit bce62feb09
24 changed files with 747 additions and 62 deletions

View File

@@ -0,0 +1,39 @@
#version 460
#extension GL_EXT_nonuniform_qualifier : require
#extension GL_EXT_scalar_block_layout : require
#extension GL_EXT_shader_16bit_storage : require
in Varyings {
layout(location = 0) flat uint instance;
layout(location = 1) vec2 positionSSPX;
} var;
#include "includes/gui_box_common.glsl"
layout(location = 0) out vec4 fragColor;
float boxSDF(vec2 p, vec2 center, vec2 halfExtents, float borderRadius) {
vec2 q = abs(p - center) - halfExtents + borderRadius;
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - borderRadius;
}
#define BOX _Boxes[var.instance]
void main() {
vec2 halfExtentsPX = 0.5 * BOX.sizePX;
vec2 centerSSPX = BOX.positionSSPX + halfExtentsPX;
float borderHalfWidthPX = 0.5 * BOX.borderWidthPX;
float interiorSDF = boxSDF(var.positionSSPX, centerSSPX, halfExtentsPX, BOX.borderRadiusPX) + BOX.borderWidthPX;
float borderSDF = abs(interiorSDF - borderHalfWidthPX) - borderHalfWidthPX;
float interiorCoverage = clamp(-interiorSDF + 0.5, 0.0, 1.0) * BOX.backgroundColor.a;
float borderCoverage = clamp(-borderSDF + 0.5, 0.0, 1.0) * BOX.borderColor.a;
float totalCoverage = interiorCoverage + borderCoverage;
fragColor = vec4(
interiorCoverage * BOX.backgroundColor.rgb +
borderCoverage * BOX.borderColor.rgb,
totalCoverage
);
}

View File

@@ -0,0 +1,30 @@
#version 460
#extension GL_EXT_nonuniform_qualifier : require
#extension GL_EXT_scalar_block_layout : require
#extension GL_EXT_shader_16bit_storage : require
out Varyings {
layout(location = 0) flat uint instance;
layout(location = 1) vec2 positionSSPX;
} var;
#include "includes/gui_box_common.glsl"
const vec2 VERTICES[4] = vec2[](
vec2(0, 1),
vec2(1, 1),
vec2(0, 0),
vec2(1, 0)
);
#define BOX _Boxes[gl_InstanceIndex]
#define VERTEX VERTICES[gl_VertexIndex]
void main() {
vec2 positionSSPX = VERTEX * BOX.sizePX + BOX.positionSSPX;
vec4 positionCS = vec4(_Global.matrixSSPXtoCS * vec3(positionSSPX, 1.0), 0.0, 1.0);
gl_Position = positionCS;
var.instance = gl_InstanceIndex;
var.positionSSPX = positionSSPX;
}

View File

@@ -0,0 +1,20 @@
#version 460
#extension GL_EXT_nonuniform_qualifier : require
#extension GL_EXT_scalar_block_layout : require
#extension GL_EXT_shader_16bit_storage : require
in Varyings {
layout(location = 0) flat uint instance;
layout(location = 1) vec2 texCoord;
} var;
#include "includes/gui_image_common.glsl"
layout(location = 0) out vec4 fragColor;
#define IMAGE _Images[var.instance]
void main() {
vec4 texel = texture(sampler2D(_Textures[uint(IMAGE.textureId)], _Sampler), var.texCoord);
fragColor = texel * IMAGE.tint;
}

View File

@@ -0,0 +1,32 @@
#version 460
#extension GL_EXT_nonuniform_qualifier : require
#extension GL_EXT_scalar_block_layout : require
#extension GL_EXT_shader_16bit_storage : require
out Varyings {
layout(location = 0) flat uint instance;
layout(location = 1) vec2 texCoord;
} var;
#include "includes/gui_image_common.glsl"
const vec2 VERTICES[4] = vec2[](
vec2(0, 1),
vec2(1, 1),
vec2(0, 0),
vec2(1, 0)
);
#define IMAGE _Images[gl_InstanceIndex]
#define VERTEX VERTICES[gl_VertexIndex]
void main() {
vec2 positionSSPX = VERTEX * IMAGE.sizePX + IMAGE.positionSSPX;
vec4 positionCS = vec4(_Global.matrixSSPXtoCS * vec3(positionSSPX, 1.0), 0.0, 1.0);
vec2 texCoord = VERTEX * (IMAGE.uvMax - IMAGE.uvMin) + IMAGE.uvMin;
gl_Position = positionCS;
var.instance = gl_InstanceIndex;
var.texCoord = texCoord;
}

View File

@@ -0,0 +1,15 @@
#version 460
#extension GL_EXT_nonuniform_qualifier : require
#extension GL_EXT_scalar_block_layout : require
#extension GL_EXT_shader_16bit_storage : require
uint calcRootCode(float y1, float y2, float y3) {
uint i1 = floatBitsToUint(y1) >> 31U;
uint i2 = floatBitsToUint(y2) >> 30U;
uint i3 = floatBitsToUint(y3) >> 29U;
uint shift = (i2 & 2U) | (i1 & ~2U);
shift = (i3 & 4U) | (shift & ~4U);
return ((0x2E74U >> shift) & 0x0101U);
}

View File

@@ -0,0 +1,10 @@
#version 460
#extension GL_EXT_nonuniform_qualifier : require
#extension GL_EXT_scalar_block_layout : require
#extension GL_EXT_shader_16bit_storage : require
layout(location = 0) in vec4 positionOS_normalOS;
layout(location = 1) in vec4 texCoordEM_band_flags;
layout(location = 2) in vec4 jacobian;
layout(location = 3) in vec4 scale_offset;
layout(location = 4) in vec4 color;

View File

@@ -0,0 +1,6 @@
layout(set = 0, binding = 0, scalar) uniform GlobalUniforms {
mat4 matrixWStoVS;
mat4 matrixVStoCS;
mat3x2 matrixSSPXtoCS;
vec3 ambientLight;
} _Global;

View File

@@ -0,0 +1,14 @@
struct Box {
vec4 backgroundColor;
vec4 borderColor;
vec2 positionSSPX;
vec2 sizePX;
float borderWidthPX;
float borderRadiusPX;
};
#include "global_uniforms.glsl"
layout(set = 0, binding = 1, scalar) readonly buffer Boxes {
Box _Boxes[];
};

View File

@@ -0,0 +1,17 @@
struct Image {
vec4 tint;
vec2 positionSSPX;
vec2 sizePX;
vec2 uvMin;
vec2 uvMax;
uint16_t textureId;
};
#include "global_uniforms.glsl"
layout(set = 0, binding = 1, scalar) readonly buffer Images {
Image _Images[];
};
layout(set = 0, binding = 2) uniform sampler _Sampler;
layout(set = 0, binding = 3) uniform texture2D _Textures[];

View File

@@ -32,11 +32,7 @@ struct ObjectUniforms {
uint16_t material; uint16_t material;
}; };
layout(set = 0, binding = 0, scalar) uniform GlobalUniforms { #include "global_uniforms.glsl"
mat4 matrixWStoVS;
mat4 matrixVStoCS;
vec3 ambientLight;
} _Global;
layout(set = 0, binding = 1, scalar) readonly buffer PointLights { layout(set = 0, binding = 1, scalar) readonly buffer PointLights {
uint count; uint count;

View File

@@ -0,0 +1,8 @@
vec3 toneMapAcesNarkowicz(vec3 color) {
const float A = 2.51;
const float B = 0.03;
const float C = 2.43;
const float D = 0.59;
const float E = 0.14;
return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0);
}

View File

@@ -12,7 +12,8 @@ in Varyings {
layout(location = 5) vec3 bitangentVS; layout(location = 5) vec3 bitangentVS;
} var; } var;
#include "main_common.glsl" #include "includes/main_common.glsl"
#include "includes/tone_mapping.glsl"
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
@@ -39,15 +40,6 @@ float distributionGGX(float dotNH, float alpha) {
return alphaSquared * INV_PI / (tmp * tmp); return alphaSquared * INV_PI / (tmp * tmp);
} }
vec3 toneMapAcesNarkowicz(vec3 color) {
const float A = 2.51;
const float B = 0.03;
const float C = 2.43;
const float D = 0.59;
const float E = 0.14;
return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0);
}
vec3 lightOutgoingRadiance( vec3 lightOutgoingRadiance(
vec3 viewDirectionVS, vec3 normalVS, float dotNV, vec3 viewDirectionVS, vec3 normalVS, float dotNV,
vec3 baseColor, float alpha, float metallic, vec3 f0, vec3 baseColor, float alpha, float metallic, vec3 f0,

View File

@@ -17,7 +17,7 @@ out Varyings {
layout(location = 5) vec3 bitangentVS; layout(location = 5) vec3 bitangentVS;
} var; } var;
#include "main_common.glsl" #include "includes/main_common.glsl"
#define OBJECT _Object[gl_InstanceIndex] #define OBJECT _Object[gl_InstanceIndex]

View File

@@ -9,14 +9,7 @@ layout(set = 0, binding = 2) uniform textureCube _Texture;
layout(location = 0) out vec4 fragColor; layout(location = 0) out vec4 fragColor;
vec3 toneMapAcesNarkowicz(vec3 color) { #include "includes/tone_mapping.glsl"
const float A = 2.51;
const float B = 0.03;
const float C = 2.43;
const float D = 0.59;
const float E = 0.14;
return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0);
}
void main() { void main() {
vec4 texel = texture(samplerCube(_Texture, _Sampler), var.texCoord); vec4 texel = texture(samplerCube(_Texture, _Sampler), var.texCoord);

View File

@@ -7,11 +7,7 @@ out Varyings {
layout(location = 0) vec3 texCoord; layout(location = 0) vec3 texCoord;
} var; } var;
layout(set = 0, binding = 0, scalar) uniform GlobalUniforms { #include "includes/global_uniforms.glsl"
mat4 matrixWStoVS;
mat4 matrixVStoCS;
vec3 ambientLight;
} _Global;
void main() { void main() {
vec3 directionVS = (_Global.matrixWStoVS * vec4(directionWS, 0.0)).xyz; vec3 directionVS = (_Global.matrixWStoVS * vec4(directionWS, 0.0)).xyz;

View File

@@ -10,11 +10,22 @@ pub fn build(b: *std.Build) !void {
const media_dep = b.dependency("media", .{ const media_dep = b.dependency("media", .{
.target = target, .target = target,
}); });
const vecmath_dep = b.dependency("vecmath", .{ const vecmath_dep = b.dependency("vecmath", .{
.target = target, .target = target,
}); });
const vulkan_dep = b.dependency("vulkan_zig", .{ .registry = b.path("vendor/vk.xml") });
const zglfw_dep = b.dependency("zglfw", .{ .import_vulkan = true }); const vulkan_dep = b.dependency("vulkan_zig", .{
.target = target,
.optimize = optimize,
.registry = b.path("vendor/vk.xml"),
});
const zglfw_dep = b.dependency("zglfw", .{
.target = target,
.optimize = optimize,
.import_vulkan = true,
});
const media_mod = media_dep.module("media"); const media_mod = media_dep.module("media");
const vecmath_mod = vecmath_dep.module("vecmath"); const vecmath_mod = vecmath_dep.module("vecmath");

View File

@@ -1,7 +1,9 @@
#!/bin/sh #!/bin/sh
glslc --target-env=vulkan1.2 assets/shaders/equirect_to_cube.comp -o src/shaders/equirect_to_cube_comp.spv glslc -g --target-env=vulkan1.2 assets/shaders/equirect_to_cube.comp -o src/shaders/equirect_to_cube_comp.spv
glslc --target-env=vulkan1.2 assets/shaders/main.frag -o src/shaders/main_frag.spv glslc -g --target-env=vulkan1.2 assets/shaders/gui_box.frag -o src/shaders/gui_box_frag.spv
glslc --target-env=vulkan1.2 assets/shaders/main.vert -o src/shaders/main_vert.spv glslc -g --target-env=vulkan1.2 assets/shaders/gui_box.vert -o src/shaders/gui_box_vert.spv
glslc --target-env=vulkan1.2 assets/shaders/skybox.frag -o src/shaders/skybox_frag.spv glslc -g --target-env=vulkan1.2 assets/shaders/main.frag -o src/shaders/main_frag.spv
glslc --target-env=vulkan1.2 assets/shaders/skybox.vert -o src/shaders/skybox_vert.spv glslc -g --target-env=vulkan1.2 assets/shaders/main.vert -o src/shaders/main_vert.spv
glslc -g --target-env=vulkan1.2 assets/shaders/skybox.frag -o src/shaders/skybox_frag.spv
glslc -g --target-env=vulkan1.2 assets/shaders/skybox.vert -o src/shaders/skybox_vert.spv

View File

@@ -15,6 +15,7 @@ const Chunk = @import("assets/Chunk.zig");
const Chunks = @import("Chunks.zig"); const Chunks = @import("Chunks.zig");
const CommandBuffer = @import("engine/CommandBuffer.zig"); const CommandBuffer = @import("engine/CommandBuffer.zig");
const Engine = @import("engine/Engine.zig"); const Engine = @import("engine/Engine.zig");
const Gui = @import("Gui.zig");
const Iterator2 = math.Iterator2; const Iterator2 = math.Iterator2;
const Materials = @import("assets/Materials.zig"); const Materials = @import("assets/Materials.zig");
const Player = @import("Player.zig"); const Player = @import("Player.zig");
@@ -51,6 +52,7 @@ materials: Materials,
textures: Textures, textures: Textures,
chunks: Chunks, chunks: Chunks,
skybox: Skybox, skybox: Skybox,
gui: Gui,
player: Player, player: Player,
@@ -164,7 +166,7 @@ pub fn init(allocator: std.mem.Allocator, io: std.Io, engine: *Engine, swapchain
}, },
}); });
errdefer engine.destroyPipelineLayout(pipeline_layout); errdefer engine.destroyPipelineLayout(pipeline_layout);
engine.setObjectName(pipeline_layout, "PL", .{}); engine.setObjectName(pipeline_layout, "PL Main", .{});
const vertex_shader = try engine.createShaderModule(.{ .code = &shaders.main_vert_spv }); const vertex_shader = try engine.createShaderModule(.{ .code = &shaders.main_vert_spv });
defer engine.destroyShaderModule(vertex_shader); defer engine.destroyShaderModule(vertex_shader);
@@ -403,7 +405,7 @@ pub fn init(allocator: std.mem.Allocator, io: std.Io, engine: *Engine, swapchain
.subpass = 0, .subpass = 0,
}); });
errdefer engine.destroyPipeline(pipeline); errdefer engine.destroyPipeline(pipeline);
engine.setObjectName(pipeline, "P", .{}); engine.setObjectName(pipeline, "P Main", .{});
const descriptor_pool = try engine.createDescriptorPool(.{ const descriptor_pool = try engine.createDescriptorPool(.{
.flags = .{ .flags = .{
@@ -430,7 +432,7 @@ pub fn init(allocator: std.mem.Allocator, io: std.Io, engine: *Engine, swapchain
}, },
}); });
errdefer engine.destroyDescriptorPool(descriptor_pool); errdefer engine.destroyDescriptorPool(descriptor_pool);
engine.setObjectName(descriptor_pool, "DP", .{}); engine.setObjectName(descriptor_pool, "DP Main", .{});
const global_descriptor_set = try engine.allocateDescriptorSet(.{ const global_descriptor_set = try engine.allocateDescriptorSet(.{
.descriptor_pool = descriptor_pool, .descriptor_pool = descriptor_pool,
@@ -645,6 +647,14 @@ pub fn init(allocator: std.mem.Allocator, io: std.Io, engine: *Engine, swapchain
); );
errdefer skybox.deinit(engine); errdefer skybox.deinit(engine);
var gui = try Gui.init(
allocator,
engine,
global_uniforms.buffer,
swapchain.render_pass,
);
errdefer gui.deinit(engine, allocator);
return .{ return .{
.allocator = allocator, .allocator = allocator,
.io = io, .io = io,
@@ -674,6 +684,7 @@ pub fn init(allocator: std.mem.Allocator, io: std.Io, engine: *Engine, swapchain
.textures = textures, .textures = textures,
.chunks = .{ .chunks = chunks }, .chunks = .{ .chunks = chunks },
.skybox = skybox, .skybox = skybox,
.gui = gui,
.player = .init(player_position_sv, 0, 0), .player = .init(player_position_sv, 0, 0),
}; };
@@ -692,6 +703,7 @@ pub fn deinit(self: *Game) void {
self.chunks.deinit(self.engine, self.descriptor_pool, self.allocator); self.chunks.deinit(self.engine, self.descriptor_pool, self.allocator);
self.skybox.deinit(self.engine); self.skybox.deinit(self.engine);
self.gui.deinit(self.engine, self.allocator);
self.global_uniforms.deinit(self.engine); self.global_uniforms.deinit(self.engine);
self.global_uniforms_staging_buffer.deinit(self.engine); self.global_uniforms_staging_buffer.deinit(self.engine);
@@ -718,8 +730,36 @@ pub fn deinit(self: *Game) void {
} }
pub fn update(self: *Game, dt: f32) void { pub fn update(self: *Game, dt: f32) void {
self.gui.beginFrame();
self.player.update(dt, &self.chunks); self.player.update(dt, &self.chunks);
const extent = self.swapchain.extent;
const framebuffer_size = vm.Vector2.init(
@floatFromInt(extent.width),
@floatFromInt(extent.height),
);
const crosshair_half_extent_px = 8;
const crosshair_half_width_px = 1;
self.gui.pushBox(.{
.background_color = .init(1, 1, 1, 0.5),
.border_color = .init(0, 0, 0, 1),
.position_sspx = framebuffer_size.mulScalar(0.5).add(.init(-crosshair_half_extent_px, -crosshair_half_width_px)),
.size_px = .init(2.0 * crosshair_half_extent_px, 2.0 * crosshair_half_width_px),
.border_width_px = 0,
.border_radius_px = 0,
});
self.gui.pushBox(.{
.background_color = .init(1, 1, 1, 0.5),
.border_color = .init(0, 0, 0, 1),
.position_sspx = framebuffer_size.mulScalar(0.5).add(.init(-crosshair_half_width_px, -crosshair_half_extent_px)),
.size_px = .init(2.0 * crosshair_half_width_px, 2.0 * crosshair_half_extent_px),
.border_width_px = 0,
.border_radius_px = 0,
});
self.render() catch |err| { self.render() catch |err| {
std.log.err("Failed to render: {s}", .{@errorName(err)}); std.log.err("Failed to render: {s}", .{@errorName(err)});
@panic("Frame update failed"); @panic("Frame update failed");
@@ -807,11 +847,20 @@ fn render(self: *Game) !void {
); );
// zig fmt: on // zig fmt: on
// zig fmt: off
const matrix_sspx_to_cs = vm.Matrix3x2.init(
2.0 / framebuffer_size.x, 0,
0, 2.0 / framebuffer_size.y,
-1, -1,
);
// zig fmt: on
const ambient_light = vm.Vector3.init(0.01, 0.01, 0.01); const ambient_light = vm.Vector3.init(0.01, 0.01, 0.01);
const global_uniforms_data: shaders.GlobalUniforms = .{ const global_uniforms_data: shaders.GlobalUniforms = .{
.matrixWStoVS = matrix_ws_to_vs, .matrixWStoVS = matrix_ws_to_vs,
.matrixVStoCS = matrix_vs_to_cs, .matrixVStoCS = matrix_vs_to_cs,
.matrixSSPXtoCS = matrix_sspx_to_cs,
.ambientLight = ambient_light, .ambientLight = ambient_light,
}; };
@@ -887,6 +936,8 @@ fn render(self: *Game) !void {
}, },
}); });
// --- SUBPASS 0 (MAIN) ---
command_buffer.bindPipeline(.graphics, self.pipeline); command_buffer.bindPipeline(.graphics, self.pipeline);
try command_buffer.bindVertexBuffers(0, &.{ try command_buffer.bindVertexBuffers(0, &.{
.{ .{
@@ -902,8 +953,13 @@ fn render(self: *Game) !void {
chunk.draw(self.pipeline_layout, command_buffer); chunk.draw(self.pipeline_layout, command_buffer);
} }
try self.skybox.bind(command_buffer, extent); try self.skybox.draw(command_buffer);
self.skybox.draw(command_buffer);
// --- SUBPASS 1 (GUI) ---
command_buffer.nextSubpass(.@"inline");
try self.gui.draw(self.engine, command_buffer);
} }
try command_buffer.endCommandBuffer(); try command_buffer.endCommandBuffer();

427
src/Gui.zig Normal file
View File

@@ -0,0 +1,427 @@
const Gui = @This();
const std = @import("std");
const shaders = @import("shaders.zig");
const vk = @import("vulkan");
const vm = @import("vecmath");
const CommandBuffer = @import("engine/CommandBuffer.zig");
const Engine = @import("engine/Engine.zig");
const GenericBuffer = @import("engine/GenericBuffer.zig").GenericBuffer;
const Swapchain = @import("engine/Swapchain.zig");
const Textures = @import("assets/Textures.zig");
pub const Draw = struct {
pub const Box = extern struct {
background_color: vm.Vector4,
border_color: vm.Vector4,
position_sspx: vm.Vector2,
size_px: vm.Vector2,
border_width_px: f32,
border_radius_px: f32,
};
pub const Text = extern struct {
color: vm.Vector4,
pos_min: vm.Vector2,
pos_max: vm.Vector2,
uv_min: vm.Vector2,
uv_max: vm.Vector2,
atlas_id: Textures.Id,
};
pub const Image = extern struct {
tint: vm.Vector4,
position_sspx: vm.Vector2,
size_px: vm.Vector2,
uv_min: vm.Vector2,
uv_max: vm.Vector2,
texture_id: Textures.Id,
};
};
pub const Batch = struct {
draw_type: std.meta.DeclEnum(Draw),
first_instance: u32,
instance_count: u32,
};
box_gpu_buffer: GenericBuffer(void, Draw.Box),
text_gpu_buffer: GenericBuffer(void, Draw.Text),
image_gpu_buffer: GenericBuffer(void, Draw.Image),
box_cpu_buffer: std.ArrayList(Draw.Box),
text_cpu_buffer: std.ArrayList(Draw.Text),
image_cpu_buffer: std.ArrayList(Draw.Image),
batches: std.ArrayList(Batch),
sampler: vk.Sampler,
index_buffer: shaders.IndexBuffer,
box_descriptor_set_layout: vk.DescriptorSetLayout,
box_pipeline_layout: vk.PipelineLayout,
box_pipeline: vk.Pipeline,
descriptor_pool: vk.DescriptorPool,
box_descriptor_set: vk.DescriptorSet,
pub const max_box_draws = 1024;
pub const max_image_draws = 1024;
pub const max_text_draws = 4096;
pub const max_batches = 1024;
pub fn init(
allocator: std.mem.Allocator,
engine: *Engine,
global_uniforms_buffer: vk.Buffer,
render_pass: vk.RenderPass,
) !Gui {
var box_gpu_buffer: GenericBuffer(void, Draw.Box) = try .init(engine, .{
.usage = .storage,
.target_queue = .graphics,
.array_capacity = max_box_draws,
.name = "GUI box draws",
});
errdefer box_gpu_buffer.deinit(engine);
var text_gpu_buffer: GenericBuffer(void, Draw.Text) = try .init(engine, .{
.usage = .storage,
.target_queue = .graphics,
.array_capacity = max_text_draws,
.name = "GUI text draws",
});
errdefer text_gpu_buffer.deinit(engine);
var image_gpu_buffer: GenericBuffer(void, Draw.Image) = try .init(engine, .{
.usage = .storage,
.target_queue = .graphics,
.array_capacity = max_image_draws,
.name = "GUI image draws",
});
errdefer image_gpu_buffer.deinit(engine);
var box_cpu_buffer: std.ArrayList(Draw.Box) = try .initCapacity(allocator, max_box_draws);
errdefer box_cpu_buffer.deinit(allocator);
var text_cpu_buffer: std.ArrayList(Draw.Text) = try .initCapacity(allocator, max_text_draws);
errdefer text_cpu_buffer.deinit(allocator);
var image_cpu_buffer: std.ArrayList(Draw.Image) = try .initCapacity(allocator, max_image_draws);
errdefer image_cpu_buffer.deinit(allocator);
var batches: std.ArrayList(Batch) = try .initCapacity(allocator, max_batches);
errdefer batches.deinit(allocator);
const sampler = try engine.createSampler(.{
.mag_filter = .linear,
.min_filter = .linear,
.mipmap_mode = .linear,
.address_mode_u = .repeat,
.address_mode_v = .repeat,
.address_mode_w = .repeat,
.mip_lod_bias = 0,
.anisotropy_enable = .false,
.max_anisotropy = 0,
.compare_enable = .false,
.compare_op = .always,
.min_lod = 0,
.max_lod = vk.LOD_CLAMP_NONE,
.border_color = .float_transparent_black,
.unnormalized_coordinates = .false,
});
errdefer engine.destroySampler(sampler);
const box_descriptor_set_layout = try engine.createDescriptorSetLayout(.{
.bindings = &.{
.{
.binding = 0,
.descriptor_type = .uniform_buffer,
.descriptor_count = 1,
.stage_flags = .{ .vertex_bit = true, .fragment_bit = true },
},
.{
.binding = 1,
.descriptor_type = .storage_buffer,
.descriptor_count = 1,
.stage_flags = .{ .vertex_bit = true, .fragment_bit = true },
},
},
});
errdefer engine.destroyDescriptorSetLayout(box_descriptor_set_layout);
engine.setObjectName(box_descriptor_set_layout, "DSL GUI Box", .{});
const box_pipeline_layout = try engine.createPipelineLayout(.{
.set_layouts = &.{
box_descriptor_set_layout,
},
});
errdefer engine.destroyPipelineLayout(box_pipeline_layout);
engine.setObjectName(box_pipeline_layout, "PL GUI Box", .{});
const box_vertex_shader = try engine.createShaderModule(.{ .code = &shaders.gui_box_vert_spv });
defer engine.destroyShaderModule(box_vertex_shader);
engine.setObjectName(box_vertex_shader, "SM gui_box_vert", .{});
const box_fragment_shader = try engine.createShaderModule(.{ .code = &shaders.gui_box_frag_spv });
defer engine.destroyShaderModule(box_fragment_shader);
engine.setObjectName(box_fragment_shader, "SM gui_box_frag", .{});
var index_buffer = try shaders.IndexBuffer.init(engine, .{
.usage = .index,
.target_queue = .graphics,
.array_capacity = 6,
.name = "QuadIB",
});
errdefer index_buffer.deinit(engine);
try index_buffer.write(engine, .{
.elements = &.{ 0, 1, 2, 2, 1, 3 },
});
const box_pipeline = try engine.createGraphicsPipeline(.{
.stages = &.{
.{
.stage = .{ .vertex_bit = true },
.module = box_vertex_shader,
.name = "main",
},
.{
.stage = .{ .fragment_bit = true },
.module = box_fragment_shader,
.name = "main",
},
},
.vertex_input_state = .{},
.input_assembly_state = .{
.topology = .triangle_list,
.primitive_restart_enable = .false,
},
.viewport_state = .{
.viewports = &.{undefined}, // dynamic
.scissors = &.{undefined}, // dynamic
},
.rasterization_state = .{
.depth_clamp_enable = .false,
.rasterizer_discard_enable = .false,
.polygon_mode = .fill,
.cull_mode = .{},
.front_face = .counter_clockwise,
.depth_bias_enable = .false,
.depth_bias_constant_factor = 0,
.depth_bias_clamp = 0,
.depth_bias_slope_factor = 0,
.line_width = 1,
},
.multisample_state = .{
.rasterization_samples = .{ .@"1_bit" = true },
.sample_shading_enable = .false,
.min_sample_shading = 1,
.alpha_to_coverage_enable = .false,
.alpha_to_one_enable = .false,
},
.color_blend_state = .{
.logic_op_enable = .false,
.logic_op = .copy,
.attachments = &.{
.{
.blend_enable = .true,
.src_color_blend_factor = .one,
.dst_color_blend_factor = .one_minus_src_alpha,
.color_blend_op = .add,
.src_alpha_blend_factor = .one,
.dst_alpha_blend_factor = .one_minus_src_alpha,
.alpha_blend_op = .add,
.color_write_mask = .{
.r_bit = true,
.g_bit = true,
.b_bit = true,
.a_bit = true,
},
},
},
.blend_constants = .{ 0, 0, 0, 0 },
},
.dynamic_state = .{
.dynamic_states = &.{ .viewport, .scissor },
},
.layout = box_pipeline_layout,
.render_pass = render_pass,
.subpass = 1,
});
errdefer engine.destroyPipeline(box_pipeline);
engine.setObjectName(box_pipeline, "P GUI Box", .{});
const descriptor_pool = try engine.createDescriptorPool(.{
.max_sets = 1,
.pool_sizes = &.{
.{
.type = .uniform_buffer,
.descriptor_count = 1,
},
.{
.type = .storage_buffer,
.descriptor_count = 1,
},
},
});
errdefer engine.destroyDescriptorPool(descriptor_pool);
engine.setObjectName(descriptor_pool, "DP GUI", .{});
const box_descriptor_set = try engine.allocateDescriptorSet(.{
.descriptor_pool = descriptor_pool,
.set_layout = box_descriptor_set_layout,
});
engine.setObjectName(box_descriptor_set, "DS GUI Box", .{});
try engine.updateDescriptorSets(.{
.writes = &.{
.{
.dst_set = box_descriptor_set,
.dst_binding = 0,
.dst_array_element = 0,
.descriptor_type = .uniform_buffer,
.descriptor_infos = .{
.buffer = &.{
.{
.buffer = global_uniforms_buffer,
.offset = 0,
.range = vk.WHOLE_SIZE,
},
},
},
},
.{
.dst_set = box_descriptor_set,
.dst_binding = 1,
.dst_array_element = 0,
.descriptor_type = .storage_buffer,
.descriptor_infos = .{
.buffer = &.{
.{
.buffer = box_gpu_buffer.buffer,
.offset = 0,
.range = vk.WHOLE_SIZE,
},
},
},
},
},
});
return .{
.box_gpu_buffer = box_gpu_buffer,
.text_gpu_buffer = text_gpu_buffer,
.image_gpu_buffer = image_gpu_buffer,
.box_cpu_buffer = box_cpu_buffer,
.text_cpu_buffer = text_cpu_buffer,
.image_cpu_buffer = image_cpu_buffer,
.batches = batches,
.sampler = sampler,
.index_buffer = index_buffer,
.box_descriptor_set_layout = box_descriptor_set_layout,
.box_pipeline_layout = box_pipeline_layout,
.box_pipeline = box_pipeline,
.descriptor_pool = descriptor_pool,
.box_descriptor_set = box_descriptor_set,
};
}
pub fn deinit(self: *Gui, engine: *Engine, allocator: std.mem.Allocator) void {
std.log.scoped(.deinit).debug("Deinitializing {*} with {*} and Allocator{{{*},{*}}}", .{ self, engine, allocator.ptr, allocator.vtable });
engine.destroyDescriptorPool(self.descriptor_pool);
engine.destroyPipeline(self.box_pipeline);
self.index_buffer.deinit(engine);
engine.destroyPipelineLayout(self.box_pipeline_layout);
engine.destroyDescriptorSetLayout(self.box_descriptor_set_layout);
engine.destroySampler(self.sampler);
self.batches.deinit(allocator);
self.image_cpu_buffer.deinit(allocator);
self.text_cpu_buffer.deinit(allocator);
self.box_cpu_buffer.deinit(allocator);
self.image_gpu_buffer.deinit(engine);
self.text_gpu_buffer.deinit(engine);
self.box_gpu_buffer.deinit(engine);
self.* = undefined;
}
pub fn beginFrame(self: *Gui) void {
self.box_cpu_buffer.clearRetainingCapacity();
self.text_cpu_buffer.clearRetainingCapacity();
self.image_cpu_buffer.clearRetainingCapacity();
self.batches.clearRetainingCapacity();
}
pub fn pushBox(self: *Gui, box: Draw.Box) void {
const instance: u32 = @intCast(self.box_cpu_buffer.items.len);
self.box_cpu_buffer.appendBounded(box) catch return;
self.extendOrAddBatch(.Box, instance);
}
pub fn pushText(self: *Gui, text: Draw.Text) void {
const instance: u32 = @intCast(self.text_cpu_buffer.items.len);
self.text_cpu_buffer.appendBounded(text) catch return;
self.extendOrAddBatch(.Text, instance);
}
pub fn pushImage(self: *Gui, image: Draw.Image) void {
const instance: u32 = @intCast(self.image_cpu_buffer.items.len);
self.image_cpu_buffer.appendBounded(image) catch return;
self.extendOrAddBatch(.Image, instance);
}
fn extendOrAddBatch(self: *Gui, draw_type: std.meta.DeclEnum(Draw), instance: u32) void {
if (self.batches.items.len == 0 or self.batches.items[self.batches.items.len - 1].draw_type != draw_type) {
self.batches.appendBounded(.{
.draw_type = draw_type,
.first_instance = instance,
.instance_count = 1,
}) catch return;
} else {
const batch = &self.batches.items[self.batches.items.len - 1];
std.debug.assert(batch.first_instance + batch.instance_count == instance);
batch.instance_count += 1;
}
}
pub fn draw(self: *const Gui, engine: *Engine, command_buffer: CommandBuffer) !void {
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
try self.box_gpu_buffer.write(engine, .{ .elements = self.box_cpu_buffer.items });
try self.text_gpu_buffer.write(engine, .{ .elements = self.text_cpu_buffer.items });
try self.image_gpu_buffer.write(engine, .{ .elements = self.image_cpu_buffer.items });
for (self.batches.items) |batch| {
switch (batch.draw_type) {
.Box => {
command_buffer.bindPipeline(.graphics, self.box_pipeline);
command_buffer.bindDescriptorSet(.graphics, self.box_pipeline_layout, 0, self.box_descriptor_set, null);
},
.Text => {
std.log.warn("GUI Text not implemented; skipping batch", .{});
continue;
},
.Image => {
std.log.warn("GUI Image not implemented; skipping batch", .{});
continue;
},
}
command_buffer.drawIndexed(.{
.index_count = 6,
.first_instance = batch.first_instance,
.instance_count = batch.instance_count,
});
}
}

View File

@@ -186,6 +186,10 @@ pub fn copyBufferToImage(
self.proxy.copyBufferToImage(src_buffer, dst_image, dst_image_layout, regions); self.proxy.copyBufferToImage(src_buffer, dst_image, dst_image_layout, regions);
} }
pub fn nextSubpass(self: CommandBuffer, contents: vk.SubpassContents) void {
self.proxy.nextSubpass(contents);
}
pub fn pipelineBarrier(self: CommandBuffer, barrier: PipelineBarrier) void { pub fn pipelineBarrier(self: CommandBuffer, barrier: PipelineBarrier) void {
self.proxy.pipelineBarrier( self.proxy.pipelineBarrier(
barrier.src_stage_mask, barrier.src_stage_mask,

View File

@@ -771,24 +771,7 @@ pub fn deinit(self: *Skybox, engine: *Engine) void {
engine.destroyImage(self.image); engine.destroyImage(self.image);
} }
pub fn bind(self: *const Skybox, command_buffer: CommandBuffer, extent: vk.Extent2D) !void { pub fn draw(self: *const Skybox, command_buffer: CommandBuffer) !void {
command_buffer.setViewport(0, &.{
.{
.x = 0,
.y = 0,
.width = @floatFromInt(extent.width),
.height = @floatFromInt(extent.height),
.min_depth = 0,
.max_depth = 1,
},
});
command_buffer.setScissor(0, &.{
.{
.offset = .{ .x = 0, .y = 0 },
.extent = extent,
},
});
command_buffer.bindPipeline(.graphics, self.pipeline);
try command_buffer.bindVertexBuffers(0, &.{ try command_buffer.bindVertexBuffers(0, &.{
.{ .{
.buffer = self.vertex_buffer.buffer, .buffer = self.vertex_buffer.buffer,
@@ -796,9 +779,8 @@ pub fn bind(self: *const Skybox, command_buffer: CommandBuffer, extent: vk.Exten
}, },
}); });
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16); command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
}
pub fn draw(self: *const Skybox, command_buffer: CommandBuffer) void { command_buffer.bindPipeline(.graphics, self.pipeline);
command_buffer.bindDescriptorSet(.graphics, self.pipeline_layout, 0, self.descriptor_set, null); command_buffer.bindDescriptorSet(.graphics, self.pipeline_layout, 0, self.descriptor_set, null);
command_buffer.drawIndexed(.{ .index_count = 36 }); command_buffer.drawIndexed(.{ .index_count = 36 });
} }

View File

@@ -52,6 +52,7 @@ pub fn init(engine: *Engine) !Swapchain {
}, },
}, },
.subpasses = &.{ .subpasses = &.{
// Main
.{ .{
.pipeline_bind_point = .graphics, .pipeline_bind_point = .graphics,
.color_attachments = &.{ .color_attachments = &.{
@@ -65,6 +66,16 @@ pub fn init(engine: *Engine) !Swapchain {
.layout = .depth_stencil_attachment_optimal, .layout = .depth_stencil_attachment_optimal,
}, },
}, },
// GUI
.{
.pipeline_bind_point = .graphics,
.color_attachments = &.{
.{
.attachment = 0,
.layout = .color_attachment_optimal,
},
},
},
}, },
.dependencies = &.{ .dependencies = &.{
.{ .{
@@ -89,6 +100,25 @@ pub fn init(engine: *Engine) !Swapchain {
.by_region_bit = true, .by_region_bit = true,
}, },
}, },
.{
.src_subpass = 0,
.dst_subpass = 1,
.src_stage_mask = .{
.color_attachment_output_bit = true,
},
.dst_stage_mask = .{
.color_attachment_output_bit = true,
},
.src_access_mask = .{
.color_attachment_write_bit = true,
},
.dst_access_mask = .{
.color_attachment_write_bit = true,
},
.dependency_flags = .{
.by_region_bit = true,
},
},
}, },
}); });
errdefer engine.destroyRenderPass(render_pass); errdefer engine.destroyRenderPass(render_pass);
@@ -129,6 +159,8 @@ pub fn deinit(self: *Swapchain, engine: *Engine) void {
} }
pub fn recreate(self: *Swapchain, engine: *Engine) !void { pub fn recreate(self: *Swapchain, engine: *Engine) !void {
try engine.deviceWaitIdle(); // TODO LMAO
const mode = &engine.mode.surface; const mode = &engine.mode.surface;
const allocator = engine.vk_allocator.allocator; const allocator = engine.vk_allocator.allocator;

View File

@@ -132,7 +132,7 @@ fn freeFunction(
const self: *VkAllocator = @ptrCast(@alignCast(p_user_data.?)); const self: *VkAllocator = @ptrCast(@alignCast(p_user_data.?));
if (maybe_p_memory) |p_memory| { if (maybe_p_memory) |p_memory| {
self.mutex.lockUncancelable(); self.mutex.lockUncancelable(self.io);
defer self.mutex.unlock(self.io); defer self.mutex.unlock(self.io);
const size = self.allocations.fetchRemove(p_memory).?.value; const size = self.allocations.fetchRemove(p_memory).?.value;

View File

@@ -46,6 +46,7 @@ pub const Index = u16;
pub const GlobalUniforms = extern struct { pub const GlobalUniforms = extern struct {
matrixWStoVS: vm.Matrix4x4, matrixWStoVS: vm.Matrix4x4,
matrixVStoCS: vm.Matrix4x4, matrixVStoCS: vm.Matrix4x4,
matrixSSPXtoCS: vm.Matrix3x2,
ambientLight: vm.Vector3, ambientLight: vm.Vector3,
}; };
@@ -96,6 +97,8 @@ pub const ObjectUniforms = extern struct {
}; };
pub const equirect_to_cube_comp_spv align(4) = @embedFile("shaders/equirect_to_cube_comp.spv").*; pub const equirect_to_cube_comp_spv align(4) = @embedFile("shaders/equirect_to_cube_comp.spv").*;
pub const gui_box_vert_spv align(4) = @embedFile("shaders/gui_box_vert.spv").*;
pub const gui_box_frag_spv align(4) = @embedFile("shaders/gui_box_frag.spv").*;
pub const main_vert_spv align(4) = @embedFile("shaders/main_vert.spv").*; pub const main_vert_spv align(4) = @embedFile("shaders/main_vert.spv").*;
pub const main_frag_spv align(4) = @embedFile("shaders/main_frag.spv").*; pub const main_frag_spv align(4) = @embedFile("shaders/main_frag.spv").*;
pub const skybox_vert_spv align(4) = @embedFile("shaders/skybox_vert.spv").*; pub const skybox_vert_spv align(4) = @embedFile("shaders/skybox_vert.spv").*;