1b76e08f
Test partial upload API contract
a73x 2026-04-08 19:40
Commit message
src/renderer.zig
| Old | New | ||
|---|---|---|---|
| @@ -335,6 +335,13 @@ const InstanceRangeWrite = struct { | |||
| 335 | byte_len: vk.DeviceSize, | 335 | byte_len: vk.DeviceSize, |
| 336 | }; | 336 | }; |
| 337 | 337 | ||
| 338 | const InstanceRangeUploadAction = enum { | ||
| 339 | no_op, | ||
| 340 | partial, | ||
| 341 | full, | ||
| 342 | invalid_range, | ||
| 343 | }; | ||
| 344 | |||
| 338 | fn planInstanceUpload(req: InstanceUploadRequest) InstanceUploadDecision { | 345 | fn planInstanceUpload(req: InstanceUploadRequest) InstanceUploadDecision { |
| 339 | const needed_capacity = std.math.add(u32, req.offset_instances, req.write_len) catch { | 346 | const needed_capacity = std.math.add(u32, req.offset_instances, req.write_len) catch { |
| 340 | return .{ | 347 | return .{ |
| @@ -355,6 +362,24 @@ fn planInstanceRangeWrite(offset_instances: u32, len_instances: u32) InstanceRan | |||
| 355 | }; | 362 | }; |
| 356 | } | 363 | } |
| 357 | 364 | ||
| 365 | fn planUploadInstanceRangeAction( | ||
| 366 | current_capacity: u32, | ||
| 367 | offset_instances: u32, | ||
| 368 | len_instances: u32, | ||
| 369 | ) InstanceRangeUploadAction { | ||
| 370 | if (len_instances == 0) return .no_op; | ||
| 371 | |||
| 372 | return switch (planInstanceUpload(.{ | ||
| 373 | .current_capacity = current_capacity, | ||
| 374 | .offset_instances = offset_instances, | ||
| 375 | .write_len = len_instances, | ||
| 376 | }).upload_mode) { | ||
| 377 | .partial => .partial, | ||
| 378 | .full => .full, | ||
| 379 | .invalid_range => .invalid_range, | ||
| 380 | }; | ||
| 381 | } | ||
| 382 | |||
| 358 | fn writeInstanceRange( | 383 | fn writeInstanceRange( |
| 359 | target: []Instance, | 384 | target: []Instance, |
| 360 | offset_instances: u32, | 385 | offset_instances: u32, |
| @@ -1265,16 +1290,15 @@ pub const Context = struct { | |||
| 1265 | offset_instances: u32, | 1290 | offset_instances: u32, |
| 1266 | instances: []const Instance, | 1291 | instances: []const Instance, |
| 1267 | ) !bool { | 1292 | ) !bool { |
| 1268 | if (instances.len == 0) return false; | 1293 | const action = planUploadInstanceRangeAction( |
| 1269 | 1294 | self.instance_capacity, | |
| 1270 | const decision = planInstanceUpload(.{ | 1295 | offset_instances, |
| 1271 | .current_capacity = self.instance_capacity, | 1296 | std.math.cast(u32, instances.len) orelse return error.InvalidInstanceRange, |
| 1272 | .offset_instances = offset_instances, | 1297 | ); |
| 1273 | .write_len = std.math.cast(u32, instances.len) orelse return error.InvalidInstanceRange, | 1298 | switch (action) { |
| 1274 | }); | 1299 | .no_op => return false, |
| 1275 | switch (decision.upload_mode) { | ||
| 1276 | .invalid_range => return error.InvalidInstanceRange, | ||
| 1277 | .full => return true, | 1300 | .full => return true, |
| 1301 | .invalid_range => return error.InvalidInstanceRange, | ||
| 1278 | .partial => {}, | 1302 | .partial => {}, |
| 1279 | } | 1303 | } |
| 1280 | 1304 | ||
| @@ -1575,3 +1599,23 @@ test "writeInstanceRange rejects overflowing ranges" { | |||
| 1575 | writeInstanceRange(target[0..], std.math.maxInt(u32), replacement[0..]), | 1599 | writeInstanceRange(target[0..], std.math.maxInt(u32), replacement[0..]), |
| 1576 | ); | 1600 | ); |
| 1577 | } | 1601 | } |
| 1602 | |||
| 1603 | test "uploadInstanceRange contract treats zero-length writes as a no-op" { | ||
| 1604 | const action = planUploadInstanceRangeAction(4, 99, 0); | ||
| 1605 | try std.testing.expectEqual(InstanceRangeUploadAction.no_op, action); | ||
| 1606 | } | ||
| 1607 | |||
| 1608 | test "uploadInstanceRange contract reports partial writes when capacity fits" { | ||
| 1609 | const action = planUploadInstanceRangeAction(8, 3, 2); | ||
| 1610 | try std.testing.expectEqual(InstanceRangeUploadAction.partial, action); | ||
| 1611 | } | ||
| 1612 | |||
| 1613 | test "uploadInstanceRange contract reports full-upload fallback on growth" { | ||
| 1614 | const action = planUploadInstanceRangeAction(4, 3, 2); | ||
| 1615 | try std.testing.expectEqual(InstanceRangeUploadAction.full, action); | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | test "uploadInstanceRange contract reports invalid ranges explicitly" { | ||
| 1619 | const action = planUploadInstanceRangeAction(std.math.maxInt(u32), std.math.maxInt(u32), 1); | ||
| 1620 | try std.testing.expectEqual(InstanceRangeUploadAction.invalid_range, action); | ||
| 1621 | } | ||