a73x

55523c50

Fix renderer merge blockers

a73x   2026-04-08 15:29

Commit message
Fix renderer merge blockers

src/renderer.zig
Old New
@@ -91,6 +91,7 @@ fn createSwapchain(
91 device: vk.Device, 91 device: vk.Device,
92 width: u32, 92 width: u32,
93 height: u32, 93 height: u32,
94 old_swapchain: vk.SwapchainKHR,
94 ) !SwapchainResult { 95 ) !SwapchainResult {
95 const caps = try vki.getPhysicalDeviceSurfaceCapabilitiesKHR(pd_info.physical, surface); 96 const caps = try vki.getPhysicalDeviceSurfaceCapabilitiesKHR(pd_info.physical, surface);
96 97
@@ -154,6 +155,7 @@ fn createSwapchain(
154 .composite_alpha = .{ .opaque_bit_khr = true }, 155 .composite_alpha = .{ .opaque_bit_khr = true },
155 .present_mode = present_mode, 156 .present_mode = present_mode,
156 .clipped = .true, 157 .clipped = .true,
158 .old_swapchain = old_swapchain,
157 }, null); 159 }, null);
158 160
159 var sc_count: u32 = 0; 161 var sc_count: u32 = 0;
@@ -303,6 +305,14 @@ fn findMemoryType(
303 return error.NoSuitableMemoryType; 305 return error.NoSuitableMemoryType;
304 } 306 }
305 307
308 fn nextInstanceCapacity(current: u32, needed: u32) u32 {
309 var capacity = @max(current, 1);
310 while (capacity < needed) {
311 capacity = std.math.mul(u32, capacity, 2) catch return needed;
312 }
313 return capacity;
314 }
315
306 pub const Context = struct { 316 pub const Context = struct {
307 alloc: std.mem.Allocator, 317 alloc: std.mem.Allocator,
308 vkb: vk.BaseWrapper, 318 vkb: vk.BaseWrapper,
@@ -433,7 +443,7 @@ pub const Context = struct {
433 const present_queue = vkd.getDeviceQueue(device, pd_info.present_queue_family, 0); 443 const present_queue = vkd.getDeviceQueue(device, pd_info.present_queue_family, 0);
434 444
435 // Create swapchain 445 // Create swapchain
436 const sc = try createSwapchain(alloc, vki, vkd, pd_info, surface, device, width, height); 446 const sc = try createSwapchain(alloc, vki, vkd, pd_info, surface, device, width, height, .null_handle);
437 errdefer { 447 errdefer {
438 for (sc.image_views) |view| vkd.destroyImageView(device, view, null); 448 for (sc.image_views) |view| vkd.destroyImageView(device, view, null);
439 alloc.free(sc.image_views); 449 alloc.free(sc.image_views);
@@ -898,8 +908,6 @@ pub const Context = struct {
898 } 908 }
899 909
900 pub fn recreateSwapchain(self: *Context, width: u32, height: u32) !void { 910 pub fn recreateSwapchain(self: *Context, width: u32, height: u32) !void {
901 self.destroySwapchainResources();
902
903 const sc = try createSwapchain( 911 const sc = try createSwapchain(
904 self.alloc, 912 self.alloc,
905 self.vki, 913 self.vki,
@@ -913,6 +921,7 @@ pub const Context = struct {
913 self.device, 921 self.device,
914 width, 922 width,
915 height, 923 height,
924 self.swapchain,
916 ); 925 );
917 errdefer { 926 errdefer {
918 for (sc.image_views) |view| self.vkd.destroyImageView(self.device, view, null); 927 for (sc.image_views) |view| self.vkd.destroyImageView(self.device, view, null);
@@ -934,12 +943,50 @@ pub const Context = struct {
934 self.alloc.free(framebuffers); 943 self.alloc.free(framebuffers);
935 } 944 }
936 945
946 const old_swapchain = self.swapchain;
947 const old_images = self.swapchain_images;
948 const old_image_views = self.swapchain_image_views;
949 const old_framebuffers = self.framebuffers;
950
937 self.swapchain = sc.swapchain; 951 self.swapchain = sc.swapchain;
938 self.swapchain_format = sc.format; 952 self.swapchain_format = sc.format;
939 self.swapchain_extent = sc.extent; 953 self.swapchain_extent = sc.extent;
940 self.swapchain_images = sc.images; 954 self.swapchain_images = sc.images;
941 self.swapchain_image_views = sc.image_views; 955 self.swapchain_image_views = sc.image_views;
942 self.framebuffers = framebuffers; 956 self.framebuffers = framebuffers;
957
958 for (old_framebuffers) |fb| self.vkd.destroyFramebuffer(self.device, fb, null);
959 self.alloc.free(old_framebuffers);
960
961 for (old_image_views) |view| self.vkd.destroyImageView(self.device, view, null);
962 self.alloc.free(old_image_views);
963 self.alloc.free(old_images);
964 self.vkd.destroySwapchainKHR(self.device, old_swapchain, null);
965 }
966
967 fn ensureInstanceCapacity(self: *Context, needed: u32) !void {
968 if (needed <= self.instance_capacity) return;
969
970 const new_capacity = nextInstanceCapacity(self.instance_capacity, needed);
971 const replacement = try createHostVisibleBuffer(
972 self.vki,
973 self.physical_device,
974 self.vkd,
975 self.device,
976 @as(vk.DeviceSize, @sizeOf(Instance)) * new_capacity,
977 .{ .vertex_buffer_bit = true },
978 );
979 errdefer {
980 self.vkd.destroyBuffer(self.device, replacement.buffer, null);
981 self.vkd.freeMemory(self.device, replacement.memory, null);
982 }
983
984 _ = try self.vkd.deviceWaitIdle(self.device);
985 self.vkd.destroyBuffer(self.device, self.instance_buffer, null);
986 self.vkd.freeMemory(self.device, self.instance_memory, null);
987 self.instance_buffer = replacement.buffer;
988 self.instance_memory = replacement.memory;
989 self.instance_capacity = new_capacity;
943 } 990 }
944 991
945 /// Record a command buffer that begins the render pass with the given clear color and presents. 992 /// Record a command buffer that begins the render pass with the given clear color and presents.
@@ -1127,7 +1174,7 @@ pub const Context = struct {
1127 1174
1128 /// Map the instance buffer, copy instances in, unmap. 1175 /// Map the instance buffer, copy instances in, unmap.
1129 pub fn uploadInstances(self: *Context, instances: []const Instance) !void { 1176 pub fn uploadInstances(self: *Context, instances: []const Instance) !void {
1130 if (instances.len > self.instance_capacity) return error.TooManyInstances; 1177 try self.ensureInstanceCapacity(@intCast(instances.len));
1131 const size: vk.DeviceSize = @sizeOf(Instance) * instances.len; 1178 const size: vk.DeviceSize = @sizeOf(Instance) * instances.len;
1132 const mapped = try self.vkd.mapMemory(self.device, self.instance_memory, 0, size, .{}); 1179 const mapped = try self.vkd.mapMemory(self.device, self.instance_memory, 0, size, .{});
1133 @memcpy(@as([*]Instance, @ptrCast(@alignCast(mapped)))[0..instances.len], instances); 1180 @memcpy(@as([*]Instance, @ptrCast(@alignCast(mapped)))[0..instances.len], instances);
@@ -1135,7 +1182,12 @@ pub const Context = struct {
1135 } 1182 }
1136 1183
1137 /// Full draw pass: bind pipeline, push constants, vertex + instance buffers, draw, present. 1184 /// Full draw pass: bind pipeline, push constants, vertex + instance buffers, draw, present.
1138 pub fn drawCells(self: *Context, instance_count: u32, cell_size: [2]f32) !void { 1185 pub fn drawCells(
1186 self: *Context,
1187 instance_count: u32,
1188 cell_size: [2]f32,
1189 clear_color: [4]f32,
1190 ) !void {
1139 // Wait for previous frame to finish 1191 // Wait for previous frame to finish
1140 _ = try self.vkd.waitForFences(self.device, 1, @ptrCast(&self.in_flight_fence), .true, std.math.maxInt(u64)); 1192 _ = try self.vkd.waitForFences(self.device, 1, @ptrCast(&self.in_flight_fence), .true, std.math.maxInt(u64));
1141 try self.vkd.resetFences(self.device, 1, @ptrCast(&self.in_flight_fence)); 1193 try self.vkd.resetFences(self.device, 1, @ptrCast(&self.in_flight_fence));
@@ -1156,9 +1208,7 @@ pub const Context = struct {
1156 .flags = .{ .one_time_submit_bit = true }, 1208 .flags = .{ .one_time_submit_bit = true },
1157 }); 1209 });
1158 1210
1159 const clear_value = vk.ClearValue{ 1211 const clear_value = vk.ClearValue{ .color = .{ .float_32 = clear_color } };
1160 .color = .{ .float_32 = .{ 0.08, 0.08, 0.08, 1.0 } },
1161 };
1162 1212
1163 self.vkd.cmdBeginRenderPass(self.command_buffer, &vk.RenderPassBeginInfo{ 1213 self.vkd.cmdBeginRenderPass(self.command_buffer, &vk.RenderPassBeginInfo{
1164 .render_pass = self.render_pass, 1214 .render_pass = self.render_pass,
@@ -1264,3 +1314,9 @@ test "shaders are embedded with SPIR-V magic" {
1264 const magic2: u32 = std.mem.readInt(u32, cell_frag_spv[0..4], .little); 1314 const magic2: u32 = std.mem.readInt(u32, cell_frag_spv[0..4], .little);
1265 try std.testing.expectEqual(@as(u32, 0x07230203), magic2); 1315 try std.testing.expectEqual(@as(u32, 0x07230203), magic2);
1266 } 1316 }
1317
1318 test "nextInstanceCapacity grows geometrically" {
1319 try std.testing.expectEqual(@as(u32, 16_000), nextInstanceCapacity(16_000, 8_000));
1320 try std.testing.expectEqual(@as(u32, 32_000), nextInstanceCapacity(16_000, 16_001));
1321 try std.testing.expectEqual(@as(u32, 4), nextInstanceCapacity(1, 3));
1322 }