From 4959bb13a3df02e0cce3f5ec809709acab281e84 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 16 Aug 2026 16:33:44 +0200 Subject: [PATCH 1/7] Make graphics.SSBO semi-compatible with Vulkan --- src/graphics.zig | 28 ++++++++++++++++++++++------ src/particles.zig | 3 +-- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/graphics.zig b/src/graphics.zig index 9e88593613..588fc25086 100644 --- a/src/graphics.zig +++ b/src/graphics.zig @@ -1386,6 +1386,7 @@ pub const VertexArray = struct { // MARK: VertexArray pub const SSBO = struct { // MARK: SSBO bufferID: c_uint, + buffer: ?vulkan.Buffer = null, pub fn init() SSBO { var self = SSBO{.bufferID = undefined}; c.glGenBuffers(1, &self.bufferID); @@ -1408,7 +1409,22 @@ pub const SSBO = struct { // MARK: SSBO return self; } + pub fn initDynamicSize(comptime T: type, len: usize) SSBO { + var self = SSBO{.bufferID = undefined}; + c.glGenBuffers(1, &self.bufferID); + c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, self.bufferID); + c.glBufferData(c.GL_SHADER_STORAGE_BUFFER, @intCast(len*@sizeOf(T)), null, c.GL_DYNAMIC_DRAW); + c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, 0); + if (main.settings.launchConfig.vulkanTestingMode) { + self.buffer = .init(len*@sizeOf(T), .{.usage = c.VK_BUFFER_USAGE_TRANSFER_DST_BIT | c.VK_BUFFER_USAGE_STORAGE_BUFFER_BIT}); + } + return self; + } + pub fn deinit(self: SSBO) void { + if (self.buffer) |buffer| { + buffer.deferredDeinit(); + } c.glDeleteBuffers(1, &self.bufferID); } @@ -1420,18 +1436,18 @@ pub const SSBO = struct { // MARK: SSBO c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, self.bufferID); c.glBufferData(c.GL_SHADER_STORAGE_BUFFER, @intCast(data.len*@sizeOf(T)), data.ptr, c.GL_STATIC_DRAW); c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, 0); + if (self.buffer) |buffer| { + buffer.uploadData(0, std.mem.sliceAsBytes(data)); + } } pub fn bufferSubData(self: SSBO, comptime T: type, data: []const T, length: usize) void { c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, self.bufferID); c.glBufferSubData(c.GL_SHADER_STORAGE_BUFFER, 0, @intCast(length*@sizeOf(T)), data.ptr); c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, 0); - } - - pub fn createDynamicBuffer(self: SSBO, comptime T: type, size: usize) void { - c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, self.bufferID); - c.glBufferData(c.GL_SHADER_STORAGE_BUFFER, @intCast(size*@sizeOf(T)), null, c.GL_DYNAMIC_DRAW); - c.glBindBuffer(c.GL_SHADER_STORAGE_BUFFER, 0); + if (self.buffer) |buffer| { + buffer.uploadData(0, std.mem.sliceAsBytes(data)); + } } }; diff --git a/src/particles.zig b/src/particles.zig index cc33e6cd0a..e9d82a36a6 100644 --- a/src/particles.zig +++ b/src/particles.zig @@ -194,8 +194,7 @@ pub const ParticleSystem = struct { }, ); - particlesSSBO = SSBO.init(); - particlesSSBO.createDynamicBuffer(Particle, maxCapacity); + particlesSSBO = SSBO.initDynamicSize(Particle, maxCapacity); particlesSSBO.bind(13); } From d4b5ff59925900eae42edfad2e9a1cbe833a1a6e Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 16 Aug 2026 16:35:00 +0200 Subject: [PATCH 2/7] Switch to using push descriptors from the (Vulkan 1.4-core) extension --- src/graphics/pipelines.zig | 1 + src/graphics/vulkan.zig | 1 + 2 files changed, 2 insertions(+) diff --git a/src/graphics/pipelines.zig b/src/graphics/pipelines.zig index 2e79a737fc..22c0430962 100644 --- a/src/graphics/pipelines.zig +++ b/src/graphics/pipelines.zig @@ -707,6 +707,7 @@ pub const Pipeline = struct { // MARK: Pipeline const descriptorSetLayoutInfo = c.VkDescriptorSetLayoutCreateInfo{ .sType = c.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .flags = c.VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR, .bindingCount = @intCast(options.bindings.len), .pBindings = @ptrCast(options.bindings.ptr), }; diff --git a/src/graphics/vulkan.zig b/src/graphics/vulkan.zig index 2405c82b67..0d51ac6e42 100644 --- a/src/graphics/vulkan.zig +++ b/src/graphics/vulkan.zig @@ -273,6 +273,7 @@ pub fn createInstance() void { const deviceExtensions = blk: { const baseDeviceExtensions = [_][*:0]const u8{ c.VK_KHR_SWAPCHAIN_EXTENSION_NAME, + c.VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, }; if (builtin.target.os.tag == .macos) { break :blk baseDeviceExtensions ++ [_][*:0]const u8{c.VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME}; From 6ce2d84bb9fc7e737f0db4f11a8b7946fff3f105 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 16 Aug 2026 16:35:29 +0200 Subject: [PATCH 3/7] Add descriptor binding to the CommandBuffer --- src/graphics/CommandBuffer.zig | 43 ++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/graphics/CommandBuffer.zig b/src/graphics/CommandBuffer.zig index 517cd12701..c9a1f91876 100644 --- a/src/graphics/CommandBuffer.zig +++ b/src/graphics/CommandBuffer.zig @@ -189,6 +189,49 @@ pub fn bindVertexArray(self: CommandBuffer, buffer: main.graphics.VertexArray) v } } +const DescriptorBindPoint = enum(c.VkPipelineBindPoint) { + graphics = c.VK_PIPELINE_BIND_POINT_GRAPHICS, + compute = c.VK_PIPELINE_BIND_POINT_COMPUTE, +}; + +const BindingInfo = union(enum) { + ssbo: struct { + binding: u32, + dynamic: bool = false, + ssbo: main.graphics.SSBO, + offset: usize = 0, + range: usize = c.VK_WHOLE_SIZE, + }, +}; + +pub fn bindDescriptors(self: CommandBuffer, pipeline: main.graphics.Pipeline, bindPoint: enum{ graphics, compute }, set: u32, bindings: []const BindingInfo) void { + const arena = main.stackAllocator.createArena(); + defer main.stackAllocator.destroyArena(arena); + const writeInfo = arena.alloc(c.VkWriteDescriptorSet, bindings.len); + for (0..bindings.len) |i| { + writeInfo[i] = .{ + .sType = c.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstBinding = switch (bindings[i]) { + inline else => |b| b.binding, + }, + .descriptorCount = 1, + }; + switch (bindings[i]) { + .ssbo => |ssbo| { + writeInfo[i].descriptorType = if (ssbo.dynamic) c.VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC else c.VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + const bufferInfo = arena.create(c.VkDescriptorBufferInfo); + bufferInfo.* = .{ + .buffer = ssbo.ssbo.buffer.?.handle, + .offset = ssbo.offset, + .range = ssbo.range, + }; + writeInfo[i].pBufferInfo = bufferInfo; + }, + } + } + c.vkCmdPushDescriptorSetKHR(self.handle, @intFromEnum(bindPoint), pipeline.pipelineLayout, set, @intCast(writeInfo.len), writeInfo.ptr); +} + pub fn pushConstants(self: CommandBuffer, pipeline: main.graphics.Pipeline, constants: anytype) void { c.vkCmdPushConstants(self.handle, pipeline.pipelineLayout, c.VK_SHADER_STAGE_ALL, 0, @sizeOf(@TypeOf(constants.*)), constants); } From 248424cf06b951ffa8ec1c60ee4672397275120c Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 16 Aug 2026 16:36:02 +0200 Subject: [PATCH 4/7] Render the performance_graph with vulkan --- assets/cubyz/shaders/graphics/graph.frag | 11 +++++++++ assets/cubyz/shaders/graphics/graph.vert | 11 +++++++++ src/gui/windows/performance_graph.zig | 30 +++++++++++++++++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/assets/cubyz/shaders/graphics/graph.frag b/assets/cubyz/shaders/graphics/graph.frag index ad1c129b88..24384852b9 100644 --- a/assets/cubyz/shaders/graphics/graph.frag +++ b/assets/cubyz/shaders/graphics/graph.frag @@ -2,7 +2,18 @@ layout(location = 0) out vec4 frag_color; +#ifdef OPEN_GL layout(location = 5) uniform vec3 lineColor; +#else +layout(push_constant, std430) uniform _ { + vec2 start; + vec2 dimension; + vec2 screen; + int points; + int offset; + vec3 lineColor; +}; +#endif void main() { frag_color = vec4(lineColor, 1); diff --git a/assets/cubyz/shaders/graphics/graph.vert b/assets/cubyz/shaders/graphics/graph.vert index 77ebe2a304..08f35280e8 100644 --- a/assets/cubyz/shaders/graphics/graph.vert +++ b/assets/cubyz/shaders/graphics/graph.vert @@ -1,11 +1,22 @@ #version 460 +#ifdef OPEN_GL // in pixel layout(location = 0) uniform vec2 start; layout(location = 1) uniform vec2 dimension; layout(location = 2) uniform vec2 screen; layout(location = 3) uniform int points; layout(location = 4) uniform int offset; +#else +layout(push_constant, std430) uniform _ { + vec2 start; + vec2 dimension; + vec2 screen; + int points; + int offset; + vec3 lineColor; +}; +#endif layout(std430, binding = 5) buffer _data { diff --git a/src/gui/windows/performance_graph.zig b/src/gui/windows/performance_graph.zig index cf0b5e7e3d..1ae42ca754 100644 --- a/src/gui/windows/performance_graph.zig +++ b/src/gui/windows/performance_graph.zig @@ -4,6 +4,7 @@ const main = @import("main"); const graphics = main.graphics; const draw = graphics.draw; const Texture = graphics.Texture; +const vulkan = graphics.vulkan; const Vec2f = main.vec.Vec2f; const c = @import("c"); @@ -40,9 +41,17 @@ var uniforms: struct { offset: c_int, lineColor: c_int, } = undefined; +const Uniforms = extern struct { + start: [2]f32 align(8), + dimension: [2]f32 align(8), + screen: [2]f32 align(8), + points: c_int, + offset: c_int, + lineColor: [3]f32 align(16), +}; pub fn init() void { - ssbo = graphics.SSBO.init(); + ssbo = graphics.SSBO.initDynamicSize(f32, lastFrameTime.len); pipeline = graphics.Pipeline.init( "assets/cubyz/shaders/graphics/graph.vert", "assets/cubyz/shaders/graphics/graph.frag", @@ -50,9 +59,12 @@ pub fn init() void { &uniforms, graphics.VertexArray.EmptyVertex, .{ + .bindings = &.{.ssbo(5, .{.vertex = true})}, .rasterState = .{.cullMode = .none}, .depthStencilState = .{.depthTest = false, .depthWrite = false}, .blendState = .{.attachments = &.{.alphaBlending}, .formats = &.{.swapChain}}, + .inputAssemblyState = .{.topology = .lineStrip}, + .pushConstantSize = @sizeOf(Uniforms), }, ); } @@ -93,4 +105,20 @@ pub fn render() void { ssbo.bufferData(f32, &lastFrameTime); ssbo.bind(5); c.glDrawArrays(c.GL_LINE_STRIP, 0, lastFrameTime.len); + + if (main.settings.launchConfig.vulkanTestingMode) { + vulkan.currentFrame.guiCommands.bindPipeline(pipeline, null); + vulkan.currentFrame.guiCommands.bindDescriptors(pipeline, .graphics, 0, &.{ + .{.ssbo = .{.binding = 5, .ssbo = ssbo}}, + }); + vulkan.currentFrame.guiCommands.pushConstants(pipeline, &Uniforms{ + .start = pos, + .dimension = .{dim[0], draw.setScale(1)}, + .screen = .{@floatFromInt(main.Window.width), @floatFromInt(main.Window.height)}, + .points = lastFrameTime.len, + .offset = index, + .lineColor = .{1, 1, 1}, + }); + vulkan.currentFrame.guiCommands.draw(lastFrameTime.len, 0); + } } From ee08a4776c116cef01dd9e06e5962f4aabe9efc5 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 16 Aug 2026 16:42:50 +0200 Subject: [PATCH 5/7] format --- src/graphics/CommandBuffer.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/graphics/CommandBuffer.zig b/src/graphics/CommandBuffer.zig index c9a1f91876..202bc6c8ac 100644 --- a/src/graphics/CommandBuffer.zig +++ b/src/graphics/CommandBuffer.zig @@ -191,7 +191,7 @@ pub fn bindVertexArray(self: CommandBuffer, buffer: main.graphics.VertexArray) v const DescriptorBindPoint = enum(c.VkPipelineBindPoint) { graphics = c.VK_PIPELINE_BIND_POINT_GRAPHICS, - compute = c.VK_PIPELINE_BIND_POINT_COMPUTE, + compute = c.VK_PIPELINE_BIND_POINT_COMPUTE, }; const BindingInfo = union(enum) { @@ -204,7 +204,7 @@ const BindingInfo = union(enum) { }, }; -pub fn bindDescriptors(self: CommandBuffer, pipeline: main.graphics.Pipeline, bindPoint: enum{ graphics, compute }, set: u32, bindings: []const BindingInfo) void { +pub fn bindDescriptors(self: CommandBuffer, pipeline: main.graphics.Pipeline, bindPoint: enum { graphics, compute }, set: u32, bindings: []const BindingInfo) void { const arena = main.stackAllocator.createArena(); defer main.stackAllocator.destroyArena(arena); const writeInfo = arena.alloc(c.VkWriteDescriptorSet, bindings.len); From bb04c5e9d4c1576bdc697847112c0c1cc57f8129 Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Sun, 16 Aug 2026 16:45:13 +0200 Subject: [PATCH 6/7] lint --- src/graphics/CommandBuffer.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/CommandBuffer.zig b/src/graphics/CommandBuffer.zig index 202bc6c8ac..0935924d87 100644 --- a/src/graphics/CommandBuffer.zig +++ b/src/graphics/CommandBuffer.zig @@ -204,7 +204,7 @@ const BindingInfo = union(enum) { }, }; -pub fn bindDescriptors(self: CommandBuffer, pipeline: main.graphics.Pipeline, bindPoint: enum { graphics, compute }, set: u32, bindings: []const BindingInfo) void { +pub fn bindDescriptors(self: CommandBuffer, pipeline: main.graphics.Pipeline, bindPoint: DescriptorBindPoint, set: u32, bindings: []const BindingInfo) void { const arena = main.stackAllocator.createArena(); defer main.stackAllocator.destroyArena(arena); const writeInfo = arena.alloc(c.VkWriteDescriptorSet, bindings.len); From eda0e57b7466020694bcec1c1b0457d187f7ddeb Mon Sep 17 00:00:00 2001 From: IntegratedQuantum Date: Mon, 17 Aug 2026 07:32:19 +0200 Subject: [PATCH 7/7] Update dependencies --- build.zig.zon | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 63ae963579..ddeddbbcb6 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -9,37 +9,37 @@ .lazy = true, }, .cubyz_deps_headers = .{ - .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/15/cubyz_deps_headers.tar.gz", - .hash = "N-V-__8AAM-mgACe7tD-FszvbiOt6OT20kfflXo0U4W7Ocf2", + .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/16/cubyz_deps_headers.tar.gz", + .hash = "N-V-__8AAGWugADL8wEBCVTt1693f2FFYlTOtARkDPfCA5IV", }, .cubyz_deps_aarch64_macos = .{ - .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/15/cubyz_deps_aarch64-macos-none.tar.gz", - .hash = "N-V-__8AAP4b0AUagCF3rHszwtcDGvqy1nmHFh6NKJEyW_sB", + .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/16/cubyz_deps_aarch64-macos-none.tar.gz", + .hash = "N-V-__8AAI4c0AXTRMQ1oq7SmlzUdOMFrn27lkTCTgLOPbdX", .lazy = true, }, .cubyz_deps_aarch64_linux = .{ - .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/15/cubyz_deps_aarch64-linux-musl.tar.gz", - .hash = "N-V-__8AAGB0CQMn4gzU9hxnpMoYao13RYpAYSgIQaWWWgAw", + .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/16/cubyz_deps_aarch64-linux-musl.tar.gz", + .hash = "N-V-__8AAAp-CQNms25cSzNPSuLeREoJrUMrsDUg_rKVswqD", .lazy = true, }, .cubyz_deps_aarch64_windows = .{ - .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/15/cubyz_deps_aarch64-windows-gnu.tar.gz", - .hash = "N-V-__8AAFIsLAMsvnDrhB3GbIWf_uaF4fiWs2xW4XICDDxC", + .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/16/cubyz_deps_aarch64-windows-gnu.tar.gz", + .hash = "N-V-__8AAFI0LAOW7i-eoOvmZPbP3m_8RjBa0ApOZZVWcmuI", .lazy = true, }, .cubyz_deps_x86_64_macos = .{ - .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/15/cubyz_deps_x86_64-macos-none.tar.gz", - .hash = "N-V-__8AACBhwgXczzGAqEqj60G8q1Z96x0BNBD8J5cbOgBc", + .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/16/cubyz_deps_x86_64-macos-none.tar.gz", + .hash = "N-V-__8AALBhwgWlN6EDwCpwkGloSo4glB2Sy1BlTPp16p6L", .lazy = true, }, .cubyz_deps_x86_64_linux = .{ - .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/15/cubyz_deps_x86_64-linux-musl.tar.gz", - .hash = "N-V-__8AACRdDAP1u3TIi39quNzYPCZXxZfeWtqVwP8cz7k6", + .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/16/cubyz_deps_x86_64-linux-musl.tar.gz", + .hash = "N-V-__8AAP5mDAO07XbYWBftU0_TGnDRdtvLEC4LyjPnEJHU", .lazy = true, }, .cubyz_deps_x86_64_windows = .{ - .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/15/cubyz_deps_x86_64-windows-gnu.tar.gz", - .hash = "N-V-__8AAJCyTQP3paHxSzDuz6tzj_BX7ImSiI6BVWAliH6j", + .url = "https://github.com/PixelGuys/Cubyz-Libs/releases/download/16/cubyz_deps_x86_64-windows-gnu.tar.gz", + .hash = "N-V-__8AAEC6TQMzg397LH97hse_0-Cag-pF0-oUHiCZ_k7m", .lazy = true, }, .cubyz_large_assets = .{