Path: blob/master/thirdparty/basis_universal/encoder/basisu_backend.h
9903 views
// basisu_backend.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 once1516#include "../transcoder/basisu.h"17#include "basisu_enc.h"18#include "../transcoder/basisu_transcoder_internal.h"19#include "basisu_frontend.h"2021namespace basisu22{23struct etc1_selector_palette_entry24{25etc1_selector_palette_entry()26{27clear();28}2930void clear()31{32basisu::clear_obj(*this);33}3435uint8_t operator[] (uint32_t i) const { assert(i < 16); return m_selectors[i]; }36uint8_t& operator[] (uint32_t i) { assert(i < 16); return m_selectors[i]; }3738void set_uint32(uint32_t v)39{40for (uint32_t byte_index = 0; byte_index < 4; byte_index++)41{42uint32_t b = (v >> (byte_index * 8)) & 0xFF;4344m_selectors[byte_index * 4 + 0] = b & 3;45m_selectors[byte_index * 4 + 1] = (b >> 2) & 3;46m_selectors[byte_index * 4 + 2] = (b >> 4) & 3;47m_selectors[byte_index * 4 + 3] = (b >> 6) & 3;48}49}5051uint32_t get_uint32() const52{53return get_byte(0) | (get_byte(1) << 8) | (get_byte(2) << 16) | (get_byte(3) << 24);54}5556uint32_t get_byte(uint32_t byte_index) const57{58assert(byte_index < 4);5960return m_selectors[byte_index * 4 + 0] |61(m_selectors[byte_index * 4 + 1] << 2) |62(m_selectors[byte_index * 4 + 2] << 4) |63(m_selectors[byte_index * 4 + 3] << 6);64}6566uint8_t operator()(uint32_t x, uint32_t y) const { assert((x < 4) && (y < 4)); return m_selectors[x + y * 4]; }67uint8_t& operator()(uint32_t x, uint32_t y) { assert((x < 4) && (y < 4)); return m_selectors[x + y * 4]; }6869bool operator< (const etc1_selector_palette_entry& other) const70{71for (uint32_t i = 0; i < 16; i++)72{73if (m_selectors[i] < other.m_selectors[i])74return true;75else if (m_selectors[i] != other.m_selectors[i])76return false;77}7879return false;80}8182bool operator== (const etc1_selector_palette_entry& other) const83{84for (uint32_t i = 0; i < 16; i++)85{86if (m_selectors[i] != other.m_selectors[i])87return false;88}8990return true;91}9293private:94uint8_t m_selectors[16];95};9697typedef basisu::vector<etc1_selector_palette_entry> etc1_selector_palette_entry_vec;9899struct encoder_block100{101encoder_block()102{103clear();104}105106uint32_t m_endpoint_predictor;107108int m_endpoint_index;109int m_selector_index;110111int m_selector_history_buf_index;112113bool m_is_cr_target;114void clear()115{116m_endpoint_predictor = 0;117118m_endpoint_index = 0;119m_selector_index = 0;120121m_selector_history_buf_index = 0;122m_is_cr_target = false;123}124};125126typedef basisu::vector<encoder_block> encoder_block_vec;127typedef vector2D<encoder_block> encoder_block_vec2D;128129struct etc1_endpoint_palette_entry130{131etc1_endpoint_palette_entry()132{133clear();134}135136color_rgba m_color5;137uint32_t m_inten5;138bool m_color5_valid;139140void clear()141{142clear_obj(*this);143}144};145146typedef basisu::vector<etc1_endpoint_palette_entry> etc1_endpoint_palette_entry_vec;147148struct basisu_backend_params149{150bool m_etc1s;151bool m_debug, m_debug_images;152float m_endpoint_rdo_quality_thresh;153float m_selector_rdo_quality_thresh;154uint32_t m_compression_level;155156bool m_used_global_codebooks;157158bool m_validate;159160basisu_backend_params()161{162clear();163}164165void clear()166{167m_etc1s = false;168m_debug = false;169m_debug_images = false;170m_endpoint_rdo_quality_thresh = 0.0f;171m_selector_rdo_quality_thresh = 0.0f;172m_compression_level = 0;173m_used_global_codebooks = false;174m_validate = true;175}176};177178struct basisu_backend_slice_desc179{180basisu_backend_slice_desc()181{182clear();183}184185void clear()186{187clear_obj(*this);188}189190uint32_t m_first_block_index;191192uint32_t m_orig_width;193uint32_t m_orig_height;194195uint32_t m_width;196uint32_t m_height;197198uint32_t m_num_blocks_x;199uint32_t m_num_blocks_y;200201uint32_t m_num_macroblocks_x;202uint32_t m_num_macroblocks_y;203204uint32_t m_source_file_index; // also the basis image index205uint32_t m_mip_index;206bool m_alpha;207bool m_iframe;208};209210typedef basisu::vector<basisu_backend_slice_desc> basisu_backend_slice_desc_vec;211212struct basisu_backend_output213{214basist::basis_tex_format m_tex_format;215216bool m_etc1s;217bool m_uses_global_codebooks;218bool m_srgb;219220uint32_t m_num_endpoints;221uint32_t m_num_selectors;222223uint8_vec m_endpoint_palette;224uint8_vec m_selector_palette;225226basisu_backend_slice_desc_vec m_slice_desc;227228uint8_vec m_slice_image_tables;229basisu::vector<uint8_vec> m_slice_image_data;230uint16_vec m_slice_image_crcs;231232basisu_backend_output()233{234clear();235}236237void clear()238{239m_tex_format = basist::basis_tex_format::cETC1S;240m_etc1s = false;241m_uses_global_codebooks = false;242m_srgb = true;243244m_num_endpoints = 0;245m_num_selectors = 0;246247m_endpoint_palette.clear();248m_selector_palette.clear();249m_slice_desc.clear();250m_slice_image_tables.clear();251m_slice_image_data.clear();252m_slice_image_crcs.clear();253}254255uint32_t get_output_size_estimate() const256{257uint32_t total_compressed_bytes = (uint32_t)(m_slice_image_tables.size() + m_endpoint_palette.size() + m_selector_palette.size());258for (uint32_t i = 0; i < m_slice_image_data.size(); i++)259total_compressed_bytes += (uint32_t)m_slice_image_data[i].size();260261return total_compressed_bytes;262}263};264265class basisu_backend266{267BASISU_NO_EQUALS_OR_COPY_CONSTRUCT(basisu_backend);268269public:270271basisu_backend();272273void clear();274275void init(basisu_frontend *pFront_end, basisu_backend_params ¶ms, const basisu_backend_slice_desc_vec &slice_desc);276277uint32_t encode();278279const basisu_backend_output &get_output() const { return m_output; }280const basisu_backend_params& get_params() const { return m_params; }281282private:283basisu_frontend *m_pFront_end;284basisu_backend_params m_params;285basisu_backend_slice_desc_vec m_slices;286basisu_backend_output m_output;287288etc1_endpoint_palette_entry_vec m_endpoint_palette;289etc1_selector_palette_entry_vec m_selector_palette;290291struct etc1_global_selector_cb_entry_desc292{293uint32_t m_pal_index;294uint32_t m_mod_index;295bool m_was_used;296};297298typedef basisu::vector<etc1_global_selector_cb_entry_desc> etc1_global_selector_cb_entry_desc_vec;299300etc1_global_selector_cb_entry_desc_vec m_global_selector_palette_desc;301302basisu::vector<encoder_block_vec2D> m_slice_encoder_blocks;303304// Maps OLD to NEW endpoint/selector indices305uint_vec m_endpoint_remap_table_old_to_new;306uint_vec m_endpoint_remap_table_new_to_old;307bool_vec m_old_endpoint_was_used;308bool_vec m_new_endpoint_was_used;309310uint_vec m_selector_remap_table_old_to_new;311312// Maps NEW to OLD endpoint/selector indices313uint_vec m_selector_remap_table_new_to_old;314315uint32_t get_total_slices() const316{317return (uint32_t)m_slices.size();318}319320uint32_t get_total_slice_blocks() const321{322return m_pFront_end->get_total_output_blocks();323}324325uint32_t get_block_index(uint32_t slice_index, uint32_t block_x, uint32_t block_y) const326{327const basisu_backend_slice_desc &slice = m_slices[slice_index];328329assert((block_x < slice.m_num_blocks_x) && (block_y < slice.m_num_blocks_y));330331return slice.m_first_block_index + block_y * slice.m_num_blocks_x + block_x;332}333334uint32_t get_total_blocks(uint32_t slice_index) const335{336return m_slices[slice_index].m_num_blocks_x * m_slices[slice_index].m_num_blocks_y;337}338339uint32_t get_total_blocks() const340{341uint32_t total_blocks = 0;342for (uint32_t i = 0; i < m_slices.size(); i++)343total_blocks += get_total_blocks(i);344return total_blocks;345}346347// Returns the total number of input texels, not counting padding up to blocks/macroblocks.348uint32_t get_total_input_texels(uint32_t slice_index) const349{350return m_slices[slice_index].m_orig_width * m_slices[slice_index].m_orig_height;351}352353uint32_t get_total_input_texels() const354{355uint32_t total_texels = 0;356for (uint32_t i = 0; i < m_slices.size(); i++)357total_texels += get_total_input_texels(i);358return total_texels;359}360361int find_slice(uint32_t block_index, uint32_t *pBlock_x, uint32_t *pBlock_y) const362{363for (uint32_t i = 0; i < m_slices.size(); i++)364{365if ((block_index >= m_slices[i].m_first_block_index) && (block_index < (m_slices[i].m_first_block_index + m_slices[i].m_num_blocks_x * m_slices[i].m_num_blocks_y)))366{367const uint32_t ofs = block_index - m_slices[i].m_first_block_index;368const uint32_t x = ofs % m_slices[i].m_num_blocks_x;369const uint32_t y = ofs / m_slices[i].m_num_blocks_x;370371if (pBlock_x) *pBlock_x = x;372if (pBlock_y) *pBlock_y = y;373374return i;375}376}377return -1;378}379380void create_endpoint_palette();381382void create_selector_palette();383384// endpoint palette385// 5:5:5 and predicted 4:4:4 colors, 1 or 2 3-bit intensity table indices386// selector palette387// 4x4 2-bit selectors388389// per-macroblock:390// 4 diff bits391// 4 flip bits392// Endpoint template index, 1-8 endpoint indices393// Alternately, if no template applies, we can send 4 ETC1S bits followed by 4-8 endpoint indices394// 4 selector indices395396void reoptimize_and_sort_endpoints_codebook(uint32_t total_block_endpoints_remapped, uint_vec &all_endpoint_indices);397void sort_selector_codebook();398void create_encoder_blocks();399void compute_slice_crcs();400bool encode_image();401bool encode_endpoint_palette();402bool encode_selector_palette();403int find_video_frame(int slice_index, int delta);404void check_for_valid_cr_blocks();405};406407} // namespace basisu408409410411