2fd9a6ab
Fix partial upload fallback contract
a73x 2026-04-08 19:38
diff --git a/src/renderer.zig b/src/renderer.zig index 64f5ece..4e66c13 100644 --- a/src/renderer.zig +++ b/src/renderer.zig @@ -359,19 +359,23 @@ fn writeInstanceRange( target: []Instance, offset_instances: u32, instances: []const Instance, ) !void { ) !bool { if (instances.len == 0) return false; const decision = planInstanceUpload(.{ .current_capacity = std.math.cast(u32, target.len) orelse return error.InvalidInstanceRange, .offset_instances = offset_instances, .write_len = std.math.cast(u32, instances.len) orelse return error.InvalidInstanceRange, }); switch (decision.upload_mode) { .invalid_range, .full => return error.InvalidInstanceRange, .invalid_range => return error.InvalidInstanceRange, .full => return true, .partial => {}, } const offset: usize = @intCast(offset_instances); @memcpy(target[offset .. offset + instances.len], instances); return false; } fn swapchainNeedsRebuild(result: vk.Result) bool { @@ -1261,6 +1265,8 @@ pub const Context = struct { offset_instances: u32, instances: []const Instance, ) !bool { if (instances.len == 0) return false; const decision = planInstanceUpload(.{ .current_capacity = self.instance_capacity, .offset_instances = offset_instances, @@ -1272,8 +1278,6 @@ pub const Context = struct { .partial => {}, } if (instances.len == 0) return false; const range = planInstanceRangeWrite(offset_instances, @intCast(instances.len)); const mapped = try self.vkd.mapMemory( self.device, @@ -1524,7 +1528,7 @@ test "writeInstanceRange overwrites only the requested window" { testInstance(120), }; try writeInstanceRange(target[0..], 1, replacement[0..]); try std.testing.expect(!(try writeInstanceRange(target[0..], 1, replacement[0..]))); try std.testing.expectEqualDeep(testInstance(0), target[0]); try std.testing.expectEqualDeep(testInstance(100), target[1]); @@ -1532,7 +1536,7 @@ test "writeInstanceRange overwrites only the requested window" { try std.testing.expectEqualDeep(testInstance(60), target[3]); } test "writeInstanceRange rejects writes past the backing slice" { test "writeInstanceRange reports full-upload fallback when capacity is too small" { var target = [_]Instance{ testInstance(0), testInstance(20), @@ -1542,8 +1546,32 @@ test "writeInstanceRange rejects writes past the backing slice" { testInstance(120), }; try std.testing.expect(try writeInstanceRange(target[0..], 1, replacement[0..])); try std.testing.expectEqualDeep(testInstance(0), target[0]); try std.testing.expectEqualDeep(testInstance(20), target[1]); } test "writeInstanceRange treats zero-length writes as a no-op without fallback" { var target = [_]Instance{ testInstance(0), testInstance(20), }; const empty = [_]Instance{}; try std.testing.expect(!(try writeInstanceRange(target[0..], 99, empty[0..]))); try std.testing.expectEqualDeep(testInstance(0), target[0]); try std.testing.expectEqualDeep(testInstance(20), target[1]); } test "writeInstanceRange rejects overflowing ranges" { var target = [_]Instance{ testInstance(0), testInstance(20), }; const replacement = [_]Instance{testInstance(100)}; try std.testing.expectError( error.InvalidInstanceRange, writeInstanceRange(target[0..], 1, replacement[0..]), writeInstanceRange(target[0..], std.math.maxInt(u32), replacement[0..]), ); }