feat(render3d): R3D_GFX=vk draws the frame through Vulkan, headless
gpu.ludic's calls branch to the Vulkan backend when it was chosen and came up; every OpenGL statement is unchanged, only guarded. R3D_GFX=vk selects it in a headless run (the window's swapchain is the next milestone) and falls back to OpenGL, with the reason, when the device or the SPIR-V manifest is missing. - Render state is cached as before and turned into pipelines at the draw; u_* and sampler binds go into the variant's uniform blocks; meshes, buffers and textures are gvk_* objects; framebuffer binds are dynamic-rendering passes; same-size blits are image copies; the screen, the photograph read-back, the present and the screenshot go through the frame. - Work that submits on its own (uploads, read-backs, new or freed images and buffers) flushes the frame first, so it runs in OpenGL's order. A read may take fewer channels than the image has (the height field's R from its RGBA32F bake). Pipeline keys name vertex bindings by order, not buffer handle, so re-pointed instance buffers keep their pipeline. The valley renders at frame 90 validation-clean on the RTX 3070 Ti and on MoltenVK. OpenGL frames byte-identical at the five viewpoints; 59 self-tests pass with no GL error. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
451bc9063c
commit
072f9a848e
3 changed files with 290 additions and 73 deletions
|
|
@ -328,7 +328,10 @@ function gvk_tex_mips(tex: int, w: int, h: int) -> bool {
|
|||
function gvk_tex_read(tex: int, ifmt: int, w: int, h: int, fmt: int, ty: int, out: pointer) -> bool {
|
||||
let cout = gvk_channels(ifmt)
|
||||
let bout = gvk_channel_bytes(ifmt)
|
||||
if gvk_gl_channels(fmt) != cout or gvk_gl_type_bytes(ty) != bout {
|
||||
let cwant = gvk_gl_channels(fmt)
|
||||
# a read may ask for fewer channels than the image has (the height field's R of an RGBA32F
|
||||
# bake), never more, and only in the sample size the image stores
|
||||
if cwant > cout or gvk_gl_type_bytes(ty) != bout {
|
||||
print(`r3d: vulkan: no read-back conversion for GL format {ifmt} as {fmt}/{ty}`)
|
||||
return false
|
||||
}
|
||||
|
|
@ -350,7 +353,12 @@ function gvk_tex_read(tex: int, ifmt: int, w: int, h: int, fmt: int, ty: int, ou
|
|||
Vk.cmd_copy_image_to_buffer(cb, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, gvk_st_buf, 1, bic)
|
||||
gvk_barrier(cb, image, depth, 0, 1, 1, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
|
||||
let ok = gvk_once_end(cb)
|
||||
if ok { mem_copy(out, src, n) }
|
||||
if ok and cwant == cout { mem_copy(out, src, n) }
|
||||
if ok and cwant < cout {
|
||||
let texel = cout * bout
|
||||
let keep = cwant * bout
|
||||
for t in 0 .. w * h { mem_copy(mem_off(out, t * keep), mem_off(src, t * texel), keep) }
|
||||
}
|
||||
gvk_staging_free()
|
||||
return ok
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue