feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

View file

@ -1,5 +1,5 @@
// basisu.h
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -117,13 +117,26 @@ namespace basisu
typedef basisu::vector<uint64_t> uint64_vec;
typedef basisu::vector<int> int_vec;
typedef basisu::vector<bool> bool_vec;
typedef basisu::vector<float> float_vec;
void enable_debug_printf(bool enabled);
void debug_printf(const char *pFmt, ...);
#ifndef __EMSCRIPTEN__
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
#endif
template <typename T> inline void clear_obj(T& obj) { memset(&obj, 0, sizeof(obj)); }
#ifndef __EMSCRIPTEN__
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#endif
template <typename T0, typename T1> inline T0 lerp(T0 a, T0 b, T1 c) { return a + (b - a) * c; }
template <typename S> inline S maximum(S a, S b) { return (a > b) ? a : b; }
@ -162,10 +175,45 @@ namespace basisu
template<typename T> inline T open_range_check(T v, T minv, T maxv) { assert(v >= minv && v < maxv); BASISU_NOTE_UNUSED(minv); BASISU_NOTE_UNUSED(maxv); return v; }
template<typename T> inline T open_range_check(T v, T maxv) { assert(v < maxv); BASISU_NOTE_UNUSED(maxv); return v; }
// Open interval
inline bool in_bounds(int v, int l, int h)
{
return (v >= l) && (v < h);
}
// Closed interval
inline bool in_range(int v, int l, int h)
{
return (v >= l) && (v <= h);
}
inline uint32_t total_bits(uint32_t v) { uint32_t l = 0; for ( ; v > 0U; ++l) v >>= 1; return l; }
template<typename T> inline T saturate(T val) { return clamp(val, 0.0f, 1.0f); }
inline uint32_t get_bit(uint32_t src, int ndx)
{
assert(in_bounds(ndx, 0, 32));
return (src >> ndx) & 1;
}
inline bool is_bit_set(uint32_t src, int ndx)
{
return get_bit(src, ndx) != 0;
}
inline uint32_t get_bits(uint32_t val, int low, int high)
{
const int num_bits = (high - low) + 1;
assert(in_range(num_bits, 1, 32));
val >>= low;
if (num_bits != 32)
val &= ((1u << num_bits) - 1);
return val;
}
template<typename T, typename R> inline void append_vector(T &vec, const R *pObjs, size_t n)
{
if (n)
@ -267,6 +315,11 @@ namespace basisu
return true;
}
static inline uint32_t read_le_word(const uint8_t* pBytes)
{
return (pBytes[1] << 8U) | (pBytes[0]);
}
static inline uint32_t read_le_dword(const uint8_t *pBytes)
{
return (pBytes[3] << 24U) | (pBytes[2] << 16U) | (pBytes[1] << 8U) | (pBytes[0]);
@ -303,6 +356,10 @@ namespace basisu
return *this;
}
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#endif
inline operator uint32_t() const
{
switch (NumBytes)
@ -354,6 +411,9 @@ namespace basisu
}
}
}
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
};
enum eZero { cZero };
@ -402,8 +462,11 @@ namespace basisu
cBC3, // DXT5 (BC4/DXT5A block followed by a BC1/DXT1 block)
cBC4, // DXT5A
cBC5, // 3DC/DXN (two BC4/DXT5A blocks)
cBC6HSigned, // HDR
cBC6HUnsigned, // HDR
cBC7,
cASTC4x4, // LDR only
cASTC_LDR_4x4, // ASTC 4x4 LDR only
cASTC_HDR_4x4, // ASTC 4x4 HDR only (but may use LDR ASTC blocks internally)
cPVRTC1_4_RGB,
cPVRTC1_4_RGBA,
cATC_RGB,
@ -413,17 +476,22 @@ namespace basisu
cETC2_R11_EAC,
cETC2_RG11_EAC,
cUASTC4x4,
cUASTC_HDR_4x4,
cBC1_NV,
cBC1_AMD,
// Uncompressed/raw pixels
cRGBA32,
cRGB565,
cBGR565,
cRGBA4444,
cABGR4444
cABGR4444,
cRGBA_HALF,
cRGB_HALF,
cRGB_9E5
};
// This is bytes per block for GPU formats, or bytes per texel for uncompressed formats.
inline uint32_t get_bytes_per_block(texture_format fmt)
{
switch (fmt)
@ -443,13 +511,27 @@ namespace basisu
case texture_format::cETC2_R11_EAC:
return 8;
case texture_format::cRGBA32:
return sizeof(uint32_t) * 16;
case texture_format::cRGB_9E5:
return sizeof(uint32_t);
case texture_format::cRGB_HALF:
return sizeof(uint16_t) * 3;
case texture_format::cRGBA_HALF:
return sizeof(uint16_t) * 4;
case texture_format::cRGB565:
case texture_format::cBGR565:
case texture_format::cRGBA4444:
case texture_format::cABGR4444:
return sizeof(uint16_t);
default:
break;
}
// Everything else is 16 bytes/block.
return 16;
}
// This is qwords per block for GPU formats, or not valid for uncompressed formats.
inline uint32_t get_qwords_per_block(texture_format fmt)
{
return get_bytes_per_block(fmt) >> 3;
@ -473,6 +555,17 @@ namespace basisu
BASISU_NOTE_UNUSED(fmt);
return 4;
}
inline bool is_hdr_texture_format(texture_format fmt)
{
if (fmt == texture_format::cASTC_HDR_4x4)
return true;
if (fmt == texture_format::cUASTC_HDR_4x4)
return true;
if ((fmt == texture_format::cBC6HSigned) || (fmt == texture_format::cBC6HUnsigned))
return true;
return false;
}
} // namespace basisu

View file

@ -0,0 +1,102 @@
// File: basisu_astc_hdr_core.h
#pragma once
#include "basisu_astc_helpers.h"
namespace basist
{
struct astc_blk
{
uint8_t m_vals[16];
};
// ASTC_HDR_MAX_VAL is the maximum color component value that can be encoded.
// If the input has values higher than this, they need to be linearly scaled so all values are between [0,ASTC_HDR_MAX_VAL], and the linear scaling inverted in the shader.
const float ASTC_HDR_MAX_VAL = 65216.0f; // actually MAX_QLOG12_VAL
// Maximum usable QLOG encodings, and their floating point equivalent values, that don't result in NaN/Inf's.
const uint32_t MAX_QLOG7 = 123;
//const float MAX_QLOG7_VAL = 55296.0f;
const uint32_t MAX_QLOG8 = 247;
//const float MAX_QLOG8_VAL = 60416.0f;
const uint32_t MAX_QLOG9 = 495;
//const float MAX_QLOG9_VAL = 62976.0f;
const uint32_t MAX_QLOG10 = 991;
//const float MAX_QLOG10_VAL = 64256.0f;
const uint32_t MAX_QLOG11 = 1983;
//const float MAX_QLOG11_VAL = 64896.0f;
const uint32_t MAX_QLOG12 = 3967;
//const float MAX_QLOG12_VAL = 65216.0f;
const uint32_t MAX_QLOG16 = 63487;
const float MAX_QLOG16_VAL = 65504.0f;
const uint32_t NUM_MODE11_ENDPOINTS = 6, NUM_MODE7_ENDPOINTS = 4;
// Notes:
// qlog16_to_half(half_to_qlog16(half_val_as_int)) == half_val_as_int (is lossless)
// However, this is not lossless in the general sense.
inline half_float qlog16_to_half_slow(uint32_t qlog16)
{
assert(qlog16 <= 0xFFFF);
int C = qlog16;
int E = (C & 0xF800) >> 11;
int M = C & 0x7FF;
int Mt;
if (M < 512)
Mt = 3 * M;
else if (M >= 1536)
Mt = 5 * M - 2048;
else
Mt = 4 * M - 512;
int Cf = (E << 10) + (Mt >> 3);
return (half_float)Cf;
}
// This is not lossless
inline half_float qlog_to_half_slow(uint32_t qlog, uint32_t bits)
{
assert((bits >= 7U) && (bits <= 16U));
assert(qlog < (1U << bits));
int C = qlog << (16 - bits);
return qlog16_to_half_slow(C);
}
void astc_hdr_core_init();
void decode_mode7_to_qlog12_ise20(
const uint8_t* pEndpoints,
int e[2][3],
int* pScale);
bool decode_mode7_to_qlog12(
const uint8_t* pEndpoints,
int e[2][3],
int* pScale,
uint32_t ise_endpoint_range);
void decode_mode11_to_qlog12_ise20(
const uint8_t* pEndpoints,
int e[2][3]);
bool decode_mode11_to_qlog12(
const uint8_t* pEndpoints,
int e[2][3],
uint32_t ise_endpoint_range);
bool transcode_bc6h_1subset(half_float h_e[3][2], const astc_helpers::log_astc_block& best_blk, bc6h_block& transcoded_bc6h_blk);
bool transcode_bc6h_2subsets(uint32_t common_part_index, const astc_helpers::log_astc_block& best_blk, bc6h_block& transcoded_bc6h_blk);
bool astc_hdr_transcode_to_bc6h(const astc_blk& src_blk, bc6h_block& dst_blk);
bool astc_hdr_transcode_to_bc6h(const astc_helpers::log_astc_block& log_blk, bc6h_block& dst_blk);
} // namespace basist

File diff suppressed because it is too large Load diff

View file

@ -188,8 +188,9 @@ namespace basisu
#define BASISU_IS_SCALAR_TYPE(T) (scalar_type<T>::cFlag)
#if defined(__GNUC__) && __GNUC__<5
#define BASISU_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)
#if !defined(BASISU_HAVE_STD_TRIVIALLY_COPYABLE) && defined(__GNUC__) && __GNUC__<5
//#define BASISU_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)
#define BASISU_IS_TRIVIALLY_COPYABLE(...) __is_trivially_copyable(__VA_ARGS__)
#else
#define BASISU_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value
#endif
@ -286,8 +287,19 @@ namespace basisu
if (BASISU_IS_BITWISE_COPYABLE(T))
{
#ifndef __EMSCRIPTEN__
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
#endif
if ((m_p) && (other.m_p))
memcpy(m_p, other.m_p, m_size * sizeof(T));
#ifndef __EMSCRIPTEN__
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#endif
}
else
{
@ -330,8 +342,19 @@ namespace basisu
if (BASISU_IS_BITWISE_COPYABLE(T))
{
#ifndef __EMSCRIPTEN__
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
#endif
if ((m_p) && (other.m_p))
memcpy(m_p, other.m_p, other.m_size * sizeof(T));
#ifndef __EMSCRIPTEN__
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#endif
}
else
{
@ -501,7 +524,7 @@ namespace basisu
if (new_capacity > m_capacity)
{
if (!increase_capacity(new_capacity, false))
if (!increase_capacity(new_capacity, false, true))
return false;
}
else if (new_capacity < m_capacity)
@ -509,7 +532,8 @@ namespace basisu
// Must work around the lack of a "decrease_capacity()" method.
// This case is rare enough in practice that it's probably not worth implementing an optimized in-place resize.
vector tmp;
tmp.increase_capacity(helpers::maximum(m_size, new_capacity), false);
if (!tmp.increase_capacity(helpers::maximum(m_size, new_capacity), false, true))
return false;
tmp = *this;
swap(tmp);
}
@ -750,7 +774,21 @@ namespace basisu
}
// Copy "down" the objects to preserve, filling in the empty slots.
#ifndef __EMSCRIPTEN__
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
#endif
memmove(pDst, pSrc, num_to_move * sizeof(T));
#ifndef __EMSCRIPTEN__
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#endif
}
else
{
@ -1003,7 +1041,21 @@ namespace basisu
inline void set_all(const T& o)
{
if ((sizeof(T) == 1) && (scalar_type<T>::cFlag))
{
#ifndef __EMSCRIPTEN__
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wclass-memaccess"
#endif
#endif
memset(m_p, *reinterpret_cast<const uint8_t*>(&o), m_size);
#ifndef __EMSCRIPTEN__
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#endif
}
else
{
T* pDst = m_p;
@ -1029,7 +1081,7 @@ namespace basisu
// Important: This method is used in Basis Universal. If you change how this container allocates memory, you'll need to change any users of this method.
inline bool grant_ownership(T* p, uint32_t size, uint32_t capacity)
{
// To to prevent the caller from obviously shooting themselves in the foot.
// To prevent the caller from obviously shooting themselves in the foot.
if (((p + capacity) > m_p) && (p < (m_p + m_capacity)))
{
// Can grant ownership of a block inside the container itself!

View file

@ -19,23 +19,30 @@ namespace basisu
if (m_capacity >= min_new_capacity)
return true;
size_t new_capacity = min_new_capacity;
if ((grow_hint) && (!helpers::is_power_of_2((uint64_t)new_capacity)))
uint64_t new_capacity_u64 = min_new_capacity;
if ((grow_hint) && (!helpers::is_power_of_2(new_capacity_u64)))
new_capacity_u64 = helpers::next_pow2(new_capacity_u64);
size_t new_capacity = (size_t)new_capacity_u64;
if (new_capacity != new_capacity_u64)
{
new_capacity = (size_t)helpers::next_pow2((uint64_t)new_capacity);
assert(new_capacity && (new_capacity > m_capacity));
if (new_capacity < min_new_capacity)
{
if (nofail)
return false;
fprintf(stderr, "vector too large\n");
abort();
}
if (nofail)
return false;
fprintf(stderr, "elemental_vector::increase_capacity: vector too large\n");
abort();
}
const size_t desired_size = element_size * new_capacity;
const uint64_t desired_size_u64 = (uint64_t)element_size * new_capacity;
const size_t desired_size = (size_t)desired_size_u64;
if (desired_size_u64 != desired_size)
{
if (nofail)
return false;
fprintf(stderr, "elemental_vector::increase_capacity: vector too large\n");
abort();
}
size_t actual_size = 0;
if (!pMover)
{
@ -46,11 +53,7 @@ namespace basisu
return false;
char buf[256];
#ifdef _MSC_VER
sprintf_s(buf, sizeof(buf), "vector: realloc() failed allocating %u bytes", (uint32_t)desired_size);
#else
sprintf(buf, "vector: realloc() failed allocating %u bytes", (uint32_t)desired_size);
#endif
snprintf(buf, sizeof(buf), "elemental_vector::increase_capacity: realloc() failed allocating %zu bytes", desired_size);
fprintf(stderr, "%s", buf);
abort();
}
@ -75,11 +78,7 @@ namespace basisu
return false;
char buf[256];
#ifdef _MSC_VER
sprintf_s(buf, sizeof(buf), "vector: malloc() failed allocating %u bytes", (uint32_t)desired_size);
#else
sprintf(buf, "vector: malloc() failed allocating %u bytes", (uint32_t)desired_size);
#endif
snprintf(buf, sizeof(buf), "elemental_vector::increase_capacity: malloc() failed allocating %zu bytes", desired_size);
fprintf(stderr, "%s", buf);
abort();
}

View file

@ -1,5 +1,5 @@
// basis_file_headers.h
// Copyright (C) 2019-2020 Binomial LLC. All Rights Reserved.
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -89,7 +89,8 @@ namespace basist
enum class basis_tex_format
{
cETC1S = 0,
cUASTC4x4 = 1
cUASTC4x4 = 1,
cUASTC_HDR_4x4 = 2
};
struct basis_file_header

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
// basisu_transcoder.h
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -29,6 +29,7 @@
// Set BASISU_FORCE_DEVEL_MESSAGES to 1 to enable debug printf()'s whenever an error occurs, for easier debugging during development.
#ifndef BASISU_FORCE_DEVEL_MESSAGES
// TODO - disable before checking in
#define BASISU_FORCE_DEVEL_MESSAGES 0
#endif
@ -55,7 +56,7 @@ namespace basist
cTFETC2_RGBA = 1, // Opaque+alpha, ETC2_EAC_A8 block followed by a ETC1 block, alpha channel will be opaque for opaque .basis files
// BC1-5, BC7 (desktop, some mobile devices)
cTFBC1_RGB = 2, // Opaque only, no punchthrough alpha support yet, transcodes alpha slice if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
cTFBC1_RGB = 2, // Opaque only, no punchthrough alpha support yet, transcodes alpha slice if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
cTFBC3_RGBA = 3, // Opaque+alpha, BC4 followed by a BC1 block, alpha channel will be opaque for opaque .basis files
cTFBC4_R = 4, // Red only, alpha slice is transcoded to output if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified
cTFBC5_RG = 5, // XY: Two BC4 blocks, X=R and Y=Alpha, .basis file should have alpha data (if not Y will be all 255's)
@ -63,10 +64,11 @@ namespace basist
// PVRTC1 4bpp (mobile, PowerVR devices)
cTFPVRTC1_4_RGB = 8, // Opaque only, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified, nearly lowest quality of any texture format.
cTFPVRTC1_4_RGBA = 9, // Opaque+alpha, most useful for simple opacity maps. If .basis file doesn't have alpha cTFPVRTC1_4_RGB will be used instead. Lowest quality of any supported texture format.
cTFPVRTC1_4_RGBA = 9, // Opaque+alpha, most useful for simple opacity maps. If .basis file doesn't have alpha cTFPVRTC1_4_RGB will be used instead. Lowest quality of any supported texture format.
// ASTC (mobile, Intel devices, hopefully all desktop GPU's one day)
cTFASTC_4x4_RGBA = 10, // Opaque+alpha, ASTC 4x4, alpha channel will be opaque for opaque .basis files. Transcoder uses RGB/RGBA/L/LA modes, void extent, and up to two ([0,47] and [0,255]) endpoint precisions.
cTFASTC_4x4_RGBA = 10, // LDR. Opaque+alpha, ASTC 4x4, alpha channel will be opaque for opaque .basis files.
// LDR: Transcoder uses RGB/RGBA/L/LA modes, void extent, and up to two ([0,47] and [0,255]) endpoint precisions.
// ATC (mobile, Adreno devices, this is a niche format)
cTFATC_RGB = 11, // Opaque, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. ATI ATC (GL_ATC_RGB_AMD)
@ -74,8 +76,8 @@ namespace basist
// FXT1 (desktop, Intel devices, this is a super obscure format)
cTFFXT1_RGB = 17, // Opaque only, uses exclusively CC_MIXED blocks. Notable for having a 8x4 block size. GL_3DFX_texture_compression_FXT1 is supported on Intel integrated GPU's (such as HD 630).
// Punch-through alpha is relatively easy to support, but full alpha is harder. This format is only here for completeness so opaque-only is fine for now.
// See the BASISU_USE_ORIGINAL_3DFX_FXT1_ENCODING macro in basisu_transcoder_internal.h.
// Punch-through alpha is relatively easy to support, but full alpha is harder. This format is only here for completeness so opaque-only is fine for now.
// See the BASISU_USE_ORIGINAL_3DFX_FXT1_ENCODING macro in basisu_transcoder_internal.h.
cTFPVRTC2_4_RGB = 18, // Opaque-only, almost BC1 quality, much faster to transcode and supports arbitrary texture dimensions (unlike PVRTC1 RGB).
cTFPVRTC2_4_RGBA = 19, // Opaque+alpha, slower to encode than cTFPVRTC2_4_RGB. Premultiplied alpha is highly recommended, otherwise the color channel can leak into the alpha channel on transparent blocks.
@ -83,13 +85,22 @@ namespace basist
cTFETC2_EAC_R11 = 20, // R only (ETC2 EAC R11 unsigned)
cTFETC2_EAC_RG11 = 21, // RG only (ETC2 EAC RG11 unsigned), R=opaque.r, G=alpha - for tangent space normal maps
cTFBC6H = 22, // HDR, RGB only, unsigned
cTFASTC_HDR_4x4_RGBA = 23, // HDR, RGBA (currently UASTC HDR is only RGB), unsigned
// Uncompressed (raw pixel) formats
// Note these uncompressed formats (RGBA32, 565, and 4444) can only be transcoded to from LDR input files (ETC1S or UASTC LDR).
cTFRGBA32 = 13, // 32bpp RGBA image stored in raster (not block) order in memory, R is first byte, A is last byte.
cTFRGB565 = 14, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 11
cTFBGR565 = 15, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 0
cTFRGBA4444 = 16, // 16bpp RGBA image stored in raster (not block) order in memory, R at bit position 12, A at bit position 0
cTFRGBA4444 = 16, // 16bpp RGBA image stored in raster (not block) order in memory, R at bit position 12, A at bit position 0
// Note these uncompressed formats (HALF and 9E5) can only be transcoded to from HDR input files (UASTC HDR).
cTFRGB_HALF = 24, // 48bpp RGB half (16-bits/component, 3 components)
cTFRGBA_HALF = 25, // 64bpp RGBA half (16-bits/component, 4 components) (A will always currently 1.0, UASTC_HDR doesn't support alpha)
cTFRGB_9E5 = 26, // 32bpp RGB 9E5 (shared exponent, positive only, see GL_EXT_texture_shared_exponent)
cTFTotalTextureFormats = 22,
cTFTotalTextureFormats = 27,
// Old enums for compatibility with code compiled against previous versions
cTFETC1 = cTFETC1_RGB,
@ -124,6 +135,9 @@ namespace basist
// Returns true if the format supports an alpha channel.
bool basis_transcoder_format_has_alpha(transcoder_texture_format fmt);
// Returns true if the format is HDR.
bool basis_transcoder_format_is_hdr(transcoder_texture_format fmt);
// Returns the basisu::texture_format corresponding to the specified transcoder_texture_format.
basisu::texture_format basis_get_basisu_texture_format(transcoder_texture_format fmt);
@ -142,7 +156,7 @@ namespace basist
// Returns the block height for the specified texture format, which is currently always 4.
uint32_t basis_get_block_height(transcoder_texture_format tex_type);
// Returns true if the specified format was enabled at compile time.
// Returns true if the specified format was enabled at compile time, and is supported for the specific basis/ktx2 texture format (ETC1S, UASTC, or UASTC HDR).
bool basis_is_format_supported(transcoder_texture_format tex_type, basis_tex_format fmt = basis_tex_format::cETC1S);
// Validates that the output buffer is large enough to hold the entire transcoded texture.
@ -317,6 +331,42 @@ namespace basist
int channel0 = -1, int channel1 = -1);
};
class basisu_lowlevel_uastc_hdr_transcoder
{
friend class basisu_transcoder;
public:
basisu_lowlevel_uastc_hdr_transcoder();
bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, bool has_alpha, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
basisu_transcoder_state* pState = nullptr, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1, uint32_t decode_flags = 0);
bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const basis_file_header& header, const basis_slice_desc& slice_desc, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
basisu_transcoder_state* pState = nullptr, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1, uint32_t decode_flags = 0)
{
return transcode_slice(pDst_blocks, num_blocks_x, num_blocks_y, pImage_data, image_data_size, fmt,
output_block_or_pixel_stride_in_bytes, bc1_allow_threecolor_blocks, (header.m_flags & cBASISHeaderFlagHasAlphaSlices) != 0, slice_desc.m_orig_width, slice_desc.m_orig_height, output_row_pitch_in_blocks_or_pixels,
pState, output_rows_in_pixels, channel0, channel1, decode_flags);
}
// Container independent transcoding
bool transcode_image(
transcoder_texture_format target_format,
void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
const uint8_t* pCompressed_data, uint32_t compressed_data_length,
uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,
uint32_t slice_offset, uint32_t slice_length,
uint32_t decode_flags = 0,
bool has_alpha = false,
bool is_video = false,
uint32_t output_row_pitch_in_blocks_or_pixels = 0,
basisu_transcoder_state* pState = nullptr,
uint32_t output_rows_in_pixels = 0,
int channel0 = -1, int channel1 = -1);
};
struct basisu_slice_info
{
uint32_t m_orig_width;
@ -530,6 +580,7 @@ namespace basist
private:
mutable basisu_lowlevel_etc1s_transcoder m_lowlevel_etc1s_decoder;
mutable basisu_lowlevel_uastc_transcoder m_lowlevel_uastc_decoder;
mutable basisu_lowlevel_uastc_hdr_transcoder m_lowlevel_uastc_hdr_decoder;
bool m_ready_to_transcode;
@ -612,10 +663,12 @@ namespace basist
#pragma pack(pop)
const uint32_t KTX2_VK_FORMAT_UNDEFINED = 0;
const uint32_t KTX2_FORMAT_UASTC_4x4_SFLOAT_BLOCK = 1000066000; // TODO, is this correct?
const uint32_t KTX2_KDF_DF_MODEL_UASTC = 166;
const uint32_t KTX2_KDF_DF_MODEL_UASTC_HDR = 167;
const uint32_t KTX2_KDF_DF_MODEL_ETC1S = 163;
const uint32_t KTX2_IMAGE_IS_P_FRAME = 2;
const uint32_t KTX2_UASTC_BLOCK_SIZE = 16;
const uint32_t KTX2_UASTC_BLOCK_SIZE = 16; // also the block size for UASTC_HDR
const uint32_t KTX2_MAX_SUPPORTED_LEVEL_COUNT = 16; // this is an implementation specific constraint and can be increased
// The KTX2 transfer functions supported by KTX2
@ -800,13 +853,15 @@ namespace basist
// Returns 0 or the number of layers in the texture array or texture video. Valid after init().
uint32_t get_layers() const { return m_header.m_layer_count; }
// Returns cETC1S or cUASTC4x4. Valid after init().
// Returns cETC1S, cUASTC4x4, or cUASTC_HDR_4x4. Valid after init().
basist::basis_tex_format get_format() const { return m_format; }
bool is_etc1s() const { return get_format() == basist::basis_tex_format::cETC1S; }
bool is_uastc() const { return get_format() == basist::basis_tex_format::cUASTC4x4; }
bool is_hdr() const { return get_format() == basist::basis_tex_format::cUASTC_HDR_4x4; }
// Returns true if the ETC1S file has two planes (typically RGBA, or RRRG), or true if the UASTC file has alpha data. Valid after init().
uint32_t get_has_alpha() const { return m_has_alpha; }
@ -913,6 +968,7 @@ namespace basist
basist::basisu_lowlevel_etc1s_transcoder m_etc1s_transcoder;
basist::basisu_lowlevel_uastc_transcoder m_uastc_transcoder;
basist::basisu_lowlevel_uastc_hdr_transcoder m_uastc_hdr_transcoder;
ktx2_transcoder_state m_def_transcoder_state;

View file

@ -1,5 +1,5 @@
// basisu_transcoder_internal.h - Universal texture format transcoder library.
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
//
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
//
@ -20,8 +20,9 @@
#pragma warning (disable: 4127) // conditional expression is constant
#endif
#define BASISD_LIB_VERSION 116
#define BASISD_VERSION_STRING "01.16"
// v1.50: Added UASTC HDR support
#define BASISD_LIB_VERSION 150
#define BASISD_VERSION_STRING "01.50"
#ifdef _DEBUG
#define BASISD_BUILD_DEBUG
@ -82,9 +83,15 @@ namespace basist
cRGBA4444_ALPHA,
cRGBA4444_COLOR_OPAQUE,
cRGBA4444,
cRGBA_HALF,
cRGB_HALF,
cRGB_9E5,
cUASTC_4x4,
cUASTC_4x4, // LDR, universal
cUASTC_HDR_4x4, // HDR, transcodes only to 4x4 HDR ASTC, BC6H, or uncompressed
cBC6H,
cASTC_HDR_4x4,
cTotalBlockFormats
};
@ -264,8 +271,8 @@ namespace basist
}
const basisu::uint8_vec &get_code_sizes() const { return m_code_sizes; }
const basisu::int_vec get_lookup() const { return m_lookup; }
const basisu::int16_vec get_tree() const { return m_tree; }
const basisu::int_vec &get_lookup() const { return m_lookup; }
const basisu::int16_vec &get_tree() const { return m_tree; }
bool is_valid() const { return m_code_sizes.size() > 0; }
@ -789,7 +796,198 @@ namespace basist
};
bool basis_block_format_is_uncompressed(block_format tex_type);
//------------------------------------
typedef uint16_t half_float;
const double MIN_DENORM_HALF_FLOAT = 0.000000059604645; // smallest positive subnormal number
const double MIN_HALF_FLOAT = 0.00006103515625; // smallest positive normal number
const double MAX_HALF_FLOAT = 65504.0; // largest normal number
inline uint32_t get_bits(uint32_t val, int low, int high)
{
const int num_bits = (high - low) + 1;
assert((num_bits >= 1) && (num_bits <= 32));
val >>= low;
if (num_bits != 32)
val &= ((1u << num_bits) - 1);
return val;
}
inline bool is_half_inf_or_nan(half_float v)
{
return get_bits(v, 10, 14) == 31;
}
inline bool is_half_denorm(half_float v)
{
int e = (v >> 10) & 31;
return !e;
}
inline int get_half_exp(half_float v)
{
int e = ((v >> 10) & 31);
return e ? (e - 15) : -14;
}
inline int get_half_mantissa(half_float v)
{
if (is_half_denorm(v))
return v & 0x3FF;
return (v & 0x3FF) | 0x400;
}
inline float get_half_mantissaf(half_float v)
{
return ((float)get_half_mantissa(v)) / 1024.0f;
}
inline int get_half_sign(half_float v)
{
return v ? ((v & 0x8000) ? -1 : 1) : 0;
}
inline bool half_is_signed(half_float v)
{
return (v & 0x8000) != 0;
}
#if 0
int hexp = get_half_exp(Cf);
float hman = get_half_mantissaf(Cf);
int hsign = get_half_sign(Cf);
float k = powf(2.0f, hexp) * hman * hsign;
if (is_half_inf_or_nan(Cf))
k = std::numeric_limits<float>::quiet_NaN();
#endif
half_float float_to_half(float val);
inline float half_to_float(half_float hval)
{
union { float f; uint32_t u; } x = { 0 };
uint32_t s = ((uint32_t)hval >> 15) & 1;
uint32_t e = ((uint32_t)hval >> 10) & 0x1F;
uint32_t m = (uint32_t)hval & 0x3FF;
if (!e)
{
if (!m)
{
// +- 0
x.u = s << 31;
return x.f;
}
else
{
// denormalized
while (!(m & 0x00000400))
{
m <<= 1;
--e;
}
++e;
m &= ~0x00000400;
}
}
else if (e == 31)
{
if (m == 0)
{
// +/- INF
x.u = (s << 31) | 0x7f800000;
return x.f;
}
else
{
// +/- NaN
x.u = (s << 31) | 0x7f800000 | (m << 13);
return x.f;
}
}
e = e + (127 - 15);
m = m << 13;
assert(s <= 1);
assert(m <= 0x7FFFFF);
assert(e <= 255);
x.u = m | (e << 23) | (s << 31);
return x.f;
}
// Originally from bc6h_enc.h
void bc6h_enc_init();
const uint32_t MAX_BLOG16_VAL = 0xFFFF;
// BC6H internals
const uint32_t NUM_BC6H_MODES = 14;
const uint32_t BC6H_LAST_MODE_INDEX = 13;
const uint32_t BC6H_FIRST_1SUBSET_MODE_INDEX = 10; // in the MS docs, this is "mode 11" (where the first mode is 1), 60 bits for endpoints (10.10, 10.10, 10.10), 63 bits for weights
const uint32_t TOTAL_BC6H_PARTITION_PATTERNS = 32;
extern const uint8_t g_bc6h_mode_sig_bits[NUM_BC6H_MODES][4]; // base, r, g, b
struct bc6h_bit_layout
{
int8_t m_comp; // R=0,G=1,B=2,D=3 (D=partition index)
int8_t m_index; // 0-3, 0-1 Low/High subset 1, 2-3 Low/High subset 2, -1=partition index (d)
int8_t m_last_bit;
int8_t m_first_bit; // may be -1 if a single bit, may be >m_last_bit if reversed
};
const uint32_t MAX_BC6H_LAYOUT_INDEX = 25;
extern const bc6h_bit_layout g_bc6h_bit_layouts[NUM_BC6H_MODES][MAX_BC6H_LAYOUT_INDEX];
extern const uint8_t g_bc6h_2subset_patterns[TOTAL_BC6H_PARTITION_PATTERNS][4][4]; // [y][x]
extern const uint8_t g_bc6h_weight3[8];
extern const uint8_t g_bc6h_weight4[16];
extern const int8_t g_bc6h_mode_lookup[32];
// Converts b16 to half float
inline half_float bc6h_blog16_to_half(uint32_t comp)
{
assert(comp <= 0xFFFF);
// scale the magnitude by 31/64
comp = (comp * 31u) >> 6u;
return (half_float)comp;
}
const uint32_t MAX_BC6H_HALF_FLOAT_AS_UINT = 0x7BFF;
// Inverts bc6h_blog16_to_half().
// Returns the nearest blog16 given a half value.
inline uint32_t bc6h_half_to_blog16(half_float h)
{
assert(h <= MAX_BC6H_HALF_FLOAT_AS_UINT);
return (h * 64 + 30) / 31;
}
struct bc6h_block
{
uint8_t m_bytes[16];
};
void bc6h_enc_block_mode10(bc6h_block* pPacked_block, const half_float pEndpoints[3][2], const uint8_t* pWeights);
void bc6h_enc_block_1subset_4bit_weights(bc6h_block* pPacked_block, const half_float pEndpoints[3][2], const uint8_t* pWeights);
void bc6h_enc_block_1subset_mode9_3bit_weights(bc6h_block* pPacked_block, const half_float pEndpoints[3][2], const uint8_t* pWeights);
void bc6h_enc_block_1subset_3bit_weights(bc6h_block* pPacked_block, const half_float pEndpoints[3][2], const uint8_t* pWeights);
void bc6h_enc_block_2subset_mode9_3bit_weights(bc6h_block* pPacked_block, uint32_t common_part_index, const half_float pEndpoints[2][3][2], const uint8_t* pWeights); // pEndpoints[subset][comp][lh_index]
void bc6h_enc_block_2subset_3bit_weights(bc6h_block* pPacked_block, uint32_t common_part_index, const half_float pEndpoints[2][3][2], const uint8_t* pWeights); // pEndpoints[subset][comp][lh_index]
bool bc6h_enc_block_solid_color(bc6h_block* pPacked_block, const half_float pColor[3]);
} // namespace basist

View file

@ -1,4 +1,4 @@
// Copyright (C) 2017-2019 Binomial LLC. All Rights Reserved.
// Copyright (C) 2017-2024 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View file

@ -1,4 +1,4 @@
// Copyright (C) 2017-2019 Binomial LLC. All Rights Reserved.
// Copyright (C) 2017-2024 Binomial LLC. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.

View file

@ -13,6 +13,7 @@ namespace basist
const uint32_t UASTC_MODE_INDEX_SOLID_COLOR = 8;
const uint32_t TOTAL_ASTC_BC7_COMMON_PARTITIONS2 = 30;
const uint32_t TOTAL_ASTC_BC6H_COMMON_PARTITIONS2 = 27; // BC6H only supports only 5-bit pattern indices, BC7 supports 4-bit or 6-bit
const uint32_t TOTAL_ASTC_BC7_COMMON_PARTITIONS3 = 11;
const uint32_t TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS = 19;