2
0

basisu.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. // basisu.h
  2. // Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
  3. // Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. #pragma once
  17. #ifdef _MSC_VER
  18. #pragma warning (disable : 4201)
  19. #pragma warning (disable : 4127) // warning C4127: conditional expression is constant
  20. #pragma warning (disable : 4530) // C++ exception handler used, but unwind semantics are not enabled.
  21. #endif // _MSC_VER
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <math.h>
  25. #include <stdarg.h>
  26. #include <string.h>
  27. #include <memory.h>
  28. #include <limits.h>
  29. #include <stdint.h>
  30. #include <algorithm>
  31. #include <limits>
  32. #include <functional>
  33. #include <iterator>
  34. #include <type_traits>
  35. #include <assert.h>
  36. #include <random>
  37. #include <inttypes.h>
  38. #include "basisu_containers.h"
  39. #ifdef max
  40. #undef max
  41. #endif
  42. #ifdef min
  43. #undef min
  44. #endif
  45. #ifdef _WIN32
  46. #define strcasecmp _stricmp
  47. #endif
  48. // Set to one to enable debug printf()'s when any errors occur, for development/debugging. Especially useful for WebGL development.
  49. #ifndef BASISU_FORCE_DEVEL_MESSAGES
  50. #define BASISU_FORCE_DEVEL_MESSAGES 0
  51. #endif
  52. #define BASISU_NOTE_UNUSED(x) (void)(x)
  53. #define BASISU_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
  54. #define BASISU_NO_EQUALS_OR_COPY_CONSTRUCT(x) x(const x &) = delete; x& operator= (const x &) = delete;
  55. #define BASISU_ASSUME(x) static_assert(x, #x);
  56. #define BASISU_OFFSETOF(s, m) offsetof(s, m)
  57. #define BASISU_STRINGIZE(x) #x
  58. #define BASISU_STRINGIZE2(x) BASISU_STRINGIZE(x)
  59. #if BASISU_FORCE_DEVEL_MESSAGES
  60. #define BASISU_DEVEL_ERROR(...) do { basisu::debug_printf(__VA_ARGS__); } while(0)
  61. #else
  62. #define BASISU_DEVEL_ERROR(...)
  63. #endif
  64. namespace basisu
  65. {
  66. // Types/utilities
  67. #ifdef _WIN32
  68. const char BASISU_PATH_SEPERATOR_CHAR = '\\';
  69. #else
  70. const char BASISU_PATH_SEPERATOR_CHAR = '/';
  71. #endif
  72. typedef basisu::vector<uint8_t> uint8_vec;
  73. typedef basisu::vector<int16_t> int16_vec;
  74. typedef basisu::vector<uint16_t> uint16_vec;
  75. typedef basisu::vector<uint32_t> uint_vec;
  76. typedef basisu::vector<size_t> size_t_vec;
  77. typedef basisu::vector<uint64_t> uint64_vec;
  78. typedef basisu::vector<int> int_vec;
  79. typedef basisu::vector<bool> bool_vec;
  80. typedef basisu::vector<float> float_vec;
  81. void enable_debug_printf(bool enabled);
  82. void debug_printf(const char *pFmt, ...);
  83. void debug_puts(const char* p);
  84. template <typename... Args>
  85. inline void fmt_debug_printf(const char* pFmt, Args&&... args)
  86. {
  87. std::string res;
  88. if (!fmt_variants(res, pFmt, fmt_variant_vec{ fmt_variant(std::forward<Args>(args))... }))
  89. return;
  90. debug_puts(res.c_str());
  91. }
  92. #ifndef __EMSCRIPTEN__
  93. #ifdef __GNUC__
  94. #pragma GCC diagnostic push
  95. #pragma GCC diagnostic ignored "-Wclass-memaccess"
  96. #endif
  97. #endif
  98. template <typename T> inline void clear_obj(T& obj) { memset(&obj, 0, sizeof(obj)); }
  99. #ifndef __EMSCRIPTEN__
  100. #ifdef __GNUC__
  101. #pragma GCC diagnostic pop
  102. #endif
  103. #endif
  104. constexpr double cPiD = 3.14159265358979323846264338327950288;
  105. constexpr float REALLY_SMALL_FLOAT_VAL = .000000125f;
  106. constexpr float SMALL_FLOAT_VAL = .0000125f;
  107. constexpr float BIG_FLOAT_VAL = 1e+30f;
  108. template <typename T0, typename T1> inline T0 lerp(T0 a, T0 b, T1 c) { return a + (b - a) * c; }
  109. inline float clampf(float value, float low, float high) { if (value < low) value = low; else if (value > high) value = high; return value; }
  110. inline float saturate(float value) { return clampf(value, 0, 1.0f); }
  111. inline uint8_t minimumub(uint8_t a, uint8_t b) { return (a < b) ? a : b; }
  112. inline uint32_t minimumu(uint32_t a, uint32_t b) { return (a < b) ? a : b; }
  113. inline int32_t minimumi(int32_t a, int32_t b) { return (a < b) ? a : b; }
  114. inline float minimumf(float a, float b) { return (a < b) ? a : b; }
  115. inline uint8_t maximumub(uint8_t a, uint8_t b) { return (a > b) ? a : b; }
  116. inline uint32_t maximumu(uint32_t a, uint32_t b) { return (a > b) ? a : b; }
  117. inline int32_t maximumi(int32_t a, int32_t b) { return (a > b) ? a : b; }
  118. inline float maximumf(float a, float b) { return (a > b) ? a : b; }
  119. inline int squarei(int i) { return i * i; }
  120. inline float squaref(float i) { return i * i; }
  121. inline double squared(double i) { return i * i; }
  122. template<typename T> inline T square(T a) { return a * a; }
  123. template<typename T> inline T sign(T a) { return (a < 0) ? (T)-1 : ((a == 0) ? (T)0 : (T)1); }
  124. inline bool equal_tol(float a, float b, float t) { return fabsf(a - b) <= ((maximum(fabsf(a), fabsf(b)) + 1.0f) * t); }
  125. inline bool equal_tol(double a, double b, double t) { return fabs(a - b) <= ((maximum(fabs(a), fabs(b)) + 1.0f) * t); }
  126. template <class T>
  127. inline T prev_wrap(T i, T n)
  128. {
  129. T temp = i - 1;
  130. if (temp < 0)
  131. temp = n - 1;
  132. return temp;
  133. }
  134. template <class T>
  135. inline T next_wrap(T i, T n)
  136. {
  137. T temp = i + 1;
  138. if (temp >= n)
  139. temp = 0;
  140. return temp;
  141. }
  142. inline uint32_t iabs(int32_t i) { return (i < 0) ? static_cast<uint32_t>(-i) : static_cast<uint32_t>(i); }
  143. inline uint64_t iabs64(int64_t i) { return (i < 0) ? static_cast<uint64_t>(-i) : static_cast<uint64_t>(i); }
  144. template<typename T> inline void clear_vector(T &vec) { vec.erase(vec.begin(), vec.end()); }
  145. template<typename T> inline typename T::value_type *enlarge_vector(T &vec, size_t n) { size_t cs = vec.size(); vec.resize(cs + n); return &vec[cs]; }
  146. inline bool is_pow2(uint32_t x) { return x && ((x & (x - 1U)) == 0U); }
  147. inline bool is_pow2(uint64_t x) { return x && ((x & (x - 1U)) == 0U); }
  148. 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; }
  149. template<typename T> inline T open_range_check(T v, T maxv) { assert(v < maxv); BASISU_NOTE_UNUSED(maxv); return v; }
  150. // Open interval
  151. inline bool in_bounds(int v, int l, int h)
  152. {
  153. return (v >= l) && (v < h);
  154. }
  155. // Closed interval
  156. inline bool in_range(int v, int l, int h)
  157. {
  158. return (v >= l) && (v <= h);
  159. }
  160. inline uint32_t total_bits(uint32_t v) { uint32_t l = 0; for ( ; v > 0U; ++l) v >>= 1; return l; }
  161. template<typename T> inline T saturate(T val) { return clamp(val, 0.0f, 1.0f); }
  162. inline uint32_t get_bit(uint32_t src, int ndx)
  163. {
  164. assert(in_bounds(ndx, 0, 32));
  165. return (src >> ndx) & 1;
  166. }
  167. inline bool is_bit_set(uint32_t src, int ndx)
  168. {
  169. return get_bit(src, ndx) != 0;
  170. }
  171. inline uint32_t get_bits(uint32_t val, int low, int high)
  172. {
  173. const int num_bits = (high - low) + 1;
  174. assert(in_range(num_bits, 1, 32));
  175. val >>= low;
  176. if (num_bits != 32)
  177. val &= ((1u << num_bits) - 1);
  178. return val;
  179. }
  180. template<typename T, typename R> inline void append_vector(T &vec, const R *pObjs, size_t n)
  181. {
  182. if (n)
  183. {
  184. if (vec.size())
  185. {
  186. assert((pObjs + n) <= vec.begin() || (pObjs >= vec.end()));
  187. }
  188. const size_t cur_s = vec.size();
  189. vec.resize(cur_s + n);
  190. memcpy(&vec[cur_s], pObjs, sizeof(R) * n);
  191. }
  192. }
  193. template<typename T> inline void append_vector(T &vec, const T &other_vec)
  194. {
  195. assert(&vec != &other_vec);
  196. if (other_vec.size())
  197. append_vector(vec, &other_vec[0], other_vec.size());
  198. }
  199. template<typename T> inline void vector_ensure_element_is_valid(T &vec, size_t idx)
  200. {
  201. if (idx >= vec.size())
  202. vec.resize(idx + 1);
  203. }
  204. template<typename T> inline void vector_sort(T &vec)
  205. {
  206. if (vec.size())
  207. std::sort(vec.begin(), vec.end());
  208. }
  209. template<typename T, typename U> inline bool unordered_set_contains(T& set, const U&obj)
  210. {
  211. return set.find(obj) != set.end();
  212. }
  213. template<typename T> int vector_find(const T &vec, const typename T::value_type &obj)
  214. {
  215. assert(vec.size() <= INT_MAX);
  216. for (size_t i = 0; i < vec.size(); i++)
  217. if (vec[i] == obj)
  218. return static_cast<int>(i);
  219. return -1;
  220. }
  221. template<typename T> void vector_set_all(T &vec, const typename T::value_type &obj)
  222. {
  223. for (size_t i = 0; i < vec.size(); i++)
  224. vec[i] = obj;
  225. }
  226. inline uint64_t read_be64(const void *p)
  227. {
  228. uint64_t val = 0;
  229. for (uint32_t i = 0; i < 8; i++)
  230. val |= (static_cast<uint64_t>(static_cast<const uint8_t *>(p)[7 - i]) << (i * 8));
  231. return val;
  232. }
  233. inline void write_be64(void *p, uint64_t x)
  234. {
  235. for (uint32_t i = 0; i < 8; i++)
  236. static_cast<uint8_t *>(p)[7 - i] = static_cast<uint8_t>(x >> (i * 8));
  237. }
  238. static inline uint16_t byteswap16(uint16_t x) { return static_cast<uint16_t>((x << 8) | (x >> 8)); }
  239. static inline uint32_t byteswap32(uint32_t x) { return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24)); }
  240. inline uint32_t floor_log2i(uint32_t v)
  241. {
  242. uint32_t b = 0;
  243. for (; v > 1U; ++b)
  244. v >>= 1;
  245. return b;
  246. }
  247. inline uint32_t ceil_log2i(uint32_t v)
  248. {
  249. uint32_t b = floor_log2i(v);
  250. if ((b != 32) && (v > (1U << b)))
  251. ++b;
  252. return b;
  253. }
  254. inline int posmod(int x, int y)
  255. {
  256. if (x >= 0)
  257. return (x < y) ? x : (x % y);
  258. int m = (-x) % y;
  259. return (m != 0) ? (y - m) : m;
  260. }
  261. inline bool do_excl_ranges_overlap(int la, int ha, int lb, int hb)
  262. {
  263. assert(la < ha && lb < hb);
  264. if ((ha <= lb) || (la >= hb)) return false;
  265. return true;
  266. }
  267. static inline uint32_t read_le_word(const uint8_t* pBytes)
  268. {
  269. return (pBytes[1] << 8U) | (pBytes[0]);
  270. }
  271. static inline uint32_t read_le_dword(const uint8_t *pBytes)
  272. {
  273. return (pBytes[3] << 24U) | (pBytes[2] << 16U) | (pBytes[1] << 8U) | (pBytes[0]);
  274. }
  275. static inline void write_le_dword(uint8_t* pBytes, uint32_t val)
  276. {
  277. pBytes[0] = (uint8_t)val;
  278. pBytes[1] = (uint8_t)(val >> 8U);
  279. pBytes[2] = (uint8_t)(val >> 16U);
  280. pBytes[3] = (uint8_t)(val >> 24U);
  281. }
  282. // Always little endian 1-8 byte unsigned int
  283. template<uint32_t NumBytes>
  284. struct packed_uint
  285. {
  286. uint8_t m_bytes[NumBytes];
  287. inline packed_uint() { static_assert(NumBytes <= sizeof(uint64_t), "Invalid NumBytes"); }
  288. inline packed_uint(uint64_t v) { *this = v; }
  289. inline packed_uint(const packed_uint& other) { *this = other; }
  290. inline packed_uint& operator= (uint64_t v)
  291. {
  292. for (uint32_t i = 0; i < NumBytes; i++)
  293. m_bytes[i] = static_cast<uint8_t>(v >> (i * 8));
  294. return *this;
  295. }
  296. inline packed_uint& operator= (const packed_uint& rhs)
  297. {
  298. memcpy(m_bytes, rhs.m_bytes, sizeof(m_bytes));
  299. return *this;
  300. }
  301. #if 0
  302. #ifdef __GNUC__
  303. #pragma GCC diagnostic push
  304. #pragma GCC diagnostic ignored "-Warray-bounds"
  305. #endif
  306. inline operator uint32_t() const
  307. {
  308. switch (NumBytes)
  309. {
  310. case 1:
  311. {
  312. return m_bytes[0];
  313. }
  314. case 2:
  315. {
  316. return (m_bytes[1] << 8U) | m_bytes[0];
  317. }
  318. case 3:
  319. {
  320. return (m_bytes[2] << 16U) | (m_bytes[1] << 8U) | m_bytes[0];
  321. }
  322. case 4:
  323. {
  324. return read_le_dword(m_bytes);
  325. }
  326. case 5:
  327. {
  328. uint32_t l = read_le_dword(m_bytes);
  329. uint32_t h = m_bytes[4];
  330. return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
  331. }
  332. case 6:
  333. {
  334. uint32_t l = read_le_dword(m_bytes);
  335. uint32_t h = (m_bytes[5] << 8U) | m_bytes[4];
  336. return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
  337. }
  338. case 7:
  339. {
  340. uint32_t l = read_le_dword(m_bytes);
  341. uint32_t h = (m_bytes[6] << 16U) | (m_bytes[5] << 8U) | m_bytes[4];
  342. return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
  343. }
  344. case 8:
  345. {
  346. uint32_t l = read_le_dword(m_bytes);
  347. uint32_t h = read_le_dword(m_bytes + 4);
  348. return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
  349. }
  350. default:
  351. {
  352. assert(0);
  353. return 0;
  354. }
  355. }
  356. }
  357. #ifdef __GNUC__
  358. #pragma GCC diagnostic pop
  359. #endif
  360. #else
  361. inline operator uint32_t() const
  362. {
  363. if constexpr (NumBytes == 1)
  364. {
  365. return m_bytes[0];
  366. }
  367. else if constexpr (NumBytes == 2)
  368. {
  369. return (m_bytes[1] << 8U) | m_bytes[0];
  370. }
  371. else if constexpr (NumBytes == 3)
  372. {
  373. return (m_bytes[2] << 16U) | (m_bytes[1] << 8U) | m_bytes[0];
  374. }
  375. else if constexpr (NumBytes == 4)
  376. {
  377. return read_le_dword(m_bytes);
  378. }
  379. else if constexpr (NumBytes == 5)
  380. {
  381. uint32_t l = read_le_dword(m_bytes);
  382. uint32_t h = m_bytes[4];
  383. return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
  384. }
  385. else if constexpr (NumBytes == 6)
  386. {
  387. uint32_t l = read_le_dword(m_bytes);
  388. uint32_t h = (m_bytes[5] << 8U) | m_bytes[4];
  389. return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
  390. }
  391. else if constexpr (NumBytes == 7)
  392. {
  393. uint32_t l = read_le_dword(m_bytes);
  394. uint32_t h = (m_bytes[6] << 16U) | (m_bytes[5] << 8U) | m_bytes[4];
  395. return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
  396. }
  397. else if constexpr (NumBytes == 8)
  398. {
  399. uint32_t l = read_le_dword(m_bytes);
  400. uint32_t h = read_le_dword(m_bytes + 4);
  401. return static_cast<uint64_t>(l) | (static_cast<uint64_t>(h) << 32U);
  402. }
  403. else
  404. {
  405. static_assert(NumBytes <= 8, "Invalid NumBytes");
  406. return 0;
  407. }
  408. }
  409. #endif
  410. };
  411. enum eZero { cZero };
  412. enum eNoClamp { cNoClamp };
  413. // Rice/Huffman entropy coding
  414. // This is basically Deflate-style canonical Huffman, except we allow for a lot more symbols.
  415. enum
  416. {
  417. cHuffmanMaxSupportedCodeSize = 16, cHuffmanMaxSupportedInternalCodeSize = 31,
  418. cHuffmanFastLookupBits = 10,
  419. cHuffmanMaxSymsLog2 = 14, cHuffmanMaxSyms = 1 << cHuffmanMaxSymsLog2,
  420. // Small zero runs
  421. cHuffmanSmallZeroRunSizeMin = 3, cHuffmanSmallZeroRunSizeMax = 10, cHuffmanSmallZeroRunExtraBits = 3,
  422. // Big zero run
  423. cHuffmanBigZeroRunSizeMin = 11, cHuffmanBigZeroRunSizeMax = 138, cHuffmanBigZeroRunExtraBits = 7,
  424. // Small non-zero run
  425. cHuffmanSmallRepeatSizeMin = 3, cHuffmanSmallRepeatSizeMax = 6, cHuffmanSmallRepeatExtraBits = 2,
  426. // Big non-zero run
  427. cHuffmanBigRepeatSizeMin = 7, cHuffmanBigRepeatSizeMax = 134, cHuffmanBigRepeatExtraBits = 7,
  428. cHuffmanTotalCodelengthCodes = 21, cHuffmanSmallZeroRunCode = 17, cHuffmanBigZeroRunCode = 18, cHuffmanSmallRepeatCode = 19, cHuffmanBigRepeatCode = 20
  429. };
  430. static const uint8_t g_huffman_sorted_codelength_codes[] = { cHuffmanSmallZeroRunCode, cHuffmanBigZeroRunCode, cHuffmanSmallRepeatCode, cHuffmanBigRepeatCode, 0, 8, 7, 9, 6, 0xA, 5, 0xB, 4, 0xC, 3, 0xD, 2, 0xE, 1, 0xF, 0x10 };
  431. const uint32_t cHuffmanTotalSortedCodelengthCodes = sizeof(g_huffman_sorted_codelength_codes) / sizeof(g_huffman_sorted_codelength_codes[0]);
  432. // GPU texture formats and various uncompressed texture formats.
  433. enum class texture_format
  434. {
  435. cInvalidTextureFormat = -1,
  436. // Block-based formats
  437. cETC1, // ETC1
  438. cETC1S, // ETC1 (subset: diff colors only, no subblocks)
  439. cETC2_RGB, // ETC2 color block (basisu doesn't support ETC2 planar/T/H modes - just basic ETC1)
  440. cETC2_RGBA, // ETC2 EAC alpha block followed by ETC2 color block
  441. cETC2_ALPHA, // ETC2 EAC alpha block
  442. cBC1, // DXT1
  443. cBC3, // DXT5 (BC4/DXT5A block followed by a BC1/DXT1 block)
  444. cBC4, // DXT5A
  445. cBC5, // 3DC/DXN (two BC4/DXT5A blocks)
  446. cBC6HSigned, // HDR
  447. cBC6HUnsigned, // HDR
  448. cBC7,
  449. cASTC_LDR_4x4, // ASTC 4x4 LDR only
  450. cASTC_HDR_4x4, // ASTC 4x4 HDR only (but may use LDR ASTC blocks internally, although our encoders don't do this)
  451. cASTC_HDR_6x6, // ASTC 6x6 HDR only (but may use LDR ASTC blocks internally, although our encoders don't do this)
  452. cPVRTC1_4_RGB,
  453. cPVRTC1_4_RGBA,
  454. cATC_RGB,
  455. cATC_RGBA_INTERPOLATED_ALPHA,
  456. cFXT1_RGB,
  457. cPVRTC2_4_RGBA,
  458. cETC2_R11_EAC,
  459. cETC2_RG11_EAC,
  460. cUASTC4x4,
  461. cUASTC_HDR_4x4,
  462. cBC1_NV,
  463. cBC1_AMD,
  464. // Uncompressed/raw pixels
  465. cRGBA32,
  466. cRGB565,
  467. cBGR565,
  468. cRGBA4444,
  469. cABGR4444,
  470. cRGBA_HALF,
  471. cRGB_HALF,
  472. cRGB_9E5
  473. };
  474. inline bool is_uncompressed_texture_format(texture_format fmt)
  475. {
  476. switch (fmt)
  477. {
  478. case texture_format::cRGBA32:
  479. case texture_format::cRGB565:
  480. case texture_format::cBGR565:
  481. case texture_format::cRGBA4444:
  482. case texture_format::cABGR4444:
  483. case texture_format::cRGBA_HALF:
  484. case texture_format::cRGB_HALF:
  485. case texture_format::cRGB_9E5:
  486. return true;
  487. default:
  488. break;
  489. }
  490. return false;
  491. }
  492. inline bool is_block_based_texture_format(texture_format fmt)
  493. {
  494. return !is_uncompressed_texture_format(fmt);
  495. }
  496. // This is bytes per block for GPU formats, or bytes per texel for uncompressed formats.
  497. inline uint32_t get_bytes_per_block_or_pixel(texture_format fmt)
  498. {
  499. switch (fmt)
  500. {
  501. case texture_format::cETC1:
  502. case texture_format::cETC1S:
  503. case texture_format::cETC2_RGB:
  504. case texture_format::cETC2_ALPHA:
  505. case texture_format::cBC1:
  506. case texture_format::cBC1_NV:
  507. case texture_format::cBC1_AMD:
  508. case texture_format::cBC4:
  509. case texture_format::cPVRTC1_4_RGB:
  510. case texture_format::cPVRTC1_4_RGBA:
  511. case texture_format::cATC_RGB:
  512. case texture_format::cPVRTC2_4_RGBA:
  513. case texture_format::cETC2_R11_EAC:
  514. return 8;
  515. case texture_format::cRGBA32:
  516. case texture_format::cRGB_9E5:
  517. return sizeof(uint32_t);
  518. case texture_format::cRGB_HALF:
  519. return sizeof(uint16_t) * 3;
  520. case texture_format::cRGBA_HALF:
  521. return sizeof(uint16_t) * 4;
  522. case texture_format::cRGB565:
  523. case texture_format::cBGR565:
  524. case texture_format::cRGBA4444:
  525. case texture_format::cABGR4444:
  526. return sizeof(uint16_t);
  527. default:
  528. break;
  529. }
  530. // Everything else is 16 bytes/block.
  531. return 16;
  532. }
  533. // This is qwords per block for GPU formats, or not valid for uncompressed formats.
  534. inline uint32_t get_qwords_per_block(texture_format fmt)
  535. {
  536. assert(is_block_based_texture_format(fmt));
  537. const uint32_t bytes_per_block = get_bytes_per_block_or_pixel(fmt);
  538. return bytes_per_block >> 3;
  539. }
  540. inline uint32_t get_block_width(texture_format fmt)
  541. {
  542. assert(is_block_based_texture_format(fmt));
  543. switch (fmt)
  544. {
  545. case texture_format::cFXT1_RGB:
  546. return 8;
  547. case texture_format::cASTC_HDR_6x6:
  548. return 6;
  549. default:
  550. break;
  551. }
  552. return 4;
  553. }
  554. inline uint32_t get_block_height(texture_format fmt)
  555. {
  556. assert(is_block_based_texture_format(fmt));
  557. switch (fmt)
  558. {
  559. case texture_format::cASTC_HDR_6x6:
  560. return 6;
  561. default:
  562. break;
  563. }
  564. return 4;
  565. }
  566. inline bool is_hdr_texture_format(texture_format fmt)
  567. {
  568. switch (fmt)
  569. {
  570. case texture_format::cASTC_HDR_4x4:
  571. case texture_format::cUASTC_HDR_4x4:
  572. case texture_format::cASTC_HDR_6x6:
  573. case texture_format::cBC6HSigned:
  574. case texture_format::cBC6HUnsigned:
  575. case texture_format::cRGBA_HALF:
  576. case texture_format::cRGB_HALF:
  577. case texture_format::cRGB_9E5:
  578. return true;
  579. default:
  580. break;
  581. }
  582. return false;
  583. }
  584. inline bool is_ldr_texture_format(texture_format fmt)
  585. {
  586. return !is_hdr_texture_format(fmt);
  587. }
  588. } // namespace basisu