blob: 61b2cc8960b460ced23db3c4c36663ad3da1c420 [file] [edit]
/*
* Copyright 2026 Rive
*/
#ifndef _RIVE_DECODE_KTX2_HPP_
#define _RIVE_DECODE_KTX2_HPP_
#include "rive/gpu_texture_format.hpp"
#include <cstddef>
#include <cstdint>
#include <vector>
namespace rive
{
// HW support flags for the formats KTX2 may contain. When a format is not
// supported by the backend, DecodeKtx2 will software-decode mip 0 to RGBA8
// (if the corresponding RIVE_*_DECODER family was compiled in) and store
// the result in `blocks` with `format = rgba32`.
// Defaults assume the caller's backend natively supports every GPU
// compressed format we recognise. Callers that have actually queried HW
// caps should set the relevant booleans to false to opt the parser into
// the software-decode fallback. Tests + parser-only consumers can use the
// defaults to keep the original "pass blocks through verbatim" behavior.
struct Ktx2HwSupport
{
bool bc = true;
bool astc = true;
bool etc2 = true;
};
// Result of parsing a KTX2 container. Block data is held in a contiguous
// owned buffer, level 0 first (largest), then level 1, … level N-1
// (smallest). Each level's region is exactly its block-grid size in bytes
// (no inter-level padding).
//
// If `softwareDecoded` is true, the GPU format in the container was not
// supported by the caller's backend and mip 0 was decoded to RGBA8. In that
// case `format == rgba32`, `levelCount == 1`, and `blocks` holds tightly
// packed RGBA8 pixels.
struct Ktx2DecodeResult
{
GPUTextureFormat format;
uint32_t pixelWidth; // logical mip 0 width
uint32_t pixelHeight; // logical mip 0 height
uint32_t levelCount; // number of mip levels stored (>=1)
uint8_t blockWidth = 4; // compressed block footprint width (1 for rgba32)
uint8_t blockHeight = 4; // compressed block footprint height (1 for rgba32)
bool srgb = false; // sRGB colour space (BC7_SRGB / ASTC_SRGB)
std::vector<uint8_t> blocks;
bool softwareDecoded = false;
};
// Parses a KTX2 container. Returns true on success and fills `out`. Returns
// false (with a stderr log) on:
// - bad magic, truncated header / level index
// - unsupported vkFormat (today: only BC7 UNORM/SRGB)
// - non-NONE supercompressionScheme
// - cubemaps / array layers
// - oversized dimensions or level count
// - level data outside the buffer
//
// `hwSupport` is consulted after parsing to decide whether to fall back to
// CPU decompression. Pass all-true to skip the fallback path entirely.
bool DecodeKtx2(const uint8_t* bytes,
size_t byteCount,
Ktx2DecodeResult& out,
const Ktx2HwSupport& hwSupport = {});
} // namespace rive
#endif