From 92530c5db7b1117a20a112e16ea3f7fb4f59cb85 Mon Sep 17 00:00:00 2001 From: Orkuncakilkaya Date: Tue, 29 Sep 2026 23:18:05 +0300 Subject: [PATCH] render3d: gpu_tex_read_all and gpu_tex_write_all flush the frame first - the read-back is a submit of its own and took the image before the draws that fill it (the sky bake's BRDF table was all zeros at one width in three) Co-Authored-By: Claude Opus 5.5 --- changes/r3d-readback-flush.md | 6 ++++++ packages/ludic.render3d/gpu_vk_readback.ludic | 6 +++++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 changes/r3d-readback-flush.md diff --git a/changes/r3d-readback-flush.md b/changes/r3d-readback-flush.md new file mode 100644 index 00000000..2a015820 --- /dev/null +++ b/changes/r3d-readback-flush.md @@ -0,0 +1,6 @@ +bump: patch +type: fix +**A bake reads what was drawn.** `gpu_tex_read_all` (every bake's `bake_pack`) copied a texture on a +submit of its own without submitting the frame's draws first, so it read whatever the image held before +them: the sky bake's BRDF table came out all zeros for one light width and right for another, depending on +whether something else had flushed. It flushes first now, and so does `gpu_tex_write_all`. diff --git a/packages/ludic.render3d/gpu_vk_readback.ludic b/packages/ludic.render3d/gpu_vk_readback.ludic index 9b129aaa..9ca57a7c 100644 --- a/packages/ludic.render3d/gpu_vk_readback.ludic +++ b/packages/ludic.render3d/gpu_vk_readback.ludic @@ -36,8 +36,11 @@ function gvk_tex_read_layer(render3d_st: mut Render3dState, tex: int, layer: int return ok } -# every layer's level 0 into `out` (gpu_tex_byte_size bytes), layer after layer +# every layer's level 0 into `out` (gpu_tex_byte_size bytes), layer after layer. The frame so far goes +# first: the copy is a submit of its own, and read before the draws that fill the texture were submitted +# it took whatever the image held - a bake of the sky's BRDF table came out all zeros at one width in three function gpu_tex_read_all(render3d_st: mut Render3dState, tex: int, out: pointer) -> bool { + gvk_flush(render3d_st) let layers = render3d_st.gvk_tex_layers[tex] let per = gpu_tex_byte_size(render3d_st, tex) / max(layers, 1) for l in 0 .. layers { if not gvk_tex_read_layer(render3d_st, tex, l, mem_off(out, l * per)) { return false } } @@ -47,6 +50,7 @@ function gpu_tex_read_all(render3d_st: mut Render3dState, tex: int, out: pointer # level 0 of every layer written from bytes read back by gpu_tex_read_all; the texture's storage must # already be what it was (same format, size and layers). Mips, where it has them, are the caller's function gpu_tex_write_all(render3d_st: mut Render3dState, tex: int, data: pointer) -> bool { + gvk_flush(render3d_st) # after whatever the frame so far drew into it let ifmt = render3d_st.gvk_tex_glfmt[tex] let c = gvk_channels(ifmt) let b = gvk_channel_bytes(ifmt)