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