# 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) }