basisu_pvrtc1_4.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. // basisu_pvrtc1_4.cpp
  2. // Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. #pragma once
  16. #include "basisu_gpu_texture.h"
  17. namespace basisu
  18. {
  19. enum
  20. {
  21. PVRTC2_MIN_WIDTH = 16,
  22. PVRTC2_MIN_HEIGHT = 8,
  23. PVRTC4_MIN_WIDTH = 8,
  24. PVRTC4_MIN_HEIGHT = 8
  25. };
  26. struct pvrtc4_block
  27. {
  28. uint32_t m_modulation;
  29. uint32_t m_endpoints;
  30. pvrtc4_block() : m_modulation(0), m_endpoints(0) { }
  31. inline bool operator== (const pvrtc4_block& rhs) const
  32. {
  33. return (m_modulation == rhs.m_modulation) && (m_endpoints == rhs.m_endpoints);
  34. }
  35. inline void clear()
  36. {
  37. m_modulation = 0;
  38. m_endpoints = 0;
  39. }
  40. inline bool get_block_uses_transparent_modulation() const
  41. {
  42. return (m_endpoints & 1) != 0;
  43. }
  44. inline bool is_endpoint_opaque(uint32_t endpoint_index) const
  45. {
  46. static const uint32_t s_bitmasks[2] = { 0x8000U, 0x80000000U };
  47. return (m_endpoints & s_bitmasks[open_range_check(endpoint_index, 2U)]) != 0;
  48. }
  49. // Returns raw endpoint or 8888
  50. color_rgba get_endpoint(uint32_t endpoint_index, bool unpack) const;
  51. color_rgba get_endpoint_5554(uint32_t endpoint_index) const;
  52. static uint32_t get_component_precision_in_bits(uint32_t c, uint32_t endpoint_index, bool opaque_endpoint)
  53. {
  54. static const uint32_t s_comp_prec[4][4] =
  55. {
  56. // R0 G0 B0 A0 R1 G1 B1 A1
  57. { 4, 4, 3, 3 }, { 4, 4, 4, 3 }, // transparent endpoint
  58. { 5, 5, 4, 0 }, { 5, 5, 5, 0 } // opaque endpoint
  59. };
  60. return s_comp_prec[open_range_check(endpoint_index, 2U) + (opaque_endpoint * 2)][open_range_check(c, 4U)];
  61. }
  62. static color_rgba get_color_precision_in_bits(uint32_t endpoint_index, bool opaque_endpoint)
  63. {
  64. static const color_rgba s_color_prec[4] =
  65. {
  66. color_rgba(4, 4, 3, 3), color_rgba(4, 4, 4, 3), // transparent endpoint
  67. color_rgba(5, 5, 4, 0), color_rgba(5, 5, 5, 0) // opaque endpoint
  68. };
  69. return s_color_prec[open_range_check(endpoint_index, 2U) + (opaque_endpoint * 2)];
  70. }
  71. inline uint32_t get_modulation(uint32_t x, uint32_t y) const
  72. {
  73. assert((x < 4) && (y < 4));
  74. return (m_modulation >> ((y * 4 + x) * 2)) & 3;
  75. }
  76. inline void set_modulation(uint32_t x, uint32_t y, uint32_t s)
  77. {
  78. assert((x < 4) && (y < 4) && (s < 4));
  79. uint32_t n = (y * 4 + x) * 2;
  80. m_modulation = (m_modulation & (~(3 << n))) | (s << n);
  81. assert(get_modulation(x, y) == s);
  82. }
  83. // Scaled by 8
  84. inline const uint32_t* get_scaled_modulation_values(bool block_uses_transparent_modulation) const
  85. {
  86. static const uint32_t s_block_scales[2][4] = { { 0, 3, 5, 8 }, { 0, 4, 4, 8 } };
  87. return s_block_scales[block_uses_transparent_modulation];
  88. }
  89. // Scaled by 8
  90. inline uint32_t get_scaled_modulation(uint32_t x, uint32_t y) const
  91. {
  92. return get_scaled_modulation_values(get_block_uses_transparent_modulation())[get_modulation(x, y)];
  93. }
  94. inline void byte_swap()
  95. {
  96. m_modulation = byteswap32(m_modulation);
  97. m_endpoints = byteswap32(m_endpoints);
  98. }
  99. // opaque endpoints: 554, 555
  100. // transparent endpoints: 3443, 3444
  101. inline void set_endpoint_raw(uint32_t endpoint_index, const color_rgba& c, bool opaque_endpoint)
  102. {
  103. assert(endpoint_index < 2);
  104. const uint32_t m = m_endpoints & 1;
  105. uint32_t r = c[0], g = c[1], b = c[2], a = c[3];
  106. uint32_t packed;
  107. if (opaque_endpoint)
  108. {
  109. if (!endpoint_index)
  110. {
  111. // 554
  112. // 1RRRRRGGGGGBBBBM
  113. assert((r < 32) && (g < 32) && (b < 16));
  114. packed = 0x8000 | (r << 10) | (g << 5) | (b << 1) | m;
  115. }
  116. else
  117. {
  118. // 555
  119. // 1RRRRRGGGGGBBBBB
  120. assert((r < 32) && (g < 32) && (b < 32));
  121. packed = 0x8000 | (r << 10) | (g << 5) | b;
  122. }
  123. }
  124. else
  125. {
  126. if (!endpoint_index)
  127. {
  128. // 3443
  129. // 0AAA RRRR GGGG BBBM
  130. assert((r < 16) && (g < 16) && (b < 8) && (a < 8));
  131. packed = (a << 12) | (r << 8) | (g << 4) | (b << 1) | m;
  132. }
  133. else
  134. {
  135. // 3444
  136. // 0AAA RRRR GGGG BBBB
  137. assert((r < 16) && (g < 16) && (b < 16) && (a < 8));
  138. packed = (a << 12) | (r << 8) | (g << 4) | b;
  139. }
  140. }
  141. assert(packed <= 0xFFFF);
  142. if (endpoint_index)
  143. m_endpoints = (m_endpoints & 0xFFFFU) | (packed << 16);
  144. else
  145. m_endpoints = (m_endpoints & 0xFFFF0000U) | packed;
  146. }
  147. };
  148. typedef vector2D<pvrtc4_block> pvrtc4_block_vector2D;
  149. uint32_t pvrtc4_swizzle_uv(uint32_t XSize, uint32_t YSize, uint32_t XPos, uint32_t YPos);
  150. class pvrtc4_image
  151. {
  152. public:
  153. inline pvrtc4_image() :
  154. m_width(0), m_height(0), m_block_width(0), m_block_height(0), m_uses_alpha(false)
  155. {
  156. }
  157. inline pvrtc4_image(uint32_t width, uint32_t height) :
  158. m_width(0), m_height(0), m_block_width(0), m_block_height(0), m_uses_alpha(false)
  159. {
  160. resize(width, height);
  161. }
  162. inline void clear()
  163. {
  164. m_width = 0;
  165. m_height = 0;
  166. m_block_width = 0;
  167. m_block_height = 0;
  168. m_blocks.clear();
  169. m_uses_alpha = false;
  170. }
  171. inline void resize(uint32_t width, uint32_t height)
  172. {
  173. if ((width == m_width) && (height == m_height))
  174. return;
  175. m_width = width;
  176. m_height = height;
  177. m_block_width = (width + 3) >> 2;
  178. m_block_height = (height + 3) >> 2;
  179. m_blocks.resize(m_block_width, m_block_height);
  180. }
  181. inline uint32_t get_width() const { return m_width; }
  182. inline uint32_t get_height() const { return m_height; }
  183. inline uint32_t get_block_width() const { return m_block_width; }
  184. inline uint32_t get_block_height() const { return m_block_height; }
  185. inline const pvrtc4_block_vector2D &get_blocks() const { return m_blocks; }
  186. inline pvrtc4_block_vector2D &get_blocks() { return m_blocks; }
  187. inline uint32_t get_total_blocks() const { return m_block_width * m_block_height; }
  188. inline bool get_uses_alpha() const { return m_uses_alpha; }
  189. inline void set_uses_alpha(bool uses_alpha) { m_uses_alpha = uses_alpha; }
  190. inline bool are_blocks_equal(const pvrtc4_image& rhs) const
  191. {
  192. return m_blocks == rhs.m_blocks;
  193. }
  194. inline void set_to_black()
  195. {
  196. memset(m_blocks.get_ptr(), 0, m_blocks.size_in_bytes());
  197. }
  198. inline bool get_block_uses_transparent_modulation(uint32_t bx, uint32_t by) const
  199. {
  200. return m_blocks(bx, by).get_block_uses_transparent_modulation();
  201. }
  202. inline bool is_endpoint_opaque(uint32_t bx, uint32_t by, uint32_t endpoint_index) const
  203. {
  204. return m_blocks(bx, by).is_endpoint_opaque(endpoint_index);
  205. }
  206. color_rgba get_endpoint(uint32_t bx, uint32_t by, uint32_t endpoint_index, bool unpack) const
  207. {
  208. assert((bx < m_block_width) && (by < m_block_height));
  209. return m_blocks(bx, by).get_endpoint(endpoint_index, unpack);
  210. }
  211. inline uint32_t get_modulation(uint32_t x, uint32_t y) const
  212. {
  213. assert((x < m_width) && (y < m_height));
  214. return m_blocks(x >> 2, y >> 2).get_modulation(x & 3, y & 3);
  215. }
  216. // Returns true if the block uses transparent modulation.
  217. bool get_interpolated_colors(uint32_t x, uint32_t y, color_rgba* pColors) const;
  218. color_rgba get_pixel(uint32_t x, uint32_t y, uint32_t m) const;
  219. inline color_rgba get_pixel(uint32_t x, uint32_t y) const
  220. {
  221. assert((x < m_width) && (y < m_height));
  222. return get_pixel(x, y, m_blocks(x >> 2, y >> 2).get_modulation(x & 3, y & 3));
  223. }
  224. void deswizzle()
  225. {
  226. pvrtc4_block_vector2D temp(m_blocks);
  227. for (uint32_t y = 0; y < m_block_height; y++)
  228. for (uint32_t x = 0; x < m_block_width; x++)
  229. m_blocks(x, y) = temp[pvrtc4_swizzle_uv(m_block_width, m_block_height, x, y)];
  230. }
  231. void swizzle()
  232. {
  233. pvrtc4_block_vector2D temp(m_blocks);
  234. for (uint32_t y = 0; y < m_block_height; y++)
  235. for (uint32_t x = 0; x < m_block_width; x++)
  236. m_blocks[pvrtc4_swizzle_uv(m_block_width, m_block_height, x, y)] = temp(x, y);
  237. }
  238. void unpack_all_pixels(image& img) const
  239. {
  240. img.crop(m_width, m_height);
  241. for (uint32_t y = 0; y < m_height; y++)
  242. for (uint32_t x = 0; x < m_width; x++)
  243. img(x, y) = get_pixel(x, y);
  244. }
  245. void unpack_block(image &dst, uint32_t block_x, uint32_t block_y)
  246. {
  247. for (uint32_t y = 0; y < 4; y++)
  248. for (uint32_t x = 0; x < 4; x++)
  249. dst(x, y) = get_pixel(block_x * 4 + x, block_y * 4 + y);
  250. }
  251. inline int wrap_x(int x) const
  252. {
  253. return posmod(x, m_width);
  254. }
  255. inline int wrap_y(int y) const
  256. {
  257. return posmod(y, m_height);
  258. }
  259. inline int wrap_block_x(int bx) const
  260. {
  261. return posmod(bx, m_block_width);
  262. }
  263. inline int wrap_block_y(int by) const
  264. {
  265. return posmod(by, m_block_height);
  266. }
  267. inline vec2F get_interpolation_factors(uint32_t x, uint32_t y) const
  268. {
  269. // 0 1 2 3
  270. // 2 3 0 1
  271. // .5 .75 0 .25
  272. static const float s_interp[4] = { 2, 3, 0, 1 };
  273. return vec2F(s_interp[x & 3], s_interp[y & 3]);
  274. }
  275. inline color_rgba interpolate(int x, int y,
  276. const color_rgba& p, const color_rgba& q,
  277. const color_rgba& r, const color_rgba& s) const
  278. {
  279. static const int s_interp[4] = { 2, 3, 0, 1 };
  280. const int u_interp = s_interp[x & 3];
  281. const int v_interp = s_interp[y & 3];
  282. color_rgba result;
  283. for (uint32_t c = 0; c < 4; c++)
  284. {
  285. int t = p[c] * 4 + u_interp * ((int)q[c] - (int)p[c]);
  286. int b = r[c] * 4 + u_interp * ((int)s[c] - (int)r[c]);
  287. int v = t * 4 + v_interp * (b - t);
  288. if (c < 3)
  289. {
  290. v >>= 1;
  291. v += (v >> 5);
  292. }
  293. else
  294. {
  295. v += (v >> 4);
  296. }
  297. assert((v >= 0) && (v < 256));
  298. result[c] = static_cast<uint8_t>(v);
  299. }
  300. return result;
  301. }
  302. inline void set_modulation(uint32_t x, uint32_t y, uint32_t s)
  303. {
  304. assert((x < m_width) && (y < m_height));
  305. return m_blocks(x >> 2, y >> 2).set_modulation(x & 3, y & 3, s);
  306. }
  307. inline uint64_t map_pixel(uint32_t x, uint32_t y, const color_rgba& c, bool perceptual, bool alpha_is_significant, bool record = true)
  308. {
  309. color_rgba v[4];
  310. get_interpolated_colors(x, y, v);
  311. uint64_t best_dist = color_distance(perceptual, c, v[0], alpha_is_significant);
  312. uint32_t best_v = 0;
  313. for (uint32_t i = 1; i < 4; i++)
  314. {
  315. uint64_t dist = color_distance(perceptual, c, v[i], alpha_is_significant);
  316. if (dist < best_dist)
  317. {
  318. best_dist = dist;
  319. best_v = i;
  320. }
  321. }
  322. if (record)
  323. set_modulation(x, y, best_v);
  324. return best_dist;
  325. }
  326. inline uint64_t remap_pixels_influenced_by_endpoint(uint32_t bx, uint32_t by, const image& orig_img, bool perceptual, bool alpha_is_significant)
  327. {
  328. uint64_t total_error = 0;
  329. for (int yd = -3; yd <= 3; yd++)
  330. {
  331. const int y = wrap_y((int)by * 4 + 2 + yd);
  332. for (int xd = -3; xd <= 3; xd++)
  333. {
  334. const int x = wrap_x((int)bx * 4 + 2 + xd);
  335. total_error += map_pixel(x, y, orig_img(x, y), perceptual, alpha_is_significant);
  336. }
  337. }
  338. return total_error;
  339. }
  340. inline uint64_t evaluate_1x1_endpoint_error(uint32_t bx, uint32_t by, const image& orig_img, bool perceptual, bool alpha_is_significant, uint64_t threshold_error = 0) const
  341. {
  342. uint64_t total_error = 0;
  343. for (int yd = -3; yd <= 3; yd++)
  344. {
  345. const int y = wrap_y((int)by * 4 + 2 + yd);
  346. for (int xd = -3; xd <= 3; xd++)
  347. {
  348. const int x = wrap_x((int)bx * 4 + 2 + xd);
  349. total_error += color_distance(perceptual, get_pixel(x, y), orig_img(x, y), alpha_is_significant);
  350. if ((threshold_error) && (total_error >= threshold_error))
  351. return total_error;
  352. }
  353. }
  354. return total_error;
  355. }
  356. uint64_t local_endpoint_optimization_opaque(uint32_t bx, uint32_t by, const image& orig_img, bool perceptual);
  357. inline uint64_t map_all_pixels(const image& img, bool perceptual, bool alpha_is_significant)
  358. {
  359. assert(m_width == img.get_width());
  360. assert(m_height == img.get_height());
  361. uint64_t total_error = 0;
  362. for (uint32_t y = 0; y < img.get_height(); y++)
  363. for (uint32_t x = 0; x < img.get_width(); x++)
  364. total_error += map_pixel(x, y, img(x, y), perceptual, alpha_is_significant);
  365. return total_error;
  366. }
  367. public:
  368. uint32_t m_width, m_height;
  369. pvrtc4_block_vector2D m_blocks;
  370. uint32_t m_block_width, m_block_height;
  371. bool m_uses_alpha;
  372. };
  373. } // namespace basisu