perf(render3d): Vulkan device memory in blocks, and a shadow map that survives running out of it

- A block sub-allocator: 64 MB blocks per memory type, images and buffers kept apart, first fit with
  alignment, freed ranges merged and empty blocks given back; anything over 16 MB still gets its own
  allocation. The self-tests' second world holds 94 allocations instead of 8735 (the driver's limit
  refused a shadow map before). Camp bench unchanged, 105.3 fps.
- shadow_set_res keeps the size that worked when the card has no memory for the new one, and records
  it in shadow_refused, instead of ending with no shadow map; gpu_tex_ok says whether a texture has an
  image behind it.
- Image barriers skip an image that was never made (a failed allocation used to crash there), and
  R3D_VK_ERRLOG=<file> appends every Vulkan failure line by line, so a crash no longer takes the
  message with it.
- R3D_VK_PROF reports draws asked for and not made, so a layer missing from a frame is never silent.

Validation on (VK_INSTANCE_LAYERS): the game's self-tests 61 OK, 0 errors, on the RTX 3070 Ti.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-15 15:44:21 +03:00
parent 3706920e16
commit 989bdca736
5 changed files with 255 additions and 21 deletions

View file

@ -623,6 +623,12 @@ function gpu_tx_at(tex: int) -> int {
function gpu_bound(kind: int) -> int { if kind == GPU_TEX2D_ARRAY { return gpu_bound_array }; return gpu_bound_2d }
function gpu_tex_new() -> int { if gpu_kind == GPU_VK { return gvk_tex_new() }; return gl_texture() }
# does texture `tex` have an image behind it? Always on OpenGL; on Vulkan an image whose memory could
# not be had is never made, and a caller that can fall back (a smaller shadow map) asks here.
function gpu_tex_ok(tex: int) -> bool {
if gpu_kind != GPU_VK { return tex > 0 }
return tex > 0 and tex < len(gvk_tex_image) and gvk_tex_image[tex] != 0
}
# what GL has on each unit's 2D target, for R3D_GLCHECK: deleting a texture unbinds it everywhere
var gpu_unit_2d: words = null
var gpu_unit_cur: int = 0