mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
The BC3 encoder's colour half is a four-colour BC1 block (c0 above c1, or every index 0 when they are equal), so a BC1 image of an opaque texture decodes to exactly the texels the BC3 one did. The encoder writes that half alone with its specialization constant BC1 set; its push constants are as before, so the BC3 pipeline is unchanged. Every ASTC texture the CPU provides is made BC3, and its first upload checks its blocks while it copies them into staging: when all decode with alpha 255 (tex_astc.c astc_blocks_opaque, from the block header for all but the endpoint modes with alpha, which are decoded), the entry gets a BC1 image in place of the BC3 one before the decode. Later uploads into a BC1 image check again and go back to BC3 for content with alpha. A large texture's copy and check run on the ASTC decode workers, so its first upload copies faster than before. A check of its own where the texture is made cost 1.7 s of the render thread over a seven-minute teleport tour. On that tour (Kakariko Village, the Graveyard, Death Mountain Trail, Kokiri Forest, Hyrule Field, RX 7900 XT), against BC3 alone in the same batch: the ASTC textures in Hyrule Field at the end 2,568 instead of 3,104 MiB, video memory at its peak 11,814 instead of 12,374 MiB, process commit at its peak 25,539 instead of 26,139 MiB; the first 7,200 frames in 93.7 instead of 101.3 s and the run's slowest 1 % at 24.1 instead of 21.1 fps. --probe-astc checks the header test against a decode of every generated block, the loop, its copy and the worker pool against it, and each BC1 block against the colour half of its BC3 block. NX2NAVI_ASTC_BC1=0 (astc_bc1 = 0) keeps every ASTC texture BC3; the sampling probe NX2NAVI_ASTC_BC_PROBE it replaces is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
82 lines
6.3 KiB
C
82 lines
6.3 KiB
C
// 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 <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#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);
|
|
// 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_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);
|