// CPU-side texture code: block-linear <-> linear copies, ASTC decode, NVN format -> VkFormat. Vulkan memory and // the texture objects are in vk_memory.c and vk_texture.c. #pragma once #include #include #include #include "nvn_obj.h" #include "nvn_tex.h" #include "vk.h" // ---- tex_deswizzle.c ---- // Block-linear <-> linear for one level and layer of a texture. The linear side is laid out by block rows: dst_pitch // bytes per row (>= row bytes of the level), compressed formats one block row per row, 3D textures slice k at // dst + k * dst_pitch * block rows. LINEAR / LINEAR_RENDER_TARGET storage is copied by pitch. Multisampled and BUFFER // textures return -1; success returns 0. int nvn_deswizzle(const nvn_texdesc *d, unsigned level, unsigned layer, const void *src_storage, void *dst_linear, size_t dst_pitch); int nvn_swizzle(const nvn_texdesc *d, unsigned level, unsigned layer, const void *src_linear, size_t src_pitch, void *dst_storage); // nvn_deswizzle with a large level's block-linear copy split over the par_jobs pool (tex_bl_copy_mt): the same bytes. // For the texture upload, which runs on a drawing thread; the caller keeps the storage mapped until it returns. int nvn_deswizzle_mt(const nvn_texdesc *d, unsigned level, unsigned layer, const void *src_storage, void *dst_linear, size_t dst_pitch); // One box of a level and layer, [x, x + wb) bytes by [y, y + h) block rows of slice z (3D textures), between the storage // and caller rows of pitch bytes, touching nothing else of the level: ReadTexels / WriteTexels of a region cost the // region, not the level. Same textures as nvn_deswizzle; -1 for others and for a box outside the level. int nvn_texels_box(const nvn_texdesc *d, unsigned level, unsigned layer, uint32_t x, uint32_t y, uint32_t z, uint32_t wb, uint32_t h, void *storage, void *rows, size_t pitch, int to_linear); // Byte offset of (x byte, y block row, z slice) inside one level of block height 2^th and block depth 2^td GOBs. uint64_t nvn_bl_offset(uint32_t x, uint32_t y, uint32_t z, uint32_t row_bytes, uint32_t rows, unsigned th, unsigned td); // Geometry of a level as the two functions above use it; -1 for textures they reject. int nvn_deswizzle_geom(const nvn_texdesc *d, unsigned level, unsigned layer, uint32_t *row_bytes, uint32_t *rows, uint32_t *slices, uint64_t *base, unsigned *th, unsigned *td, uint32_t *bpb); // The copy loop on its own, for callers that know the level geometry (bl points at the level's first byte). void tex_bl_copy(uint8_t *bl, uint8_t *lin, size_t pitch, uint32_t row_bytes, uint32_t rows, uint32_t slices, unsigned th, unsigned td, int to_linear); // tex_bl_copy with a level of 1 MiB or more split into bands of rows over the par_jobs pool; the same bytes. void tex_bl_copy_mt(uint8_t *bl, uint8_t *lin, size_t pitch, uint32_t row_bytes, uint32_t rows, uint32_t slices, unsigned th, unsigned td, int to_linear); // ---- tex_astc.c ---- // ASTC LDR 2D to RGBA8, bit-exact with astcenc's 8-bit decode. blocks: row-major 16-byte blocks covering // ceil(width/bw) x ceil(height/bh); rgba_out: width*height*4 bytes. srgb only selects the sRGB endpoint expansion. // Error blocks and HDR content decode to magenta. void astc_decode_ldr(const uint8_t *blocks, uint32_t width, uint32_t height, uint32_t bw, uint32_t bh, bool srgb, uint8_t *rgba_out); bool astc_decode_block(const uint8_t block[16], uint32_t bw, uint32_t bh, bool srgb, uint8_t *rgba_out); // Whether the block decodes to alpha 255 in every texel; mostly from its header, blocks of the endpoint modes with // alpha by a decode (counted in *decoded). bool astc_block_opaque(const uint8_t block[16], uint32_t bw, uint32_t bh, bool srgb, uint32_t *decoded); // The first of the n blocks (16 bytes each) that is not opaque, or that took *decoded past max_decoded; n when none // is. dst (optional): all n blocks are copied there too, as by memcpy, the rest also after a block that is not opaque. uint64_t astc_blocks_opaque(const uint8_t *blocks, uint64_t n, uint32_t bw, uint32_t bh, bool srgb, uint32_t max_decoded, uint32_t *decoded, uint8_t *dst); // tex_astc_mt.c: astc_blocks_opaque with the blocks of a large texture spread over the decode workers, each also // copying its part to dst when given; whether every block is opaque (and *decoded stayed within max_decoded, summed // over the workers). bool astc_blocks_opaque_mt(const uint8_t *blocks, uint64_t n, uint32_t bw, uint32_t bh, bool srgb, uint32_t max_decoded, uint32_t *decoded, uint8_t *dst); // tex_astc_mt.c: the same bytes as astc_decode_ldr, large images split by block rows over a worker pool; blocks. void astc_decode_ldr_mt(const uint8_t *blocks, uint32_t width, uint32_t height, uint32_t bw, uint32_t bh, bool srgb, uint8_t *rgba_out); // ---- vk_formats.c ---- typedef struct TexVkFormat { VkFormat vk; // format of the image created on this GPU VkFormat ideal; // format the NVN format maps to by itself; differs from vk after a fallback VkFormatFeatureFlags need; // optimal-tiling features vk must report for sampling and upload uint8_t expand_rgb; // 3-component format: the upload expands each texel to 4 components (alpha / integer 1) uint8_t alpha_one; // "X" format: sample alpha as 1 (view swizzle) uint8_t chan[4]; // nonzero chan[0]: vk stands in with another component order; chan[i] is the // NVN_TEXTURE_SWIZZLE_R..A selector of the image component holding R, G, B, A uint8_t astc_bw, astc_bh; // nonzero: ASTC decoded into vk (RGBA8, same colour space) by vk_astc.c or tex_astc.c; // zero for native ASTC (vk == ideal, raw blocks as for BC) uint8_t astc_srgb; uint8_t astc_bc; // ASTC decoded and then encoded on the GPU (vk_astc.c): 1 BC3 (NX2NAVI_ASTC_BC), // 2 BC1 for a texture whose every block decodes opaque (vk_texture.c "ASTC as BC1") uint8_t depth, stencil; // aspect flags of depth / stencil formats const char *note; // why a fallback or an expansion was chosen; NULL when the mapping is direct const char *reason; // unmapped formats only: why there is no Vulkan format } TexVkFormat; // 1 when nvn_format (an NVNformat value) has a Vulkan mapping, 0 otherwise (out->reason says why). The mapping is // fixed per device: ASTC decodes to RGBA8 unless vk_astc_native (NX2NAVI_ASTC) takes the format as it is, D24S8 is // D32S8, DEPTH24 is D32. Whether the GPU reports the features is a separate question (tex_vk_format_supported). int tex_vk_format(int nvn_format, TexVkFormat *out); // 1 when vk_ctx()->phys reports every bit of f->need for f->vk in optimal tiling. Needs vk_init(). int tex_vk_format_supported(const TexVkFormat *f);