basisu_comp.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723
  1. // basisu_comp.h
  2. // Copyright (C) 2019-2024 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_frontend.h"
  17. #include "basisu_backend.h"
  18. #include "basisu_basis_file.h"
  19. #include "../transcoder/basisu_transcoder.h"
  20. #include "basisu_uastc_enc.h"
  21. #include "basisu_astc_hdr_enc.h"
  22. #define BASISU_LIB_VERSION 150
  23. #define BASISU_LIB_VERSION_STRING "1.50"
  24. #ifndef BASISD_SUPPORT_KTX2
  25. #error BASISD_SUPPORT_KTX2 is undefined
  26. #endif
  27. #ifndef BASISD_SUPPORT_KTX2_ZSTD
  28. #error BASISD_SUPPORT_KTX2_ZSTD is undefined
  29. #endif
  30. #if !BASISD_SUPPORT_KTX2
  31. #error BASISD_SUPPORT_KTX2 must be enabled when building the encoder. To reduce code size if KTX2 support is not needed, set BASISD_SUPPORT_KTX2_ZSTD to 0
  32. #endif
  33. namespace basisu
  34. {
  35. struct opencl_context;
  36. typedef opencl_context* opencl_context_ptr;
  37. const uint32_t BASISU_MAX_SUPPORTED_TEXTURE_DIMENSION = 16384;
  38. // Allow block's color distance to increase by 1.5 while searching for an alternative nearby endpoint.
  39. const float BASISU_DEFAULT_ENDPOINT_RDO_THRESH = 1.5f;
  40. // Allow block's color distance to increase by 1.25 while searching the selector history buffer for a close enough match.
  41. const float BASISU_DEFAULT_SELECTOR_RDO_THRESH = 1.25f;
  42. const int BASISU_DEFAULT_QUALITY = 128;
  43. const float BASISU_DEFAULT_HYBRID_SEL_CB_QUALITY_THRESH = 2.0f;
  44. const uint32_t BASISU_MAX_IMAGE_DIMENSION = 16384;
  45. const uint32_t BASISU_QUALITY_MIN = 1;
  46. const uint32_t BASISU_QUALITY_MAX = 255;
  47. const uint32_t BASISU_MAX_ENDPOINT_CLUSTERS = basisu_frontend::cMaxEndpointClusters;
  48. const uint32_t BASISU_MAX_SELECTOR_CLUSTERS = basisu_frontend::cMaxSelectorClusters;
  49. const uint32_t BASISU_MAX_SLICES = 0xFFFFFF;
  50. const int BASISU_RDO_UASTC_DICT_SIZE_DEFAULT = 4096; // 32768;
  51. const int BASISU_RDO_UASTC_DICT_SIZE_MIN = 64;
  52. const int BASISU_RDO_UASTC_DICT_SIZE_MAX = 65536;
  53. struct image_stats
  54. {
  55. image_stats()
  56. {
  57. clear();
  58. }
  59. void clear()
  60. {
  61. m_filename.clear();
  62. m_width = 0;
  63. m_height = 0;
  64. m_basis_rgb_avg_psnr = 0.0f;
  65. m_basis_rgba_avg_psnr = 0.0f;
  66. m_basis_a_avg_psnr = 0.0f;
  67. m_basis_luma_709_psnr = 0.0f;
  68. m_basis_luma_601_psnr = 0.0f;
  69. m_basis_luma_709_ssim = 0.0f;
  70. m_basis_rgb_avg_bc6h_psnr = 0.0f;
  71. m_bc7_rgb_avg_psnr = 0.0f;
  72. m_bc7_rgba_avg_psnr = 0.0f;
  73. m_bc7_a_avg_psnr = 0.0f;
  74. m_bc7_luma_709_psnr = 0.0f;
  75. m_bc7_luma_601_psnr = 0.0f;
  76. m_bc7_luma_709_ssim = 0.0f;
  77. m_best_etc1s_rgb_avg_psnr = 0.0f;
  78. m_best_etc1s_luma_709_psnr = 0.0f;
  79. m_best_etc1s_luma_601_psnr = 0.0f;
  80. m_best_etc1s_luma_709_ssim = 0.0f;
  81. m_opencl_failed = false;
  82. }
  83. std::string m_filename;
  84. uint32_t m_width;
  85. uint32_t m_height;
  86. // .basis/.ktx2 compressed (LDR: ETC1S or UASTC statistics, HDR: transcoded BC6H statistics)
  87. float m_basis_rgb_avg_psnr;
  88. float m_basis_rgba_avg_psnr;
  89. float m_basis_a_avg_psnr;
  90. float m_basis_luma_709_psnr;
  91. float m_basis_luma_601_psnr;
  92. float m_basis_luma_709_ssim;
  93. // UASTC HDR only.
  94. float m_basis_rgb_avg_bc6h_psnr;
  95. // LDR: BC7 statistics
  96. float m_bc7_rgb_avg_psnr;
  97. float m_bc7_rgba_avg_psnr;
  98. float m_bc7_a_avg_psnr;
  99. float m_bc7_luma_709_psnr;
  100. float m_bc7_luma_601_psnr;
  101. float m_bc7_luma_709_ssim;
  102. // LDR: Highest achievable quality ETC1S statistics
  103. float m_best_etc1s_rgb_avg_psnr;
  104. float m_best_etc1s_luma_709_psnr;
  105. float m_best_etc1s_luma_601_psnr;
  106. float m_best_etc1s_luma_709_ssim;
  107. bool m_opencl_failed;
  108. };
  109. template<bool def>
  110. struct bool_param
  111. {
  112. bool_param() :
  113. m_value(def),
  114. m_changed(false)
  115. {
  116. }
  117. void clear()
  118. {
  119. m_value = def;
  120. m_changed = false;
  121. }
  122. operator bool() const
  123. {
  124. return m_value;
  125. }
  126. bool operator= (bool v)
  127. {
  128. m_value = v;
  129. m_changed = true;
  130. return m_value;
  131. }
  132. bool was_changed() const { return m_changed; }
  133. void set_changed(bool flag) { m_changed = flag; }
  134. bool m_value;
  135. bool m_changed;
  136. };
  137. template<typename T>
  138. struct param
  139. {
  140. param(T def, T min_v, T max_v) :
  141. m_value(def),
  142. m_def(def),
  143. m_min(min_v),
  144. m_max(max_v),
  145. m_changed(false)
  146. {
  147. }
  148. void clear()
  149. {
  150. m_value = m_def;
  151. m_changed = false;
  152. }
  153. operator T() const
  154. {
  155. return m_value;
  156. }
  157. T operator= (T v)
  158. {
  159. m_value = clamp<T>(v, m_min, m_max);
  160. m_changed = true;
  161. return m_value;
  162. }
  163. T operator *= (T v)
  164. {
  165. m_value *= v;
  166. m_changed = true;
  167. return m_value;
  168. }
  169. bool was_changed() const { return m_changed; }
  170. void set_changed(bool flag) { m_changed = flag; }
  171. T m_value;
  172. T m_def;
  173. T m_min;
  174. T m_max;
  175. bool m_changed;
  176. };
  177. struct basis_compressor_params
  178. {
  179. basis_compressor_params() :
  180. m_compression_level((int)BASISU_DEFAULT_COMPRESSION_LEVEL, 0, (int)BASISU_MAX_COMPRESSION_LEVEL),
  181. m_selector_rdo_thresh(BASISU_DEFAULT_SELECTOR_RDO_THRESH, 0.0f, 1e+10f),
  182. m_endpoint_rdo_thresh(BASISU_DEFAULT_ENDPOINT_RDO_THRESH, 0.0f, 1e+10f),
  183. m_mip_scale(1.0f, .000125f, 4.0f),
  184. m_mip_smallest_dimension(1, 1, 16384),
  185. m_max_endpoint_clusters(512),
  186. m_max_selector_clusters(512),
  187. m_quality_level(-1),
  188. m_pack_uastc_flags(cPackUASTCLevelDefault),
  189. m_rdo_uastc_quality_scalar(1.0f, 0.001f, 50.0f),
  190. m_rdo_uastc_dict_size(BASISU_RDO_UASTC_DICT_SIZE_DEFAULT, BASISU_RDO_UASTC_DICT_SIZE_MIN, BASISU_RDO_UASTC_DICT_SIZE_MAX),
  191. m_rdo_uastc_max_smooth_block_error_scale(UASTC_RDO_DEFAULT_SMOOTH_BLOCK_MAX_ERROR_SCALE, 1.0f, 300.0f),
  192. m_rdo_uastc_smooth_block_max_std_dev(UASTC_RDO_DEFAULT_MAX_SMOOTH_BLOCK_STD_DEV, .01f, 65536.0f),
  193. m_rdo_uastc_max_allowed_rms_increase_ratio(UASTC_RDO_DEFAULT_MAX_ALLOWED_RMS_INCREASE_RATIO, .01f, 100.0f),
  194. m_rdo_uastc_skip_block_rms_thresh(UASTC_RDO_DEFAULT_SKIP_BLOCK_RMS_THRESH, .01f, 100.0f),
  195. m_resample_width(0, 1, 16384),
  196. m_resample_height(0, 1, 16384),
  197. m_resample_factor(0.0f, .00125f, 100.0f),
  198. m_ktx2_uastc_supercompression(basist::KTX2_SS_NONE),
  199. m_ktx2_zstd_supercompression_level(6, INT_MIN, INT_MAX),
  200. m_pJob_pool(nullptr)
  201. {
  202. clear();
  203. }
  204. void clear()
  205. {
  206. m_uastc.clear();
  207. m_use_opencl.clear();
  208. m_status_output.clear();
  209. m_source_filenames.clear();
  210. m_source_alpha_filenames.clear();
  211. m_source_images.clear();
  212. m_source_mipmap_images.clear();
  213. m_out_filename.clear();
  214. m_y_flip.clear();
  215. m_debug.clear();
  216. m_validate_etc1s.clear();
  217. m_debug_images.clear();
  218. m_perceptual.clear();
  219. m_no_selector_rdo.clear();
  220. m_selector_rdo_thresh.clear();
  221. m_read_source_images.clear();
  222. m_write_output_basis_or_ktx2_files.clear();
  223. m_compression_level.clear();
  224. m_compute_stats.clear();
  225. m_print_stats.clear();
  226. m_check_for_alpha.clear();
  227. m_force_alpha.clear();
  228. m_multithreading.clear();
  229. m_swizzle[0] = 0;
  230. m_swizzle[1] = 1;
  231. m_swizzle[2] = 2;
  232. m_swizzle[3] = 3;
  233. m_renormalize.clear();
  234. m_disable_hierarchical_endpoint_codebooks.clear();
  235. m_no_endpoint_rdo.clear();
  236. m_endpoint_rdo_thresh.clear();
  237. m_mip_gen.clear();
  238. m_mip_scale.clear();
  239. m_mip_filter = "kaiser";
  240. m_mip_scale = 1.0f;
  241. m_mip_srgb.clear();
  242. m_mip_premultiplied.clear();
  243. m_mip_renormalize.clear();
  244. m_mip_wrapping.clear();
  245. m_mip_fast.clear();
  246. m_mip_smallest_dimension.clear();
  247. m_max_endpoint_clusters = 0;
  248. m_max_selector_clusters = 0;
  249. m_quality_level = -1;
  250. m_tex_type = basist::cBASISTexType2D;
  251. m_userdata0 = 0;
  252. m_userdata1 = 0;
  253. m_us_per_frame = 0;
  254. m_pack_uastc_flags = cPackUASTCLevelDefault;
  255. m_rdo_uastc.clear();
  256. m_rdo_uastc_quality_scalar.clear();
  257. m_rdo_uastc_max_smooth_block_error_scale.clear();
  258. m_rdo_uastc_smooth_block_max_std_dev.clear();
  259. m_rdo_uastc_max_allowed_rms_increase_ratio.clear();
  260. m_rdo_uastc_skip_block_rms_thresh.clear();
  261. m_rdo_uastc_favor_simpler_modes_in_rdo_mode.clear();
  262. m_rdo_uastc_multithreading.clear();
  263. m_resample_width.clear();
  264. m_resample_height.clear();
  265. m_resample_factor.clear();
  266. m_pGlobal_codebooks = nullptr;
  267. m_create_ktx2_file.clear();
  268. m_ktx2_uastc_supercompression = basist::KTX2_SS_NONE;
  269. m_ktx2_key_values.clear();
  270. m_ktx2_zstd_supercompression_level.clear();
  271. m_ktx2_srgb_transfer_func.clear();
  272. m_validate_output_data.clear();
  273. m_hdr_ldr_srgb_to_linear_conversion.clear();
  274. m_hdr_favor_astc.clear();
  275. m_pJob_pool = nullptr;
  276. }
  277. // True to generate UASTC .basis/.KTX2 file data, otherwise ETC1S.
  278. bool_param<false> m_uastc;
  279. // Set m_hdr to true to switch to UASTC HDR mode.
  280. bool_param<false> m_hdr;
  281. bool_param<false> m_use_opencl;
  282. // If m_read_source_images is true, m_source_filenames (and optionally m_source_alpha_filenames) contains the filenames of PNG etc. images to read.
  283. // Otherwise, the compressor processes the images in m_source_images or m_source_images_hdr.
  284. basisu::vector<std::string> m_source_filenames;
  285. basisu::vector<std::string> m_source_alpha_filenames;
  286. basisu::vector<image> m_source_images;
  287. basisu::vector<imagef> m_source_images_hdr;
  288. // Stores mipmaps starting from level 1. Level 0 is still stored in m_source_images, as usual.
  289. // If m_source_mipmaps isn't empty, automatic mipmap generation isn't done. m_source_mipmaps.size() MUST equal m_source_images.size() or the compressor returns an error.
  290. // The compressor applies the user-provided swizzling (in m_swizzle) to these images.
  291. basisu::vector< basisu::vector<image> > m_source_mipmap_images;
  292. basisu::vector< basisu::vector<imagef> > m_source_mipmap_images_hdr;
  293. // Filename of the output basis/ktx2 file
  294. std::string m_out_filename;
  295. // The params are done this way so we can detect when the user has explictly changed them.
  296. // Flip images across Y axis
  297. bool_param<false> m_y_flip;
  298. // If true, the compressor will print basis status to stdout during compression.
  299. bool_param<true> m_status_output;
  300. // Output debug information during compression
  301. bool_param<false> m_debug;
  302. bool_param<false> m_validate_etc1s;
  303. // m_debug_images is pretty slow
  304. bool_param<false> m_debug_images;
  305. // ETC1S compression level, from 0 to BASISU_MAX_COMPRESSION_LEVEL (higher is slower).
  306. // This parameter controls numerous internal encoding speed vs. compression efficiency/performance tradeoffs.
  307. // Note this is NOT the same as the ETC1S quality level, and most users shouldn't change this.
  308. param<int> m_compression_level;
  309. // Use perceptual sRGB colorspace metrics instead of linear
  310. bool_param<true> m_perceptual;
  311. // Disable selector RDO, for faster compression but larger files
  312. bool_param<false> m_no_selector_rdo;
  313. param<float> m_selector_rdo_thresh;
  314. bool_param<false> m_no_endpoint_rdo;
  315. param<float> m_endpoint_rdo_thresh;
  316. // Read source images from m_source_filenames/m_source_alpha_filenames
  317. bool_param<false> m_read_source_images;
  318. // Write the output basis/ktx2 file to disk using m_out_filename
  319. bool_param<false> m_write_output_basis_or_ktx2_files;
  320. // Compute and display image metrics
  321. bool_param<false> m_compute_stats;
  322. // Print stats to stdout, if m_compute_stats is true.
  323. bool_param<true> m_print_stats;
  324. // Check to see if any input image has an alpha channel, if so then the output basis/ktx2 file will have alpha channels
  325. bool_param<true> m_check_for_alpha;
  326. // Always put alpha slices in the output basis/ktx2 file, even when the input doesn't have alpha
  327. bool_param<false> m_force_alpha;
  328. bool_param<true> m_multithreading;
  329. // Split the R channel to RGB and the G channel to alpha, then write a basis/ktx2 file with alpha channels
  330. uint8_t m_swizzle[4];
  331. bool_param<false> m_renormalize;
  332. // If true the front end will not use 2 level endpoint codebook searching, for slightly higher quality but much slower execution.
  333. // Note some m_compression_level's disable this automatically.
  334. bool_param<false> m_disable_hierarchical_endpoint_codebooks;
  335. // mipmap generation parameters
  336. bool_param<false> m_mip_gen;
  337. param<float> m_mip_scale;
  338. std::string m_mip_filter;
  339. bool_param<false> m_mip_srgb;
  340. bool_param<true> m_mip_premultiplied; // not currently supported
  341. bool_param<false> m_mip_renormalize;
  342. bool_param<true> m_mip_wrapping;
  343. bool_param<true> m_mip_fast;
  344. param<int> m_mip_smallest_dimension;
  345. // Codebook size (quality) control.
  346. // If m_quality_level != -1, it controls the quality level. It ranges from [1,255] or [BASISU_QUALITY_MIN, BASISU_QUALITY_MAX].
  347. // Otherwise m_max_endpoint_clusters/m_max_selector_clusters controls the codebook sizes directly.
  348. uint32_t m_max_endpoint_clusters;
  349. uint32_t m_max_selector_clusters;
  350. int m_quality_level;
  351. // m_tex_type, m_userdata0, m_userdata1, m_framerate - These fields go directly into the Basis file header.
  352. basist::basis_texture_type m_tex_type;
  353. uint32_t m_userdata0;
  354. uint32_t m_userdata1;
  355. uint32_t m_us_per_frame;
  356. // cPackUASTCLevelDefault, etc.
  357. uint32_t m_pack_uastc_flags;
  358. bool_param<false> m_rdo_uastc;
  359. param<float> m_rdo_uastc_quality_scalar;
  360. param<int> m_rdo_uastc_dict_size;
  361. param<float> m_rdo_uastc_max_smooth_block_error_scale;
  362. param<float> m_rdo_uastc_smooth_block_max_std_dev;
  363. param<float> m_rdo_uastc_max_allowed_rms_increase_ratio;
  364. param<float> m_rdo_uastc_skip_block_rms_thresh;
  365. bool_param<true> m_rdo_uastc_favor_simpler_modes_in_rdo_mode;
  366. bool_param<true> m_rdo_uastc_multithreading;
  367. param<int> m_resample_width;
  368. param<int> m_resample_height;
  369. param<float> m_resample_factor;
  370. const basist::basisu_lowlevel_etc1s_transcoder *m_pGlobal_codebooks;
  371. // KTX2 specific parameters.
  372. // Internally, the compressor always creates a .basis file then it converts that lossless to KTX2.
  373. bool_param<false> m_create_ktx2_file;
  374. basist::ktx2_supercompression m_ktx2_uastc_supercompression;
  375. basist::ktx2_transcoder::key_value_vec m_ktx2_key_values;
  376. param<int> m_ktx2_zstd_supercompression_level;
  377. bool_param<false> m_ktx2_srgb_transfer_func;
  378. astc_hdr_codec_options m_uastc_hdr_options;
  379. bool_param<false> m_validate_output_data;
  380. // If true, LDR images (such as PNG) will be converted to normalized [0,1] linear light (via a sRGB->Linear conversion) and then processed as HDR.
  381. // Otherwise, LDR images will be processed as HDR as-is.
  382. bool_param<true> m_hdr_ldr_srgb_to_linear_conversion;
  383. // If true, ASTC HDR quality is favored more than BC6H quality. Otherwise it's a rough balance.
  384. bool_param<false> m_hdr_favor_astc;
  385. job_pool *m_pJob_pool;
  386. };
  387. // Important: basisu_encoder_init() MUST be called first before using this class.
  388. class basis_compressor
  389. {
  390. BASISU_NO_EQUALS_OR_COPY_CONSTRUCT(basis_compressor);
  391. public:
  392. basis_compressor();
  393. ~basis_compressor();
  394. // Note it *should* be possible to call init() multiple times with different inputs, but this scenario isn't well tested. Ideally, create 1 object, compress, then delete it.
  395. bool init(const basis_compressor_params &params);
  396. enum error_code
  397. {
  398. cECSuccess = 0,
  399. cECFailedInitializing,
  400. cECFailedReadingSourceImages,
  401. cECFailedValidating,
  402. cECFailedEncodeUASTC,
  403. cECFailedFrontEnd,
  404. cECFailedFontendExtract,
  405. cECFailedBackend,
  406. cECFailedCreateBasisFile,
  407. cECFailedWritingOutput,
  408. cECFailedUASTCRDOPostProcess,
  409. cECFailedCreateKTX2File
  410. };
  411. error_code process();
  412. // The output .basis file will always be valid of process() succeeded.
  413. const uint8_vec &get_output_basis_file() const { return m_output_basis_file; }
  414. // The output .ktx2 file will only be valid if m_create_ktx2_file was true and process() succeeded.
  415. const uint8_vec& get_output_ktx2_file() const { return m_output_ktx2_file; }
  416. const basisu::vector<image_stats> &get_stats() const { return m_stats; }
  417. uint32_t get_basis_file_size() const { return m_basis_file_size; }
  418. double get_basis_bits_per_texel() const { return m_basis_bits_per_texel; }
  419. bool get_any_source_image_has_alpha() const { return m_any_source_image_has_alpha; }
  420. bool get_opencl_failed() const { return m_opencl_failed; }
  421. private:
  422. basis_compressor_params m_params;
  423. opencl_context_ptr m_pOpenCL_context;
  424. basisu::vector<image> m_slice_images;
  425. basisu::vector<imagef> m_slice_images_hdr;
  426. basisu::vector<image_stats> m_stats;
  427. uint32_t m_basis_file_size;
  428. double m_basis_bits_per_texel;
  429. basisu_backend_slice_desc_vec m_slice_descs;
  430. uint32_t m_total_blocks;
  431. basisu_frontend m_frontend;
  432. pixel_block_vec m_source_blocks;
  433. pixel_block_hdr_vec m_source_blocks_hdr;
  434. basisu::vector<gpu_image> m_frontend_output_textures;
  435. basisu::vector<gpu_image> m_best_etc1s_images;
  436. basisu::vector<image> m_best_etc1s_images_unpacked;
  437. basisu_backend m_backend;
  438. basisu_file m_basis_file;
  439. basisu::vector<gpu_image> m_decoded_output_textures; // BC6H in HDR mode
  440. basisu::vector<image> m_decoded_output_textures_unpacked;
  441. basisu::vector<gpu_image> m_decoded_output_textures_bc7;
  442. basisu::vector<image> m_decoded_output_textures_unpacked_bc7;
  443. basisu::vector<imagef> m_decoded_output_textures_bc6h_hdr_unpacked; // BC6H in HDR mode
  444. basisu::vector<gpu_image> m_decoded_output_textures_astc_hdr;
  445. basisu::vector<imagef> m_decoded_output_textures_astc_hdr_unpacked;
  446. uint8_vec m_output_basis_file;
  447. uint8_vec m_output_ktx2_file;
  448. basisu::vector<gpu_image> m_uastc_slice_textures;
  449. basisu_backend_output m_uastc_backend_output;
  450. bool m_any_source_image_has_alpha;
  451. bool m_opencl_failed;
  452. void check_for_hdr_inputs();
  453. bool sanity_check_input_params();
  454. void clean_hdr_image(imagef& src_img);
  455. bool read_dds_source_images();
  456. bool read_source_images();
  457. bool extract_source_blocks();
  458. bool process_frontend();
  459. bool extract_frontend_texture_data();
  460. bool process_backend();
  461. bool create_basis_file_and_transcode();
  462. bool write_hdr_debug_images(const char* pBasename, const imagef& img, uint32_t width, uint32_t height);
  463. bool write_output_files_and_compute_stats();
  464. error_code encode_slices_to_uastc_hdr();
  465. error_code encode_slices_to_uastc();
  466. bool generate_mipmaps(const imagef& img, basisu::vector<imagef>& mips, bool has_alpha);
  467. bool generate_mipmaps(const image &img, basisu::vector<image> &mips, bool has_alpha);
  468. bool validate_texture_type_constraints();
  469. bool validate_ktx2_constraints();
  470. void get_dfd(uint8_vec& dfd, const basist::ktx2_header& hdr);
  471. bool create_ktx2_file();
  472. };
  473. // Alternative simple C-style wrapper API around the basis_compressor class.
  474. // This doesn't expose every encoder feature, but it's enough to get going.
  475. // Important: basisu_encoder_init() MUST be called first before calling these functions.
  476. //
  477. // Input parameters:
  478. // source_images: Array of "image" objects, one per mipmap level, largest mipmap level first.
  479. // OR
  480. // pImageRGBA: pointer to a 32-bpp RGBx or RGBA raster image, R first in memory, A last. Top scanline first in memory.
  481. // width/height/pitch_in_pixels: dimensions of pImageRGBA
  482. //
  483. // flags_and_quality: Combination of the above flags logically OR'd with the ETC1S or UASTC level, i.e. "cFlagSRGB | cFlagGenMipsClamp | cFlagThreaded | 128" or "cFlagSRGB | cFlagGenMipsClamp | cFlagUASTC | cFlagThreaded | cPackUASTCLevelDefault".
  484. // In ETC1S mode, the lower 8-bits are the ETC1S quality level which ranges from [1,255] (higher=better quality/larger files)
  485. // In UASTC mode, the lower 8-bits are the UASTC LDR/HDR pack level (see cPackUASTCLevelFastest, etc.). Fastest/lowest quality is 0, so be sure to set it correctly. Valid values are [0,4] for both LDR/HDR.
  486. // In UASTC mode, be sure to set this, otherwise it defaults to 0 (fastest/lowest quality).
  487. //
  488. // uastc_rdo_quality: Float UASTC RDO quality level (0=no change, higher values lower quality but increase compressibility, initially try .5-1.5)
  489. //
  490. // pSize: Returns the output data's compressed size in bytes
  491. //
  492. // Return value is the compressed .basis or .ktx2 file data, or nullptr on failure. Must call basis_free() to free it.
  493. enum
  494. {
  495. cFlagUseOpenCL = 1 << 8, // use OpenCL if available
  496. cFlagThreaded = 1 << 9, // use multiple threads for compression
  497. cFlagDebug = 1 << 10, // enable debug output
  498. cFlagKTX2 = 1 << 11, // generate a KTX2 file
  499. cFlagKTX2UASTCSuperCompression = 1 << 12, // use KTX2 Zstd supercompression on UASTC files
  500. cFlagSRGB = 1 << 13, // input texture is sRGB, use perceptual colorspace metrics, also use sRGB filtering during mipmap gen, and also sets KTX2 output transfer func to sRGB
  501. cFlagGenMipsClamp = 1 << 14, // generate mipmaps with clamp addressing
  502. cFlagGenMipsWrap = 1 << 15, // generate mipmaps with wrap addressing
  503. cFlagYFlip = 1 << 16, // flip source image on Y axis before compression
  504. cFlagUASTC = 1 << 17, // use UASTC compression vs. ETC1S
  505. cFlagUASTCRDO = 1 << 18, // use RDO postprocessing when generating UASTC files (must set uastc_rdo_quality to the quality scalar)
  506. cFlagPrintStats = 1 << 19, // print image stats to stdout
  507. cFlagPrintStatus = 1 << 20, // print status to stdout
  508. cFlagHDR = 1 << 21, // Force encoder into HDR mode, even if source image is LDR.
  509. cFlagHDRLDRImageSRGBToLinearConversion = 1 << 22, // In HDR mode, convert LDR source images to linear before encoding.
  510. cFlagDebugImages = 1 << 23 // enable status output
  511. };
  512. // This function accepts an array of source images.
  513. // If more than one image is provided, it's assumed the images form a mipmap pyramid and automatic mipmap generation is disabled.
  514. // Returns a pointer to the compressed .basis or .ktx2 file data. *pSize is the size of the compressed data.
  515. // Important: The returned block MUST be manually freed using basis_free_data().
  516. // basisu_encoder_init() MUST be called first!
  517. // LDR version. To compress the LDR source image as HDR: Use the cFlagHDR flag.
  518. void* basis_compress(
  519. const basisu::vector<image> &source_images,
  520. uint32_t flags_and_quality, float uastc_rdo_quality,
  521. size_t* pSize,
  522. image_stats* pStats = nullptr);
  523. // HDR-only version.
  524. // Important: The returned block MUST be manually freed using basis_free_data().
  525. void* basis_compress(
  526. const basisu::vector<imagef>& source_images_hdr,
  527. uint32_t flags_and_quality,
  528. size_t* pSize,
  529. image_stats* pStats = nullptr);
  530. // This function only accepts a single LDR source image. It's just a wrapper for basis_compress() above.
  531. // Important: The returned block MUST be manually freed using basis_free_data().
  532. void* basis_compress(
  533. const uint8_t* pImageRGBA, uint32_t width, uint32_t height, uint32_t pitch_in_pixels,
  534. uint32_t flags_and_quality, float uastc_rdo_quality,
  535. size_t* pSize,
  536. image_stats* pStats = nullptr);
  537. // Frees the dynamically allocated file data returned by basis_compress().
  538. // This MUST be called on the pointer returned by basis_compress() when you're done with it.
  539. void basis_free_data(void* p);
  540. // Runs a short benchmark using synthetic image data to time OpenCL encoding vs. CPU encoding, with multithreading enabled.
  541. // Returns true if opencl is worth using on this system, otherwise false.
  542. // If pOpenCL_failed is not null, it will be set to true if OpenCL encoding failed *on this particular machine/driver/BasisU version* and the encoder falled back to CPU encoding.
  543. // basisu_encoder_init() MUST be called first. If OpenCL support wasn't enabled this always returns false.
  544. bool basis_benchmark_etc1s_opencl(bool *pOpenCL_failed = nullptr);
  545. // Parallel compression API
  546. struct parallel_results
  547. {
  548. double m_total_time;
  549. basis_compressor::error_code m_error_code;
  550. uint8_vec m_basis_file;
  551. uint8_vec m_ktx2_file;
  552. basisu::vector<image_stats> m_stats;
  553. double m_basis_bits_per_texel;
  554. bool m_any_source_image_has_alpha;
  555. parallel_results()
  556. {
  557. clear();
  558. }
  559. void clear()
  560. {
  561. m_total_time = 0.0f;
  562. m_error_code = basis_compressor::cECFailedInitializing;
  563. m_basis_file.clear();
  564. m_ktx2_file.clear();
  565. m_stats.clear();
  566. m_basis_bits_per_texel = 0.0f;
  567. m_any_source_image_has_alpha = false;
  568. }
  569. };
  570. // Compresses an array of input textures across total_threads threads using the basis_compressor class.
  571. // Compressing multiple textures at a time is substantially more efficient than just compressing one at a time.
  572. // total_threads must be >= 1.
  573. bool basis_parallel_compress(
  574. uint32_t total_threads,
  575. const basisu::vector<basis_compressor_params> &params_vec,
  576. basisu::vector< parallel_results > &results_vec);
  577. } // namespace basisu