Path: blob/master/thirdparty/basis_universal/encoder/basisu_frontend.h
9902 views
// basisu_frontend.h1// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7// http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14#pragma once15#include "basisu_enc.h"16#include "basisu_etc.h"17#include "basisu_gpu_texture.h"18#include "../transcoder/basisu_file_headers.h"19#include "../transcoder/basisu_transcoder.h"2021namespace basisu22{23struct opencl_context;24typedef opencl_context* opencl_context_ptr;2526struct vec2U27{28uint32_t m_comps[2];2930vec2U() { }31vec2U(uint32_t a, uint32_t b) { set(a, b); }3233void set(uint32_t a, uint32_t b) { m_comps[0] = a; m_comps[1] = b; }3435uint32_t operator[] (uint32_t i) const { assert(i < 2); return m_comps[i]; }36uint32_t &operator[] (uint32_t i) { assert(i < 2); return m_comps[i]; }37};3839const uint32_t BASISU_DEFAULT_COMPRESSION_LEVEL = 2;40const uint32_t BASISU_MAX_COMPRESSION_LEVEL = 6;4142class basisu_frontend43{44BASISU_NO_EQUALS_OR_COPY_CONSTRUCT(basisu_frontend);4546public:4748basisu_frontend() :49m_total_blocks(0),50m_total_pixels(0),51m_endpoint_refinement(false),52m_use_hierarchical_endpoint_codebooks(false),53m_use_hierarchical_selector_codebooks(false),54m_num_endpoint_codebook_iterations(0),55m_num_selector_codebook_iterations(0),56m_opencl_failed(false)57{58}5960enum61{62cMaxEndpointClusters = 16128,6364cMaxSelectorClusters = 16128,65};6667struct params68{69params() :70m_num_source_blocks(0),71m_pSource_blocks(NULL),72m_max_endpoint_clusters(256),73m_max_selector_clusters(256),74m_compression_level(BASISU_DEFAULT_COMPRESSION_LEVEL),75m_perceptual(true),76m_debug_stats(false),77m_debug_images(false),78m_dump_endpoint_clusterization(true),79m_validate(false),80m_multithreaded(false),81m_disable_hierarchical_endpoint_codebooks(false),82m_tex_type(basist::cBASISTexType2D),83m_pOpenCL_context(nullptr),84m_pJob_pool(nullptr)85{86}8788uint32_t m_num_source_blocks;89pixel_block *m_pSource_blocks;9091uint32_t m_max_endpoint_clusters;92uint32_t m_max_selector_clusters;9394uint32_t m_compression_level;9596bool m_perceptual;97bool m_debug_stats;98bool m_debug_images;99bool m_dump_endpoint_clusterization;100bool m_validate;101bool m_multithreaded;102bool m_disable_hierarchical_endpoint_codebooks;103104basist::basis_texture_type m_tex_type;105const basist::basisu_lowlevel_etc1s_transcoder *m_pGlobal_codebooks;106107opencl_context_ptr m_pOpenCL_context;108109job_pool *m_pJob_pool;110};111112bool init(const params &p);113114bool compress();115116const params &get_params() const { return m_params; }117118const pixel_block &get_source_pixel_block(uint32_t i) const { return m_source_blocks[i]; }119120// RDO output blocks121uint32_t get_total_output_blocks() const { return static_cast<uint32_t>(m_encoded_blocks.size()); }122123const etc_block &get_output_block(uint32_t block_index) const { return m_encoded_blocks[block_index]; }124const etc_block_vec &get_output_blocks() const { return m_encoded_blocks; }125126// "Best" ETC1S blocks127const etc_block &get_etc1s_block(uint32_t block_index) const { return m_etc1_blocks_etc1s[block_index]; }128129// Per-block flags130bool get_diff_flag(uint32_t block_index) const { return m_encoded_blocks[block_index].get_diff_bit(); }131132// Endpoint clusters133uint32_t get_total_endpoint_clusters() const { return static_cast<uint32_t>(m_endpoint_clusters.size()); }134uint32_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]; }135136const 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]; }137uint32_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]; }138139bool 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]; }140141// Selector clusters142uint32_t get_total_selector_clusters() const { return static_cast<uint32_t>(m_selector_cluster_block_indices.size()); }143uint32_t get_block_selector_cluster_index(uint32_t block_index) const { return m_block_selector_cluster_index[block_index]; }144const etc_block &get_selector_cluster_selector_bits(uint32_t cluster_index) const { return m_optimized_cluster_selectors[cluster_index]; }145146// Returns block indices using each selector cluster147const uint_vec &get_selector_cluster_block_indices(uint32_t selector_cluster_index) const { return m_selector_cluster_block_indices[selector_cluster_index]; }148149void dump_debug_image(const char *pFilename, uint32_t first_block, uint32_t num_blocks_x, uint32_t num_blocks_y, bool output_blocks);150151void 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);152153bool get_opencl_failed() const { return m_opencl_failed; }154155private:156params m_params;157uint32_t m_total_blocks;158uint32_t m_total_pixels;159160bool m_endpoint_refinement;161bool m_use_hierarchical_endpoint_codebooks;162bool m_use_hierarchical_selector_codebooks;163164uint32_t m_num_endpoint_codebook_iterations;165uint32_t m_num_selector_codebook_iterations;166167// Source pixels for each blocks168pixel_block_vec m_source_blocks;169170// The quantized ETC1S texture.171etc_block_vec m_encoded_blocks;172173// Quantized blocks after endpoint quant, but before selector quant174etc_block_vec m_orig_encoded_blocks;175176// Full quality ETC1S texture177etc_block_vec m_etc1_blocks_etc1s;178179typedef vec<6, float> vec6F;180181// Endpoint clusterizer182typedef tree_vector_quant<vec6F> vec6F_quantizer;183vec6F_quantizer m_endpoint_clusterizer;184185// For each endpoint cluster: An array of which subblock indices (block_index*2+subblock) are located in that cluster.186basisu::vector<uint_vec> m_endpoint_clusters;187188// Array of subblock indices for each parent endpoint cluster189// Note: Initially, each endpoint cluster will only live in a single parent cluster, in a shallow tree.190// As the endpoint clusters are manipulated this constraint gets broken.191basisu::vector<uint_vec> m_endpoint_parent_clusters;192193// Each block's parent endpoint cluster index194uint8_vec m_block_parent_endpoint_cluster;195196// Array of endpoint cluster indices for each parent endpoint cluster197basisu::vector<uint_vec> m_endpoint_clusters_within_each_parent_cluster;198199struct endpoint_cluster_etc_params200{201endpoint_cluster_etc_params()202{203clear();204}205206void clear()207{208clear_obj(m_color_unscaled);209clear_obj(m_inten_table);210clear_obj(m_color_error);211m_subblocks.clear();212213clear_obj(m_color_used);214m_valid = false;215}216217// TODO: basisu doesn't use individual mode.218color_rgba m_color_unscaled[2]; // [use_individual_mode]219uint32_t m_inten_table[2];220221uint64_t m_color_error[2];222223uint_vec m_subblocks;224225bool m_color_used[2];226227bool m_valid;228229bool operator== (const endpoint_cluster_etc_params &other) const230{231for (uint32_t i = 0; i < 2; i++)232{233if (m_color_unscaled[i] != other.m_color_unscaled[i])234return false;235}236237if (m_inten_table[0] != other.m_inten_table[0])238return false;239if (m_inten_table[1] != other.m_inten_table[1])240return false;241242return true;243}244245bool operator< (const endpoint_cluster_etc_params &other) const246{247for (uint32_t i = 0; i < 2; i++)248{249if (m_color_unscaled[i] < other.m_color_unscaled[i])250return true;251else if (m_color_unscaled[i] != other.m_color_unscaled[i])252return false;253}254255if (m_inten_table[0] < other.m_inten_table[0])256return true;257else if (m_inten_table[0] == other.m_inten_table[0])258{259if (m_inten_table[1] < other.m_inten_table[1])260return true;261}262263return false;264}265};266267typedef basisu::vector<endpoint_cluster_etc_params> cluster_subblock_etc_params_vec;268269// Each endpoint cluster's ETC1S parameters270cluster_subblock_etc_params_vec m_endpoint_cluster_etc_params;271272// The endpoint cluster index used by each ETC1 subblock.273basisu::vector<vec2U> m_block_endpoint_clusters_indices;274275// The block(s) within each selector cluster276// Note: If you add anything here that uses selector cluster indicies, be sure to update optimize_selector_codebook()!277basisu::vector<uint_vec> m_selector_cluster_block_indices;278279// The selector bits for each selector cluster.280basisu::vector<etc_block> m_optimized_cluster_selectors;281282// The block(s) within each parent selector cluster.283basisu::vector<uint_vec> m_selector_parent_cluster_block_indices;284285// Each block's parent selector cluster286uint8_vec m_block_parent_selector_cluster;287288// Array of selector cluster indices for each parent selector cluster289basisu::vector<uint_vec> m_selector_clusters_within_each_parent_cluster;290291// Each block's selector cluster index292basisu::vector<uint32_t> m_block_selector_cluster_index;293294struct subblock_endpoint_quant_err295{296uint64_t m_total_err;297uint32_t m_cluster_index;298uint32_t m_cluster_subblock_index;299uint32_t m_block_index;300uint32_t m_subblock_index;301302bool operator< (const subblock_endpoint_quant_err &rhs) const303{304if (m_total_err < rhs.m_total_err)305return true;306else if (m_total_err == rhs.m_total_err)307{308if (m_block_index < rhs.m_block_index)309return true;310else if (m_block_index == rhs.m_block_index)311return m_subblock_index < rhs.m_subblock_index;312}313return false;314}315};316317// The sorted subblock endpoint quant error for each endpoint cluster318basisu::vector<subblock_endpoint_quant_err> m_subblock_endpoint_quant_err_vec;319320std::mutex m_lock;321322bool m_opencl_failed;323324//-----------------------------------------------------------------------------325326void init_etc1_images();327bool init_global_codebooks();328void init_endpoint_training_vectors();329void dump_endpoint_clusterization_visualization(const char *pFilename, bool vis_endpoint_colors);330void generate_endpoint_clusters();331void compute_endpoint_subblock_error_vec();332void introduce_new_endpoint_clusters();333void generate_endpoint_codebook(uint32_t step);334uint32_t refine_endpoint_clusterization();335void eliminate_redundant_or_empty_endpoint_clusters();336void generate_block_endpoint_clusters();337void compute_endpoint_clusters_within_each_parent_cluster();338void compute_selector_clusters_within_each_parent_cluster();339void create_initial_packed_texture();340void generate_selector_clusters();341void create_optimized_selector_codebook(uint32_t iter);342void find_optimal_selector_clusters_for_each_block();343uint32_t refine_block_endpoints_given_selectors();344void finalize();345bool validate_endpoint_cluster_hierarchy(bool ensure_clusters_have_same_parents) const;346bool validate_output() const;347void introduce_special_selector_clusters();348void optimize_selector_codebook();349bool check_etc1s_constraints() const;350};351352} // namespace basisu353354355