basisu_frontend.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. // basisu_frontend.h
  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_enc.h"
  17. #include "basisu_etc.h"
  18. #include "basisu_gpu_texture.h"
  19. #include "../transcoder/basisu_file_headers.h"
  20. #include "../transcoder/basisu_transcoder.h"
  21. namespace basisu
  22. {
  23. struct opencl_context;
  24. typedef opencl_context* opencl_context_ptr;
  25. struct vec2U
  26. {
  27. uint32_t m_comps[2];
  28. vec2U() { }
  29. vec2U(uint32_t a, uint32_t b) { set(a, b); }
  30. void set(uint32_t a, uint32_t b) { m_comps[0] = a; m_comps[1] = b; }
  31. uint32_t operator[] (uint32_t i) const { assert(i < 2); return m_comps[i]; }
  32. uint32_t &operator[] (uint32_t i) { assert(i < 2); return m_comps[i]; }
  33. };
  34. const uint32_t BASISU_DEFAULT_COMPRESSION_LEVEL = 2;
  35. const uint32_t BASISU_MAX_COMPRESSION_LEVEL = 6;
  36. class basisu_frontend
  37. {
  38. BASISU_NO_EQUALS_OR_COPY_CONSTRUCT(basisu_frontend);
  39. public:
  40. basisu_frontend() :
  41. m_total_blocks(0),
  42. m_total_pixels(0),
  43. m_endpoint_refinement(false),
  44. m_use_hierarchical_endpoint_codebooks(false),
  45. m_use_hierarchical_selector_codebooks(false),
  46. m_num_endpoint_codebook_iterations(0),
  47. m_num_selector_codebook_iterations(0),
  48. m_opencl_failed(false)
  49. {
  50. }
  51. enum
  52. {
  53. cMaxEndpointClusters = 16128,
  54. cMaxSelectorClusters = 16128,
  55. };
  56. struct params
  57. {
  58. params() :
  59. m_num_source_blocks(0),
  60. m_pSource_blocks(NULL),
  61. m_max_endpoint_clusters(256),
  62. m_max_selector_clusters(256),
  63. m_compression_level(BASISU_DEFAULT_COMPRESSION_LEVEL),
  64. m_perceptual(true),
  65. m_debug_stats(false),
  66. m_debug_images(false),
  67. m_dump_endpoint_clusterization(true),
  68. m_validate(false),
  69. m_multithreaded(false),
  70. m_disable_hierarchical_endpoint_codebooks(false),
  71. m_tex_type(basist::cBASISTexType2D),
  72. m_pOpenCL_context(nullptr),
  73. m_pJob_pool(nullptr)
  74. {
  75. }
  76. uint32_t m_num_source_blocks;
  77. pixel_block *m_pSource_blocks;
  78. uint32_t m_max_endpoint_clusters;
  79. uint32_t m_max_selector_clusters;
  80. uint32_t m_compression_level;
  81. bool m_perceptual;
  82. bool m_debug_stats;
  83. bool m_debug_images;
  84. bool m_dump_endpoint_clusterization;
  85. bool m_validate;
  86. bool m_multithreaded;
  87. bool m_disable_hierarchical_endpoint_codebooks;
  88. basist::basis_texture_type m_tex_type;
  89. const basist::basisu_lowlevel_etc1s_transcoder *m_pGlobal_codebooks;
  90. opencl_context_ptr m_pOpenCL_context;
  91. job_pool *m_pJob_pool;
  92. };
  93. bool init(const params &p);
  94. bool compress();
  95. const params &get_params() const { return m_params; }
  96. const pixel_block &get_source_pixel_block(uint32_t i) const { return m_source_blocks[i]; }
  97. // RDO output blocks
  98. uint32_t get_total_output_blocks() const { return static_cast<uint32_t>(m_encoded_blocks.size()); }
  99. const etc_block &get_output_block(uint32_t block_index) const { return m_encoded_blocks[block_index]; }
  100. const etc_block_vec &get_output_blocks() const { return m_encoded_blocks; }
  101. // "Best" ETC1S blocks
  102. const etc_block &get_etc1s_block(uint32_t block_index) const { return m_etc1_blocks_etc1s[block_index]; }
  103. // Per-block flags
  104. bool get_diff_flag(uint32_t block_index) const { return m_encoded_blocks[block_index].get_diff_bit(); }
  105. // Endpoint clusters
  106. uint32_t get_total_endpoint_clusters() const { return static_cast<uint32_t>(m_endpoint_clusters.size()); }
  107. uint32_t get_subblock_endpoint_cluster_index(uint32_t block_index, uint32_t subblock_index) const { return m_block_endpoint_clusters_indices[block_index][subblock_index]; }
  108. const color_rgba &get_endpoint_cluster_unscaled_color(uint32_t cluster_index, bool individual_mode) const { return m_endpoint_cluster_etc_params[cluster_index].m_color_unscaled[individual_mode]; }
  109. uint32_t get_endpoint_cluster_inten_table(uint32_t cluster_index, bool individual_mode) const { return m_endpoint_cluster_etc_params[cluster_index].m_inten_table[individual_mode]; }
  110. bool get_endpoint_cluster_color_is_used(uint32_t cluster_index, bool individual_mode) const { return m_endpoint_cluster_etc_params[cluster_index].m_color_used[individual_mode]; }
  111. // Selector clusters
  112. uint32_t get_total_selector_clusters() const { return static_cast<uint32_t>(m_selector_cluster_block_indices.size()); }
  113. uint32_t get_block_selector_cluster_index(uint32_t block_index) const { return m_block_selector_cluster_index[block_index]; }
  114. const etc_block &get_selector_cluster_selector_bits(uint32_t cluster_index) const { return m_optimized_cluster_selectors[cluster_index]; }
  115. // Returns block indices using each selector cluster
  116. const uint_vec &get_selector_cluster_block_indices(uint32_t selector_cluster_index) const { return m_selector_cluster_block_indices[selector_cluster_index]; }
  117. void dump_debug_image(const char *pFilename, uint32_t first_block, uint32_t num_blocks_x, uint32_t num_blocks_y, bool output_blocks);
  118. void reoptimize_remapped_endpoints(const uint_vec &new_block_endpoints, int_vec &old_to_new_endpoint_cluster_indices, bool optimize_final_codebook, uint_vec *pBlock_selector_indices = nullptr);
  119. bool get_opencl_failed() const { return m_opencl_failed; }
  120. private:
  121. params m_params;
  122. uint32_t m_total_blocks;
  123. uint32_t m_total_pixels;
  124. bool m_endpoint_refinement;
  125. bool m_use_hierarchical_endpoint_codebooks;
  126. bool m_use_hierarchical_selector_codebooks;
  127. uint32_t m_num_endpoint_codebook_iterations;
  128. uint32_t m_num_selector_codebook_iterations;
  129. // Source pixels for each blocks
  130. pixel_block_vec m_source_blocks;
  131. // The quantized ETC1S texture.
  132. etc_block_vec m_encoded_blocks;
  133. // Quantized blocks after endpoint quant, but before selector quant
  134. etc_block_vec m_orig_encoded_blocks;
  135. // Full quality ETC1S texture
  136. etc_block_vec m_etc1_blocks_etc1s;
  137. typedef vec<6, float> vec6F;
  138. // Endpoint clusterizer
  139. typedef tree_vector_quant<vec6F> vec6F_quantizer;
  140. vec6F_quantizer m_endpoint_clusterizer;
  141. // For each endpoint cluster: An array of which subblock indices (block_index*2+subblock) are located in that cluster.
  142. basisu::vector<uint_vec> m_endpoint_clusters;
  143. // Array of subblock indices for each parent endpoint cluster
  144. // Note: Initially, each endpoint cluster will only live in a single parent cluster, in a shallow tree.
  145. // As the endpoint clusters are manipulated this constraint gets broken.
  146. basisu::vector<uint_vec> m_endpoint_parent_clusters;
  147. // Each block's parent endpoint cluster index
  148. uint8_vec m_block_parent_endpoint_cluster;
  149. // Array of endpoint cluster indices for each parent endpoint cluster
  150. basisu::vector<uint_vec> m_endpoint_clusters_within_each_parent_cluster;
  151. struct endpoint_cluster_etc_params
  152. {
  153. endpoint_cluster_etc_params()
  154. {
  155. clear();
  156. }
  157. void clear()
  158. {
  159. clear_obj(m_color_unscaled);
  160. clear_obj(m_inten_table);
  161. clear_obj(m_color_error);
  162. m_subblocks.clear();
  163. clear_obj(m_color_used);
  164. m_valid = false;
  165. }
  166. // TODO: basisu doesn't use individual mode.
  167. color_rgba m_color_unscaled[2]; // [use_individual_mode]
  168. uint32_t m_inten_table[2];
  169. uint64_t m_color_error[2];
  170. uint_vec m_subblocks;
  171. bool m_color_used[2];
  172. bool m_valid;
  173. bool operator== (const endpoint_cluster_etc_params &other) const
  174. {
  175. for (uint32_t i = 0; i < 2; i++)
  176. {
  177. if (m_color_unscaled[i] != other.m_color_unscaled[i])
  178. return false;
  179. }
  180. if (m_inten_table[0] != other.m_inten_table[0])
  181. return false;
  182. if (m_inten_table[1] != other.m_inten_table[1])
  183. return false;
  184. return true;
  185. }
  186. bool operator< (const endpoint_cluster_etc_params &other) const
  187. {
  188. for (uint32_t i = 0; i < 2; i++)
  189. {
  190. if (m_color_unscaled[i] < other.m_color_unscaled[i])
  191. return true;
  192. else if (m_color_unscaled[i] != other.m_color_unscaled[i])
  193. return false;
  194. }
  195. if (m_inten_table[0] < other.m_inten_table[0])
  196. return true;
  197. else if (m_inten_table[0] == other.m_inten_table[0])
  198. {
  199. if (m_inten_table[1] < other.m_inten_table[1])
  200. return true;
  201. }
  202. return false;
  203. }
  204. };
  205. typedef basisu::vector<endpoint_cluster_etc_params> cluster_subblock_etc_params_vec;
  206. // Each endpoint cluster's ETC1S parameters
  207. cluster_subblock_etc_params_vec m_endpoint_cluster_etc_params;
  208. // The endpoint cluster index used by each ETC1 subblock.
  209. basisu::vector<vec2U> m_block_endpoint_clusters_indices;
  210. // The block(s) within each selector cluster
  211. // Note: If you add anything here that uses selector cluster indicies, be sure to update optimize_selector_codebook()!
  212. basisu::vector<uint_vec> m_selector_cluster_block_indices;
  213. // The selector bits for each selector cluster.
  214. basisu::vector<etc_block> m_optimized_cluster_selectors;
  215. // The block(s) within each parent selector cluster.
  216. basisu::vector<uint_vec> m_selector_parent_cluster_block_indices;
  217. // Each block's parent selector cluster
  218. uint8_vec m_block_parent_selector_cluster;
  219. // Array of selector cluster indices for each parent selector cluster
  220. basisu::vector<uint_vec> m_selector_clusters_within_each_parent_cluster;
  221. // Each block's selector cluster index
  222. basisu::vector<uint32_t> m_block_selector_cluster_index;
  223. struct subblock_endpoint_quant_err
  224. {
  225. uint64_t m_total_err;
  226. uint32_t m_cluster_index;
  227. uint32_t m_cluster_subblock_index;
  228. uint32_t m_block_index;
  229. uint32_t m_subblock_index;
  230. bool operator< (const subblock_endpoint_quant_err &rhs) const
  231. {
  232. if (m_total_err < rhs.m_total_err)
  233. return true;
  234. else if (m_total_err == rhs.m_total_err)
  235. {
  236. if (m_block_index < rhs.m_block_index)
  237. return true;
  238. else if (m_block_index == rhs.m_block_index)
  239. return m_subblock_index < rhs.m_subblock_index;
  240. }
  241. return false;
  242. }
  243. };
  244. // The sorted subblock endpoint quant error for each endpoint cluster
  245. basisu::vector<subblock_endpoint_quant_err> m_subblock_endpoint_quant_err_vec;
  246. std::mutex m_lock;
  247. bool m_opencl_failed;
  248. //-----------------------------------------------------------------------------
  249. void init_etc1_images();
  250. bool init_global_codebooks();
  251. void init_endpoint_training_vectors();
  252. void dump_endpoint_clusterization_visualization(const char *pFilename, bool vis_endpoint_colors);
  253. void generate_endpoint_clusters();
  254. void compute_endpoint_subblock_error_vec();
  255. void introduce_new_endpoint_clusters();
  256. void generate_endpoint_codebook(uint32_t step);
  257. uint32_t refine_endpoint_clusterization();
  258. void eliminate_redundant_or_empty_endpoint_clusters();
  259. void generate_block_endpoint_clusters();
  260. void compute_endpoint_clusters_within_each_parent_cluster();
  261. void compute_selector_clusters_within_each_parent_cluster();
  262. void create_initial_packed_texture();
  263. void generate_selector_clusters();
  264. void create_optimized_selector_codebook(uint32_t iter);
  265. void find_optimal_selector_clusters_for_each_block();
  266. uint32_t refine_block_endpoints_given_selectors();
  267. void finalize();
  268. bool validate_endpoint_cluster_hierarchy(bool ensure_clusters_have_same_parents) const;
  269. bool validate_output() const;
  270. void introduce_special_selector_clusters();
  271. void optimize_selector_codebook();
  272. bool check_etc1s_constraints() const;
  273. };
  274. } // namespace basisu