ludic/packages/ludic.render3d/gpu_vk_readback.ludic

65 lines
3.8 KiB
Text

# gpu_vk_readback.ludic — a texture's level 0, every layer, read back as the bytes it stores, and put back
# from them: what a build-time bake keeps of a texture the renderer made (bake_parts.ludic).
# the bytes a texture's level 0 takes, every layer, in the format it is stored in
function gpu_tex_byte_size(render3d_st: Render3dState, tex: int) -> int {
let ifmt = render3d_st.gvk_tex_glfmt[tex]
return render3d_st.gvk_tex_dims_w[tex] * render3d_st.gvk_tex_dims_h[tex] * render3d_st.gvk_tex_layers[tex] * gvk_channels(ifmt) * gvk_channel_bytes(ifmt)
}
# level 0 of layer `layer` into `out` (w * h * channels * bytes), as stored
function gvk_tex_read_layer(render3d_st: mut Render3dState, tex: int, layer: int, out: pointer) -> bool {
let ifmt = render3d_st.gvk_tex_glfmt[tex]
let w = render3d_st.gvk_tex_dims_w[tex]
let h = render3d_st.gvk_tex_dims_h[tex]
let layers = render3d_st.gvk_tex_layers[tex]
let n = w * h * gvk_channels(ifmt) * gvk_channel_bytes(ifmt)
let src = gvk_staging(render3d_st, n, VK_BUFFER_USAGE_TRANSFER_DST_BIT)
if src == null { return false }
let image = render3d_st.gvk_tex_image[tex]
let levels = render3d_st.gvk_tex_levels[tex]
let cb = gvk_once_begin(render3d_st)
gvk_barrier(render3d_st, cb, image, false, 0, levels, layers, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
let bic = gvk_tmp(render3d_st, VkBufferImageCopy_sizeof)
Vk.zero(bic, VkBufferImageCopy_sizeof)
Vk.put_i32(bic, VkBufferImageCopy_imageSubresource + VkImageSubresourceLayers_aspectMask, VK_IMAGE_ASPECT_COLOR_BIT)
Vk.put_i32(bic, VkBufferImageCopy_imageSubresource + VkImageSubresourceLayers_baseArrayLayer, layer)
Vk.put_i32(bic, VkBufferImageCopy_imageSubresource + VkImageSubresourceLayers_layerCount, 1)
Vk.put_i32(bic, VkBufferImageCopy_imageExtent + VkExtent3D_width, w)
Vk.put_i32(bic, VkBufferImageCopy_imageExtent + VkExtent3D_height, h)
Vk.put_i32(bic, VkBufferImageCopy_imageExtent + VkExtent3D_depth, 1)
Vk.cmd_copy_image_to_buffer(cb, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, render3d_st.gvk_st_buf, 1, bic)
gvk_barrier(render3d_st, cb, image, false, 0, levels, layers, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
let ok = gvk_once_end(render3d_st, cb)
if ok { mem_copy(out, src, n) }
gvk_staging_free(render3d_st)
return ok
}
# 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 } }
return true
}
# 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)
var fmt = GL_RGBA
if c == 1 { fmt = GL_RED }
if c == 2 { fmt = GL_RG }
if c == 3 { fmt = GL_RGB }
var ty = GL_UNSIGNED_BYTE
if b == 2 { ty = GL_HALF_FLOAT }
if b == 4 { ty = GL_FLOAT }
return gvk_tex_upload(render3d_st, tex, ifmt, render3d_st.gvk_tex_dims_w[tex], render3d_st.gvk_tex_dims_h[tex], render3d_st.gvk_tex_layers[tex], fmt, ty, data)
}