feat: updated engine version to 4.4-rc1
This commit is contained in:
parent
ee00efde1f
commit
21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions
2052
engine/thirdparty/basis_universal/encoder/3rdparty/android_astc_decomp.cpp
vendored
Normal file
2052
engine/thirdparty/basis_universal/encoder/3rdparty/android_astc_decomp.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
45
engine/thirdparty/basis_universal/encoder/3rdparty/android_astc_decomp.h
vendored
Normal file
45
engine/thirdparty/basis_universal/encoder/3rdparty/android_astc_decomp.h
vendored
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// File: android_astc_decomp.h
|
||||
#ifndef _TCUASTCUTIL_HPP
|
||||
#define _TCUASTCUTIL_HPP
|
||||
/*-------------------------------------------------------------------------
|
||||
* drawElements Quality Program Tester Core
|
||||
* ----------------------------------------
|
||||
*
|
||||
* Copyright 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*//*!
|
||||
* \file
|
||||
* \brief ASTC Utilities.
|
||||
*//*--------------------------------------------------------------------*/
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace basisu_astc
|
||||
{
|
||||
namespace astc
|
||||
{
|
||||
|
||||
// Unpacks a single ASTC block to pDst
|
||||
// If isSRGB is true, the spec requires the decoder to scale the LDR 8-bit endpoints to 16-bit before interpolation slightly differently,
|
||||
// which will lead to different outputs. So be sure to set it correctly (ideally it should match whatever the encoder did).
|
||||
bool decompress_ldr(uint8_t* pDst, const uint8_t* data, bool isSRGB, int blockWidth, int blockHeight);
|
||||
bool decompress_hdr(float* pDstRGBA, const uint8_t* data, int blockWidth, int blockHeight);
|
||||
bool is_hdr(const uint8_t* data, int blockWidth, int blockHeight, bool& is_hdr);
|
||||
|
||||
} // astc
|
||||
} // basisu
|
||||
|
||||
#endif
|
||||
3310
engine/thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.cpp
vendored
Normal file
3310
engine/thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.cpp
vendored
Normal file
File diff suppressed because it is too large
Load diff
224
engine/thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.h
vendored
Normal file
224
engine/thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.h
vendored
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
// basisu_astc_hdr_enc.h
|
||||
#pragma once
|
||||
#include "basisu_enc.h"
|
||||
#include "basisu_gpu_texture.h"
|
||||
#include "../transcoder/basisu_astc_helpers.h"
|
||||
#include "../transcoder/basisu_astc_hdr_core.h"
|
||||
|
||||
namespace basisu
|
||||
{
|
||||
// This MUST be called before encoding any blocks.
|
||||
void astc_hdr_enc_init();
|
||||
|
||||
const uint32_t MODE11_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, MODE11_LAST_ISE_RANGE = astc_helpers::BISE_16_LEVELS;
|
||||
const uint32_t MODE7_PART1_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, MODE7_PART1_LAST_ISE_RANGE = astc_helpers::BISE_16_LEVELS;
|
||||
const uint32_t MODE7_PART2_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, MODE7_PART2_LAST_ISE_RANGE = astc_helpers::BISE_8_LEVELS;
|
||||
const uint32_t MODE11_PART2_FIRST_ISE_RANGE = astc_helpers::BISE_3_LEVELS, MODE11_PART2_LAST_ISE_RANGE = astc_helpers::BISE_4_LEVELS;
|
||||
const uint32_t MODE11_TOTAL_SUBMODES = 8; // plus an extra hidden submode, directly encoded, for direct, so really 9 (see tables 99/100 of the ASTC spec)
|
||||
const uint32_t MODE7_TOTAL_SUBMODES = 6;
|
||||
|
||||
struct astc_hdr_codec_options
|
||||
{
|
||||
float m_bc6h_err_weight;
|
||||
|
||||
bool m_use_solid;
|
||||
|
||||
bool m_use_mode11;
|
||||
bool m_mode11_uber_mode;
|
||||
uint32_t m_first_mode11_weight_ise_range;
|
||||
uint32_t m_last_mode11_weight_ise_range;
|
||||
bool m_mode11_direct_only;
|
||||
int32_t m_first_mode11_submode;
|
||||
int32_t m_last_mode11_submode;
|
||||
|
||||
bool m_use_mode7_part1;
|
||||
uint32_t m_first_mode7_part1_weight_ise_range;
|
||||
uint32_t m_last_mode7_part1_weight_ise_range;
|
||||
|
||||
bool m_use_mode7_part2;
|
||||
uint32_t m_mode7_part2_part_masks;
|
||||
uint32_t m_first_mode7_part2_weight_ise_range;
|
||||
uint32_t m_last_mode7_part2_weight_ise_range;
|
||||
|
||||
bool m_use_mode11_part2;
|
||||
uint32_t m_mode11_part2_part_masks;
|
||||
uint32_t m_first_mode11_part2_weight_ise_range;
|
||||
uint32_t m_last_mode11_part2_weight_ise_range;
|
||||
|
||||
float m_r_err_scale, m_g_err_scale;
|
||||
|
||||
bool m_refine_weights;
|
||||
|
||||
uint32_t m_level;
|
||||
|
||||
bool m_use_estimated_partitions;
|
||||
uint32_t m_max_estimated_partitions;
|
||||
|
||||
// If true, the ASTC HDR compressor is allowed to more aggressively vary weight indices for slightly higher compression in non-fastest mode. This will hurt BC6H quality, however.
|
||||
bool m_allow_uber_mode;
|
||||
|
||||
astc_hdr_codec_options();
|
||||
|
||||
void init();
|
||||
|
||||
// TODO: set_quality_level() is preferred to configure the codec for transcoding purposes.
|
||||
static const int cMinLevel = 0;
|
||||
static const int cMaxLevel = 4;
|
||||
static const int cDefaultLevel = 1;
|
||||
void set_quality_level(int level);
|
||||
|
||||
private:
|
||||
void set_quality_best();
|
||||
void set_quality_normal();
|
||||
void set_quality_fastest();
|
||||
};
|
||||
|
||||
struct astc_hdr_pack_results
|
||||
{
|
||||
double m_best_block_error;
|
||||
double m_bc6h_block_error; // note this is not used/set by the encoder, here for convienance
|
||||
|
||||
// Encoder results (logical ASTC block)
|
||||
astc_helpers::log_astc_block m_best_blk;
|
||||
|
||||
// For statistical use
|
||||
uint32_t m_best_submodes[2];
|
||||
uint32_t m_best_pat_index;
|
||||
bool m_constrained_weights;
|
||||
|
||||
bool m_improved_via_refinement_flag;
|
||||
|
||||
// Only valid if the block is solid
|
||||
basist::astc_blk m_solid_blk;
|
||||
|
||||
// The BC6H transcoded block
|
||||
basist::bc6h_block m_bc6h_block;
|
||||
|
||||
// Solid color/void extent flag
|
||||
bool m_is_solid;
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_best_block_error = 1e+30f;
|
||||
m_bc6h_block_error = 1e+30f;
|
||||
|
||||
m_best_blk.clear();
|
||||
m_best_blk.m_grid_width = 4;
|
||||
m_best_blk.m_grid_height = 4;
|
||||
m_best_blk.m_endpoint_ise_range = 20; // 0-255
|
||||
|
||||
clear_obj(m_best_submodes);
|
||||
|
||||
m_best_pat_index = 0;
|
||||
m_constrained_weights = false;
|
||||
|
||||
clear_obj(m_bc6h_block);
|
||||
|
||||
m_is_solid = false;
|
||||
m_improved_via_refinement_flag = false;
|
||||
}
|
||||
};
|
||||
|
||||
void interpolate_qlog12_colors(
|
||||
const int e[2][3],
|
||||
basist::half_float* pDecoded_half,
|
||||
vec3F* pDecoded_float,
|
||||
uint32_t n, uint32_t ise_weight_range);
|
||||
|
||||
bool get_astc_hdr_mode_11_block_colors(
|
||||
const uint8_t* pEndpoints,
|
||||
basist::half_float* pDecoded_half,
|
||||
vec3F* pDecoded_float,
|
||||
uint32_t n, uint32_t ise_weight_range, uint32_t ise_endpoint_range);
|
||||
|
||||
bool get_astc_hdr_mode_7_block_colors(
|
||||
const uint8_t* pEndpoints,
|
||||
basist::half_float* pDecoded_half,
|
||||
vec3F* pDecoded_float,
|
||||
uint32_t n, uint32_t ise_weight_range, uint32_t ise_endpoint_range);
|
||||
|
||||
double eval_selectors(
|
||||
uint32_t num_pixels,
|
||||
uint8_t* pWeights,
|
||||
const basist::half_float* pBlock_pixels_half,
|
||||
uint32_t num_weight_levels,
|
||||
const basist::half_float* pDecoded_half,
|
||||
const astc_hdr_codec_options& coptions,
|
||||
uint32_t usable_selector_bitmask = UINT32_MAX);
|
||||
|
||||
double compute_block_error(const basist::half_float* pOrig_block, const basist::half_float* pPacked_block, const astc_hdr_codec_options& coptions);
|
||||
|
||||
// Encodes a 4x4 ASTC HDR block given a 4x4 array of source block pixels/texels.
|
||||
// Supports solid color blocks, mode 11 (all submodes), mode 7/1 partition (all submodes),
|
||||
// and mode 7/2 partitions (all submodes) - 30 patterns, only the ones also in common with the BC6H format.
|
||||
// The packed ASTC weight grid dimensions are currently always 4x4 texels, but may be also 3x3 in the future.
|
||||
// This function is thread safe, i.e. it may be called from multiple encoding threads simultanously with different blocks.
|
||||
//
|
||||
// Parameters:
|
||||
// pRGBPixels - An array of 48 (16 RGB) floats: the 4x4 block to pack
|
||||
// pPacked_block - A pointer to the packed ASTC HDR block
|
||||
// coptions - Codec options
|
||||
// pInternal_results - An optional pointer to details about how the block was packed, for statistics/debugging purposes. May be nullptr.
|
||||
//
|
||||
// Requirements:
|
||||
// astc_hdr_enc_init() MUST have been called first to initialized the codec.
|
||||
// Input pixels are checked and cannot be NaN's, Inf's, signed, or too large (greater than MAX_HALF_FLOAT, or 65504).
|
||||
// Normal values and denormals are okay.
|
||||
bool astc_hdr_enc_block(
|
||||
const float* pRGBPixels,
|
||||
const astc_hdr_codec_options& coptions,
|
||||
basisu::vector<astc_hdr_pack_results> &all_results);
|
||||
|
||||
bool astc_hdr_pack_results_to_block(basist::astc_blk& dst_blk, const astc_hdr_pack_results& results);
|
||||
|
||||
bool astc_hdr_refine_weights(const basist::half_float* pSource_block, astc_hdr_pack_results& cur_results, const astc_hdr_codec_options& coptions, float bc6h_weight, bool* pImproved_flag);
|
||||
|
||||
struct astc_hdr_block_stats
|
||||
{
|
||||
std::mutex m_mutex;
|
||||
|
||||
uint32_t m_total_blocks;
|
||||
uint32_t m_total_2part, m_total_solid;
|
||||
uint32_t m_total_mode7_1part, m_total_mode7_2part;
|
||||
uint32_t m_total_mode11_1part, m_total_mode11_2part;
|
||||
uint32_t m_total_mode11_1part_constrained_weights;
|
||||
|
||||
uint32_t m_weight_range_hist_7[11];
|
||||
uint32_t m_weight_range_hist_7_2part[11];
|
||||
uint32_t m_mode7_submode_hist[6];
|
||||
|
||||
uint32_t m_weight_range_hist_11[11];
|
||||
uint32_t m_weight_range_hist_11_2part[11];
|
||||
uint32_t m_mode11_submode_hist[9];
|
||||
|
||||
uint32_t m_part_hist[32];
|
||||
|
||||
uint32_t m_total_refined;
|
||||
|
||||
astc_hdr_block_stats() { clear(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
std::lock_guard<std::mutex> lck(m_mutex);
|
||||
|
||||
m_total_blocks = 0;
|
||||
m_total_mode7_1part = 0, m_total_mode7_2part = 0, m_total_mode11_1part = 0, m_total_2part = 0, m_total_solid = 0, m_total_mode11_2part = 0;
|
||||
m_total_mode11_1part_constrained_weights = 0;
|
||||
m_total_refined = 0;
|
||||
|
||||
clear_obj(m_weight_range_hist_11);
|
||||
clear_obj(m_weight_range_hist_11_2part);
|
||||
clear_obj(m_weight_range_hist_7);
|
||||
clear_obj(m_weight_range_hist_7_2part);
|
||||
clear_obj(m_mode7_submode_hist);
|
||||
clear_obj(m_mode11_submode_hist);
|
||||
clear_obj(m_part_hist);
|
||||
}
|
||||
|
||||
void update(const astc_hdr_pack_results& log_blk);
|
||||
|
||||
void print();
|
||||
};
|
||||
|
||||
} // namespace basisu
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_backend.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_backend.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_basis_file.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_basis_file.h
|
||||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// File: basisu_bc7enc.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -394,6 +394,7 @@ void bc7enc_compress_block_init()
|
|||
static void compute_least_squares_endpoints_rgba(uint32_t N, const uint8_t *pSelectors, const bc7enc_vec4F* pSelector_weights, bc7enc_vec4F* pXl, bc7enc_vec4F* pXh, const color_quad_u8 *pColors)
|
||||
{
|
||||
// Least squares using normal equations: http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf
|
||||
// https://web.archive.org/web/20150319232457/http://www.cs.cornell.edu/~bindel/class/cs3220-s12/notes/lec10.pdf
|
||||
// I did this in matrix form first, expanded out all the ops, then optimized it a bit.
|
||||
double z00 = 0.0f, z01 = 0.0f, z10 = 0.0f, z11 = 0.0f;
|
||||
double q00_r = 0.0f, q10_r = 0.0f, t_r = 0.0f;
|
||||
|
|
@ -1301,6 +1302,7 @@ void check_best_overall_error(const color_cell_compressor_params *pParams, color
|
|||
for (uint32_t c = 0; c < 4; c++)
|
||||
colors[i].m_c[c] = (uint8_t)astc_interpolate_linear(colors[0].m_c[c], colors[n - 1].m_c[c], pParams->m_pSelector_weights[i]);
|
||||
|
||||
#ifdef _DEBUG
|
||||
uint64_t total_err = 0;
|
||||
for (uint32_t p = 0; p < pParams->m_num_pixels; p++)
|
||||
{
|
||||
|
|
@ -1313,6 +1315,7 @@ void check_best_overall_error(const color_cell_compressor_params *pParams, color
|
|||
total_err += compute_color_distance_rgb(&orig, &packed, pParams->m_perceptual, pParams->m_weights);
|
||||
}
|
||||
assert(total_err == pResults->m_best_overall_err);
|
||||
#endif
|
||||
|
||||
// HACK HACK
|
||||
//if (total_err != pResults->m_best_overall_err)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// File: basisu_bc7enc.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_comp.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -18,9 +18,10 @@
|
|||
#include "basisu_basis_file.h"
|
||||
#include "../transcoder/basisu_transcoder.h"
|
||||
#include "basisu_uastc_enc.h"
|
||||
#include "basisu_astc_hdr_enc.h"
|
||||
|
||||
#define BASISU_LIB_VERSION 116
|
||||
#define BASISU_LIB_VERSION_STRING "1.16"
|
||||
#define BASISU_LIB_VERSION 150
|
||||
#define BASISU_LIB_VERSION_STRING "1.50"
|
||||
|
||||
#ifndef BASISD_SUPPORT_KTX2
|
||||
#error BASISD_SUPPORT_KTX2 is undefined
|
||||
|
|
@ -81,6 +82,8 @@ namespace basisu
|
|||
m_basis_luma_601_psnr = 0.0f;
|
||||
m_basis_luma_709_ssim = 0.0f;
|
||||
|
||||
m_basis_rgb_avg_bc6h_psnr = 0.0f;
|
||||
|
||||
m_bc7_rgb_avg_psnr = 0.0f;
|
||||
m_bc7_rgba_avg_psnr = 0.0f;
|
||||
m_bc7_a_avg_psnr = 0.0f;
|
||||
|
|
@ -100,7 +103,7 @@ namespace basisu
|
|||
uint32_t m_width;
|
||||
uint32_t m_height;
|
||||
|
||||
// .basis compressed (ETC1S or UASTC statistics)
|
||||
// .basis/.ktx2 compressed (LDR: ETC1S or UASTC statistics, HDR: transcoded BC6H statistics)
|
||||
float m_basis_rgb_avg_psnr;
|
||||
float m_basis_rgba_avg_psnr;
|
||||
float m_basis_a_avg_psnr;
|
||||
|
|
@ -108,7 +111,10 @@ namespace basisu
|
|||
float m_basis_luma_601_psnr;
|
||||
float m_basis_luma_709_ssim;
|
||||
|
||||
// BC7 statistics
|
||||
// UASTC HDR only.
|
||||
float m_basis_rgb_avg_bc6h_psnr;
|
||||
|
||||
// LDR: BC7 statistics
|
||||
float m_bc7_rgb_avg_psnr;
|
||||
float m_bc7_rgba_avg_psnr;
|
||||
float m_bc7_a_avg_psnr;
|
||||
|
|
@ -116,7 +122,7 @@ namespace basisu
|
|||
float m_bc7_luma_601_psnr;
|
||||
float m_bc7_luma_709_ssim;
|
||||
|
||||
// Highest achievable quality ETC1S statistics
|
||||
// LDR: Highest achievable quality ETC1S statistics
|
||||
float m_best_etc1s_rgb_avg_psnr;
|
||||
float m_best_etc1s_luma_709_psnr;
|
||||
float m_best_etc1s_luma_601_psnr;
|
||||
|
|
@ -256,7 +262,7 @@ namespace basisu
|
|||
m_no_selector_rdo.clear();
|
||||
m_selector_rdo_thresh.clear();
|
||||
m_read_source_images.clear();
|
||||
m_write_output_basis_files.clear();
|
||||
m_write_output_basis_or_ktx2_files.clear();
|
||||
m_compression_level.clear();
|
||||
m_compute_stats.clear();
|
||||
m_print_stats.clear();
|
||||
|
|
@ -317,27 +323,38 @@ namespace basisu
|
|||
|
||||
m_validate_output_data.clear();
|
||||
|
||||
m_hdr_ldr_srgb_to_linear_conversion.clear();
|
||||
|
||||
m_hdr_favor_astc.clear();
|
||||
|
||||
m_pJob_pool = nullptr;
|
||||
}
|
||||
|
||||
// True to generate UASTC .basis file data, otherwise ETC1S.
|
||||
// True to generate UASTC .basis/.KTX2 file data, otherwise ETC1S.
|
||||
bool_param<false> m_uastc;
|
||||
|
||||
// Set m_hdr to true to switch to UASTC HDR mode.
|
||||
bool_param<false> m_hdr;
|
||||
|
||||
bool_param<false> m_use_opencl;
|
||||
|
||||
// If m_read_source_images is true, m_source_filenames (and optionally m_source_alpha_filenames) contains the filenames of PNG images to read.
|
||||
// Otherwise, the compressor processes the images in m_source_images.
|
||||
// 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.
|
||||
// Otherwise, the compressor processes the images in m_source_images or m_source_images_hdr.
|
||||
basisu::vector<std::string> m_source_filenames;
|
||||
basisu::vector<std::string> m_source_alpha_filenames;
|
||||
|
||||
basisu::vector<image> m_source_images;
|
||||
|
||||
basisu::vector<imagef> m_source_images_hdr;
|
||||
|
||||
// Stores mipmaps starting from level 1. Level 0 is still stored in m_source_images, as usual.
|
||||
// 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.
|
||||
// The compressor applies the user-provided swizzling (in m_swizzle) to these images.
|
||||
basisu::vector< basisu::vector<image> > m_source_mipmap_images;
|
||||
|
||||
basisu::vector< basisu::vector<imagef> > m_source_mipmap_images_hdr;
|
||||
|
||||
// Filename of the output basis file
|
||||
// Filename of the output basis/ktx2 file
|
||||
std::string m_out_filename;
|
||||
|
||||
// The params are done this way so we can detect when the user has explictly changed them.
|
||||
|
|
@ -373,8 +390,8 @@ namespace basisu
|
|||
// Read source images from m_source_filenames/m_source_alpha_filenames
|
||||
bool_param<false> m_read_source_images;
|
||||
|
||||
// Write the output basis file to disk using m_out_filename
|
||||
bool_param<false> m_write_output_basis_files;
|
||||
// Write the output basis/ktx2 file to disk using m_out_filename
|
||||
bool_param<false> m_write_output_basis_or_ktx2_files;
|
||||
|
||||
// Compute and display image metrics
|
||||
bool_param<false> m_compute_stats;
|
||||
|
|
@ -382,15 +399,15 @@ namespace basisu
|
|||
// Print stats to stdout, if m_compute_stats is true.
|
||||
bool_param<true> m_print_stats;
|
||||
|
||||
// Check to see if any input image has an alpha channel, if so then the output basis file will have alpha channels
|
||||
// Check to see if any input image has an alpha channel, if so then the output basis/ktx2 file will have alpha channels
|
||||
bool_param<true> m_check_for_alpha;
|
||||
|
||||
// Always put alpha slices in the output basis file, even when the input doesn't have alpha
|
||||
// Always put alpha slices in the output basis/ktx2 file, even when the input doesn't have alpha
|
||||
bool_param<false> m_force_alpha;
|
||||
bool_param<true> m_multithreading;
|
||||
|
||||
// Split the R channel to RGB and the G channel to alpha, then write a basis file with alpha channels
|
||||
char m_swizzle[4];
|
||||
// Split the R channel to RGB and the G channel to alpha, then write a basis/ktx2 file with alpha channels
|
||||
uint8_t m_swizzle[4];
|
||||
|
||||
bool_param<false> m_renormalize;
|
||||
|
||||
|
|
@ -448,8 +465,17 @@ namespace basisu
|
|||
param<int> m_ktx2_zstd_supercompression_level;
|
||||
bool_param<false> m_ktx2_srgb_transfer_func;
|
||||
|
||||
astc_hdr_codec_options m_uastc_hdr_options;
|
||||
|
||||
bool_param<false> m_validate_output_data;
|
||||
|
||||
// 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.
|
||||
// Otherwise, LDR images will be processed as HDR as-is.
|
||||
bool_param<true> m_hdr_ldr_srgb_to_linear_conversion;
|
||||
|
||||
// If true, ASTC HDR quality is favored more than BC6H quality. Otherwise it's a rough balance.
|
||||
bool_param<false> m_hdr_favor_astc;
|
||||
|
||||
job_pool *m_pJob_pool;
|
||||
};
|
||||
|
||||
|
|
@ -504,6 +530,7 @@ namespace basisu
|
|||
opencl_context_ptr m_pOpenCL_context;
|
||||
|
||||
basisu::vector<image> m_slice_images;
|
||||
basisu::vector<imagef> m_slice_images_hdr;
|
||||
|
||||
basisu::vector<image_stats> m_stats;
|
||||
|
||||
|
|
@ -515,7 +542,9 @@ namespace basisu
|
|||
uint32_t m_total_blocks;
|
||||
|
||||
basisu_frontend m_frontend;
|
||||
|
||||
pixel_block_vec m_source_blocks;
|
||||
pixel_block_hdr_vec m_source_blocks_hdr;
|
||||
|
||||
basisu::vector<gpu_image> m_frontend_output_textures;
|
||||
|
||||
|
|
@ -526,11 +555,17 @@ namespace basisu
|
|||
|
||||
basisu_file m_basis_file;
|
||||
|
||||
basisu::vector<gpu_image> m_decoded_output_textures;
|
||||
basisu::vector<gpu_image> m_decoded_output_textures; // BC6H in HDR mode
|
||||
basisu::vector<image> m_decoded_output_textures_unpacked;
|
||||
|
||||
basisu::vector<gpu_image> m_decoded_output_textures_bc7;
|
||||
basisu::vector<image> m_decoded_output_textures_unpacked_bc7;
|
||||
|
||||
basisu::vector<imagef> m_decoded_output_textures_bc6h_hdr_unpacked; // BC6H in HDR mode
|
||||
|
||||
basisu::vector<gpu_image> m_decoded_output_textures_astc_hdr;
|
||||
basisu::vector<imagef> m_decoded_output_textures_astc_hdr_unpacked;
|
||||
|
||||
uint8_vec m_output_basis_file;
|
||||
uint8_vec m_output_ktx2_file;
|
||||
|
||||
|
|
@ -541,14 +576,21 @@ namespace basisu
|
|||
|
||||
bool m_opencl_failed;
|
||||
|
||||
void check_for_hdr_inputs();
|
||||
bool sanity_check_input_params();
|
||||
void clean_hdr_image(imagef& src_img);
|
||||
bool read_dds_source_images();
|
||||
bool read_source_images();
|
||||
bool extract_source_blocks();
|
||||
bool process_frontend();
|
||||
bool extract_frontend_texture_data();
|
||||
bool process_backend();
|
||||
bool create_basis_file_and_transcode();
|
||||
bool write_hdr_debug_images(const char* pBasename, const imagef& img, uint32_t width, uint32_t height);
|
||||
bool write_output_files_and_compute_stats();
|
||||
error_code encode_slices_to_uastc_hdr();
|
||||
error_code encode_slices_to_uastc();
|
||||
bool generate_mipmaps(const imagef& img, basisu::vector<imagef>& mips, bool has_alpha);
|
||||
bool generate_mipmaps(const image &img, basisu::vector<image> &mips, bool has_alpha);
|
||||
bool validate_texture_type_constraints();
|
||||
bool validate_ktx2_constraints();
|
||||
|
|
@ -568,7 +610,8 @@ namespace basisu
|
|||
//
|
||||
// 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".
|
||||
// In ETC1S mode, the lower 8-bits are the ETC1S quality level which ranges from [1,255] (higher=better quality/larger files)
|
||||
// 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.
|
||||
// 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.
|
||||
// In UASTC mode, be sure to set this, otherwise it defaults to 0 (fastest/lowest quality).
|
||||
//
|
||||
// uastc_rdo_quality: Float UASTC RDO quality level (0=no change, higher values lower quality but increase compressibility, initially try .5-1.5)
|
||||
//
|
||||
|
|
@ -594,20 +637,36 @@ namespace basisu
|
|||
cFlagUASTCRDO = 1 << 18, // use RDO postprocessing when generating UASTC files (must set uastc_rdo_quality to the quality scalar)
|
||||
|
||||
cFlagPrintStats = 1 << 19, // print image stats to stdout
|
||||
cFlagPrintStatus = 1 << 20 // print status to stdout
|
||||
cFlagPrintStatus = 1 << 20, // print status to stdout
|
||||
|
||||
cFlagHDR = 1 << 21, // Force encoder into HDR mode, even if source image is LDR.
|
||||
cFlagHDRLDRImageSRGBToLinearConversion = 1 << 22, // In HDR mode, convert LDR source images to linear before encoding.
|
||||
|
||||
cFlagDebugImages = 1 << 23 // enable status output
|
||||
};
|
||||
|
||||
// This function accepts an array of source images.
|
||||
// If more than one image is provided, it's assumed the images form a mipmap pyramid and automatic mipmap generation is disabled.
|
||||
// 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().
|
||||
// Returns a pointer to the compressed .basis or .ktx2 file data. *pSize is the size of the compressed data.
|
||||
// Important: The returned block MUST be manually freed using basis_free_data().
|
||||
// basisu_encoder_init() MUST be called first!
|
||||
// LDR version. To compress the LDR source image as HDR: Use the cFlagHDR flag.
|
||||
void* basis_compress(
|
||||
const basisu::vector<image> &source_images,
|
||||
uint32_t flags_and_quality, float uastc_rdo_quality,
|
||||
size_t* pSize,
|
||||
image_stats* pStats = nullptr);
|
||||
|
||||
// This function only accepts a single source image.
|
||||
// HDR-only version.
|
||||
// Important: The returned block MUST be manually freed using basis_free_data().
|
||||
void* basis_compress(
|
||||
const basisu::vector<imagef>& source_images_hdr,
|
||||
uint32_t flags_and_quality,
|
||||
size_t* pSize,
|
||||
image_stats* pStats = nullptr);
|
||||
|
||||
// This function only accepts a single LDR source image. It's just a wrapper for basis_compress() above.
|
||||
// Important: The returned block MUST be manually freed using basis_free_data().
|
||||
void* basis_compress(
|
||||
const uint8_t* pImageRGBA, uint32_t width, uint32_t height, uint32_t pitch_in_pixels,
|
||||
uint32_t flags_and_quality, float uastc_rdo_quality,
|
||||
|
|
@ -615,6 +674,7 @@ namespace basisu
|
|||
image_stats* pStats = nullptr);
|
||||
|
||||
// Frees the dynamically allocated file data returned by basis_compress().
|
||||
// This MUST be called on the pointer returned by basis_compress() when you're done with it.
|
||||
void basis_free_data(void* p);
|
||||
|
||||
// Runs a short benchmark using synthetic image data to time OpenCL encoding vs. CPU encoding, with multithreading enabled.
|
||||
|
|
|
|||
1634
engine/thirdparty/basis_universal/encoder/basisu_enc.cpp
vendored
1634
engine/thirdparty/basis_universal/encoder/basisu_enc.cpp
vendored
File diff suppressed because it is too large
Load diff
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_enc.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -48,7 +48,8 @@ namespace basisu
|
|||
|
||||
// Encoder library initialization.
|
||||
// This function MUST be called before encoding anything!
|
||||
void basisu_encoder_init(bool use_opencl = false, bool opencl_force_serialization = false);
|
||||
// Returns false if library initialization fails.
|
||||
bool basisu_encoder_init(bool use_opencl = false, bool opencl_force_serialization = false);
|
||||
void basisu_encoder_deinit();
|
||||
|
||||
// basisu_kernels_sse.cpp - will be a no-op and g_cpu_supports_sse41 will always be false unless compiled with BASISU_SUPPORT_SSE=1
|
||||
|
|
@ -70,6 +71,18 @@ namespace basisu
|
|||
return (uint8_t)((i & 0xFFFFFF00U) ? (~(i >> 31)) : i);
|
||||
}
|
||||
|
||||
inline int left_shift32(int val, int shift)
|
||||
{
|
||||
assert((shift >= 0) && (shift < 32));
|
||||
return static_cast<int>(static_cast<uint32_t>(val) << shift);
|
||||
}
|
||||
|
||||
inline uint32_t left_shift32(uint32_t val, int shift)
|
||||
{
|
||||
assert((shift >= 0) && (shift < 32));
|
||||
return val << shift;
|
||||
}
|
||||
|
||||
inline int32_t clampi(int32_t value, int32_t low, int32_t high)
|
||||
{
|
||||
if (value < low)
|
||||
|
|
@ -130,6 +143,31 @@ namespace basisu
|
|||
|
||||
return bits;
|
||||
}
|
||||
|
||||
// Open interval
|
||||
inline int bounds_check(int v, int l, int h) { (void)v; (void)l; (void)h; assert(v >= l && v < h); return v; }
|
||||
inline uint32_t bounds_check(uint32_t v, uint32_t l, uint32_t h) { (void)v; (void)l; (void)h; assert(v >= l && v < h); return v; }
|
||||
|
||||
// Closed interval
|
||||
inline int bounds_check_incl(int v, int l, int h) { (void)v; (void)l; (void)h; assert(v >= l && v <= h); return v; }
|
||||
inline uint32_t bounds_check_incl(uint32_t v, uint32_t l, uint32_t h) { (void)v; (void)l; (void)h; assert(v >= l && v <= h); return v; }
|
||||
|
||||
inline uint32_t clz(uint32_t x)
|
||||
{
|
||||
if (!x)
|
||||
return 32;
|
||||
|
||||
uint32_t n = 0;
|
||||
while ((x & 0x80000000) == 0)
|
||||
{
|
||||
x <<= 1u;
|
||||
n++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
bool string_begins_with(const std::string& str, const char* pPhrase);
|
||||
|
||||
// Hashing
|
||||
|
||||
|
|
@ -268,6 +306,7 @@ namespace basisu
|
|||
|
||||
public:
|
||||
enum { num_elements = N };
|
||||
typedef T scalar_type;
|
||||
|
||||
inline vec() { }
|
||||
inline vec(eZero) { set_zero(); }
|
||||
|
|
@ -291,6 +330,7 @@ namespace basisu
|
|||
inline bool operator<(const vec &rhs) const { for (uint32_t i = 0; i < N; i++) { if (m_v[i] < rhs.m_v[i]) return true; else if (m_v[i] != rhs.m_v[i]) return false; } return false; }
|
||||
|
||||
inline void set_zero() { for (uint32_t i = 0; i < N; i++) m_v[i] = 0; }
|
||||
inline void clear() { set_zero(); }
|
||||
|
||||
template <uint32_t OtherN, typename OtherT>
|
||||
inline vec &set(const vec<OtherN, OtherT> &other)
|
||||
|
|
@ -391,7 +431,7 @@ namespace basisu
|
|||
inline T distance(const vec &other) const { return static_cast<T>(sqrt(squared_distance(other))); }
|
||||
inline double distance_d(const vec& other) const { return sqrt(squared_distance_d(other)); }
|
||||
|
||||
inline vec &normalize_in_place() { T len = length(); if (len != 0.0f) *this *= (1.0f / len); return *this; }
|
||||
inline vec &normalize_in_place() { T len = length(); if (len != 0.0f) *this *= (1.0f / len); return *this; }
|
||||
|
||||
inline vec &clamp(T l, T h)
|
||||
{
|
||||
|
|
@ -722,7 +762,7 @@ namespace basisu
|
|||
void job_thread(uint32_t index);
|
||||
};
|
||||
|
||||
// Simple 32-bit color class
|
||||
// Simple 64-bit color class
|
||||
|
||||
class color_rgba_i16
|
||||
{
|
||||
|
|
@ -1116,7 +1156,9 @@ namespace basisu
|
|||
{
|
||||
std::string result(s);
|
||||
for (size_t i = 0; i < result.size(); i++)
|
||||
result[i] = (char)tolower((int)result[i]);
|
||||
{
|
||||
result[i] = (char)tolower((uint8_t)(result[i]));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -1408,7 +1450,7 @@ namespace basisu
|
|||
|
||||
size_t get_total_training_vecs() const { return m_training_vecs.size(); }
|
||||
const array_of_weighted_training_vecs &get_training_vecs() const { return m_training_vecs; }
|
||||
array_of_weighted_training_vecs &get_training_vecs() { return m_training_vecs; }
|
||||
array_of_weighted_training_vecs &get_training_vecs() { return m_training_vecs; }
|
||||
|
||||
void retrieve(basisu::vector< basisu::vector<uint32_t> > &codebook) const
|
||||
{
|
||||
|
|
@ -1437,36 +1479,36 @@ namespace basisu
|
|||
}
|
||||
|
||||
void retrieve(uint32_t max_clusters, basisu::vector<uint_vec> &codebook) const
|
||||
{
|
||||
{
|
||||
uint_vec node_stack;
|
||||
node_stack.reserve(512);
|
||||
node_stack.reserve(512);
|
||||
|
||||
codebook.resize(0);
|
||||
codebook.reserve(max_clusters);
|
||||
codebook.resize(0);
|
||||
codebook.reserve(max_clusters);
|
||||
|
||||
uint32_t node_index = 0;
|
||||
uint32_t node_index = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
const tsvq_node& cur = m_nodes[node_index];
|
||||
while (true)
|
||||
{
|
||||
const tsvq_node& cur = m_nodes[node_index];
|
||||
|
||||
if (cur.is_leaf() || ((2 + cur.m_codebook_index) > (int)max_clusters))
|
||||
{
|
||||
codebook.resize(codebook.size() + 1);
|
||||
codebook.back() = cur.m_training_vecs;
|
||||
if (cur.is_leaf() || ((2 + cur.m_codebook_index) > (int)max_clusters))
|
||||
{
|
||||
codebook.resize(codebook.size() + 1);
|
||||
codebook.back() = cur.m_training_vecs;
|
||||
|
||||
if (node_stack.empty())
|
||||
break;
|
||||
if (node_stack.empty())
|
||||
break;
|
||||
|
||||
node_index = node_stack.back();
|
||||
node_stack.pop_back();
|
||||
continue;
|
||||
}
|
||||
node_index = node_stack.back();
|
||||
node_stack.pop_back();
|
||||
continue;
|
||||
}
|
||||
|
||||
node_stack.push_back(cur.m_right_index);
|
||||
node_index = cur.m_left_index;
|
||||
}
|
||||
}
|
||||
node_stack.push_back(cur.m_right_index);
|
||||
node_index = cur.m_left_index;
|
||||
}
|
||||
}
|
||||
|
||||
bool generate(uint32_t max_size)
|
||||
{
|
||||
|
|
@ -2319,6 +2361,14 @@ namespace basisu
|
|||
m_total_bits = 0;
|
||||
}
|
||||
|
||||
inline void restart()
|
||||
{
|
||||
m_bytes.resize(0);
|
||||
m_bit_buffer = 0;
|
||||
m_bit_buffer_size = 0;
|
||||
m_total_bits = 0;
|
||||
}
|
||||
|
||||
inline const uint8_vec &get_bytes() const { return m_bytes; }
|
||||
|
||||
inline uint64_t get_total_bits() const { return m_total_bits; }
|
||||
|
|
@ -2920,11 +2970,11 @@ namespace basisu
|
|||
inline const color_rgba *get_ptr() const { return &m_pixels[0]; }
|
||||
inline color_rgba *get_ptr() { return &m_pixels[0]; }
|
||||
|
||||
bool has_alpha() const
|
||||
bool has_alpha(uint32_t channel = 3) const
|
||||
{
|
||||
for (uint32_t y = 0; y < m_height; ++y)
|
||||
for (uint32_t x = 0; x < m_width; ++x)
|
||||
if ((*this)(x, y).a < 255)
|
||||
if ((*this)(x, y)[channel] < 255)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
@ -3130,6 +3180,31 @@ namespace basisu
|
|||
return *this;
|
||||
}
|
||||
|
||||
imagef& crop_dup_borders(uint32_t w, uint32_t h)
|
||||
{
|
||||
const uint32_t orig_w = m_width, orig_h = m_height;
|
||||
|
||||
crop(w, h);
|
||||
|
||||
if (orig_w && orig_h)
|
||||
{
|
||||
if (m_width > orig_w)
|
||||
{
|
||||
for (uint32_t x = orig_w; x < m_width; x++)
|
||||
for (uint32_t y = 0; y < m_height; y++)
|
||||
set_clipped(x, y, get_clamped(minimum(x, orig_w - 1U), minimum(y, orig_h - 1U)));
|
||||
}
|
||||
|
||||
if (m_height > orig_h)
|
||||
{
|
||||
for (uint32_t y = orig_h; y < m_height; y++)
|
||||
for (uint32_t x = 0; x < m_width; x++)
|
||||
set_clipped(x, y, get_clamped(minimum(x, orig_w - 1U), minimum(y, orig_h - 1U)));
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const vec4F &operator() (uint32_t x, uint32_t y) const { assert(x < m_width && y < m_height); return m_pixels[x + y * m_pitch]; }
|
||||
inline vec4F &operator() (uint32_t x, uint32_t y) { assert(x < m_width && y < m_height); return m_pixels[x + y * m_pitch]; }
|
||||
|
||||
|
|
@ -3213,19 +3288,128 @@ namespace basisu
|
|||
|
||||
inline const vec4F *get_ptr() const { return &m_pixels[0]; }
|
||||
inline vec4F *get_ptr() { return &m_pixels[0]; }
|
||||
|
||||
bool clean_astc_hdr_pixels(float highest_mag)
|
||||
{
|
||||
bool status = true;
|
||||
bool nan_msg = false;
|
||||
bool inf_msg = false;
|
||||
bool neg_zero_msg = false;
|
||||
bool neg_msg = false;
|
||||
bool clamp_msg = false;
|
||||
|
||||
for (uint32_t iy = 0; iy < m_height; iy++)
|
||||
{
|
||||
for (uint32_t ix = 0; ix < m_width; ix++)
|
||||
{
|
||||
vec4F& c = (*this)(ix, iy);
|
||||
|
||||
for (uint32_t s = 0; s < 4; s++)
|
||||
{
|
||||
float &p = c[s];
|
||||
union { float f; uint32_t u; } x; x.f = p;
|
||||
|
||||
if ((std::isnan(p)) || (std::isinf(p)) || (x.u == 0x80000000))
|
||||
{
|
||||
if (std::isnan(p))
|
||||
{
|
||||
if (!nan_msg)
|
||||
{
|
||||
fprintf(stderr, "One or more pixels was NaN, setting to 0.\n");
|
||||
nan_msg = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (std::isinf(p))
|
||||
{
|
||||
if (!inf_msg)
|
||||
{
|
||||
fprintf(stderr, "One or more pixels was INF, setting to 0.\n");
|
||||
inf_msg = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (x.u == 0x80000000)
|
||||
{
|
||||
if (!neg_zero_msg)
|
||||
{
|
||||
fprintf(stderr, "One or more pixels was -0, setting them to 0.\n");
|
||||
neg_zero_msg = true;
|
||||
}
|
||||
}
|
||||
|
||||
p = 0.0f;
|
||||
status = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//const float o = p;
|
||||
if (p < 0.0f)
|
||||
{
|
||||
p = 0.0f;
|
||||
|
||||
if (!neg_msg)
|
||||
{
|
||||
fprintf(stderr, "One or more pixels was negative -- setting these pixel components to 0 because ASTC HDR doesn't support signed values.\n");
|
||||
neg_msg = true;
|
||||
}
|
||||
|
||||
status = false;
|
||||
}
|
||||
|
||||
if (p > highest_mag)
|
||||
{
|
||||
p = highest_mag;
|
||||
|
||||
if (!clamp_msg)
|
||||
{
|
||||
fprintf(stderr, "One or more pixels had to be clamped to %f.\n", highest_mag);
|
||||
clamp_msg = true;
|
||||
}
|
||||
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
imagef& flip_y()
|
||||
{
|
||||
for (uint32_t y = 0; y < m_height / 2; ++y)
|
||||
for (uint32_t x = 0; x < m_width; ++x)
|
||||
std::swap((*this)(x, y), (*this)(x, m_height - 1 - y));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t m_width, m_height, m_pitch; // all in pixels
|
||||
vec4F_vec m_pixels;
|
||||
};
|
||||
|
||||
// REC 709 coefficients
|
||||
const float REC_709_R = 0.212656f, REC_709_G = 0.715158f, REC_709_B = 0.072186f;
|
||||
|
||||
inline float get_luminance(const vec4F &c)
|
||||
{
|
||||
return c[0] * REC_709_R + c[1] * REC_709_G + c[2] * REC_709_B;
|
||||
}
|
||||
|
||||
float linear_to_srgb(float l);
|
||||
float srgb_to_linear(float s);
|
||||
|
||||
// Image metrics
|
||||
|
||||
class image_metrics
|
||||
{
|
||||
public:
|
||||
// TODO: Add ssim
|
||||
float m_max, m_mean, m_mean_squared, m_rms, m_psnr, m_ssim;
|
||||
double m_max, m_mean, m_mean_squared, m_rms, m_psnr, m_ssim;
|
||||
bool m_has_neg, m_hf_mag_overflow, m_any_abnormal;
|
||||
|
||||
image_metrics()
|
||||
{
|
||||
|
|
@ -3240,10 +3424,17 @@ namespace basisu
|
|||
m_rms = 0;
|
||||
m_psnr = 0;
|
||||
m_ssim = 0;
|
||||
m_has_neg = false;
|
||||
m_hf_mag_overflow = false;
|
||||
m_any_abnormal = false;
|
||||
}
|
||||
|
||||
void print(const char *pPrefix = nullptr) { printf("%sMax: %3.0f Mean: %3.3f RMS: %3.3f PSNR: %2.3f dB\n", pPrefix ? pPrefix : "", m_max, m_mean, m_rms, m_psnr); }
|
||||
void print(const char *pPrefix = nullptr) { printf("%sMax: %3.3f Mean: %3.3f RMS: %3.3f PSNR: %2.3f dB\n", pPrefix ? pPrefix : "", m_max, m_mean, m_rms, m_psnr); }
|
||||
void print_hp(const char* pPrefix = nullptr) { printf("%sMax: %3.6f Mean: %3.6f RMS: %3.6f PSNR: %2.6f dB, Any Neg: %u, Half float overflow: %u, Any NaN/Inf: %u\n", pPrefix ? pPrefix : "", m_max, m_mean, m_rms, m_psnr, m_has_neg, m_hf_mag_overflow, m_any_abnormal); }
|
||||
|
||||
void calc(const imagef& a, const imagef& b, uint32_t first_chan = 0, uint32_t total_chans = 0, bool avg_comp_error = true, bool log = false);
|
||||
void calc_half(const imagef& a, const imagef& b, uint32_t first_chan, uint32_t total_chans, bool avg_comp_error);
|
||||
void calc_half2(const imagef& a, const imagef& b, uint32_t first_chan, uint32_t total_chans, bool avg_comp_error);
|
||||
void calc(const image &a, const image &b, uint32_t first_chan = 0, uint32_t total_chans = 0, bool avg_comp_error = true, bool use_601_luma = false);
|
||||
};
|
||||
|
||||
|
|
@ -3256,6 +3447,8 @@ namespace basisu
|
|||
bool load_tga(const char* pFilename, image& img);
|
||||
inline bool load_tga(const std::string &filename, image &img) { return load_tga(filename.c_str(), img); }
|
||||
|
||||
bool load_qoi(const char* pFilename, image& img);
|
||||
|
||||
bool load_jpg(const char *pFilename, image& img);
|
||||
inline bool load_jpg(const std::string &filename, image &img) { return load_jpg(filename.c_str(), img); }
|
||||
|
||||
|
|
@ -3263,9 +3456,64 @@ namespace basisu
|
|||
bool load_image(const char* pFilename, image& img);
|
||||
inline bool load_image(const std::string &filename, image &img) { return load_image(filename.c_str(), img); }
|
||||
|
||||
// Supports .HDR and most (but not all) .EXR's (see TinyEXR).
|
||||
bool load_image_hdr(const char* pFilename, imagef& img, bool ldr_srgb_to_linear = true);
|
||||
inline bool load_image_hdr(const std::string& filename, imagef& img, bool ldr_srgb_to_linear = true) { return load_image_hdr(filename.c_str(), img, ldr_srgb_to_linear); }
|
||||
|
||||
enum class hdr_image_type
|
||||
{
|
||||
cHITRGBAHalfFloat = 0,
|
||||
cHITRGBAFloat = 1,
|
||||
cHITPNGImage = 2,
|
||||
cHITEXRImage = 3,
|
||||
cHITHDRImage = 4
|
||||
};
|
||||
|
||||
bool load_image_hdr(const void* pMem, size_t mem_size, imagef& img, uint32_t width, uint32_t height, hdr_image_type img_type, bool ldr_srgb_to_linear);
|
||||
|
||||
uint8_t *read_tga(const uint8_t *pBuf, uint32_t buf_size, int &width, int &height, int &n_chans);
|
||||
uint8_t *read_tga(const char *pFilename, int &width, int &height, int &n_chans);
|
||||
|
||||
struct rgbe_header_info
|
||||
{
|
||||
std::string m_program;
|
||||
|
||||
// Note no validation is done, either gamma or exposure may be 0.
|
||||
double m_gamma;
|
||||
bool m_has_gamma;
|
||||
|
||||
double m_exposure; // watts/steradian/m^2.
|
||||
bool m_has_exposure;
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_program.clear();
|
||||
m_gamma = 1.0f;
|
||||
m_has_gamma = false;
|
||||
m_exposure = 1.0f;
|
||||
m_has_exposure = false;
|
||||
}
|
||||
};
|
||||
|
||||
bool read_rgbe(const uint8_vec& filedata, imagef& img, rgbe_header_info& hdr_info);
|
||||
bool read_rgbe(const char* pFilename, imagef& img, rgbe_header_info &hdr_info);
|
||||
|
||||
bool write_rgbe(uint8_vec& file_data, imagef& img, rgbe_header_info& hdr_info);
|
||||
bool write_rgbe(const char* pFilename, imagef& img, rgbe_header_info& hdr_info);
|
||||
|
||||
bool read_exr(const char* pFilename, imagef& img, int& n_chans);
|
||||
bool read_exr(const void* pMem, size_t mem_size, imagef& img);
|
||||
|
||||
enum
|
||||
{
|
||||
WRITE_EXR_LINEAR_HINT = 1, // hint for lossy comp. methods: exr_perceptual_treatment_t, logarithmic or linear, defaults to logarithmic
|
||||
WRITE_EXR_STORE_FLOATS = 2, // use 32-bit floats, otherwise it uses half floats
|
||||
WRITE_EXR_NO_COMPRESSION = 4 // no compression, otherwise it uses ZIP compression (16 scanlines per block)
|
||||
};
|
||||
|
||||
// Supports 1 (Y), 3 (RGB), or 4 (RGBA) channel images.
|
||||
bool write_exr(const char* pFilename, imagef& img, uint32_t n_chans, uint32_t flags);
|
||||
|
||||
enum
|
||||
{
|
||||
cImageSaveGrayscale = 1,
|
||||
|
|
@ -3276,19 +3524,22 @@ namespace basisu
|
|||
inline bool save_png(const std::string &filename, const image &img, uint32_t image_save_flags = 0, uint32_t grayscale_comp = 0) { return save_png(filename.c_str(), img, image_save_flags, grayscale_comp); }
|
||||
|
||||
bool read_file_to_vec(const char* pFilename, uint8_vec& data);
|
||||
|
||||
bool read_file_to_data(const char* pFilename, void *pData, size_t len);
|
||||
|
||||
bool write_data_to_file(const char* pFilename, const void* pData, size_t len);
|
||||
|
||||
inline bool write_vec_to_file(const char* pFilename, const uint8_vec& v) { return v.size() ? write_data_to_file(pFilename, &v[0], v.size()) : write_data_to_file(pFilename, "", 0); }
|
||||
|
||||
float linear_to_srgb(float l);
|
||||
float srgb_to_linear(float s);
|
||||
|
||||
|
||||
bool image_resample(const image &src, image &dst, bool srgb = false,
|
||||
const char *pFilter = "lanczos4", float filter_scale = 1.0f,
|
||||
bool wrapping = false,
|
||||
uint32_t first_comp = 0, uint32_t num_comps = 4);
|
||||
|
||||
bool image_resample(const imagef& src, imagef& dst,
|
||||
const char* pFilter = "lanczos4", float filter_scale = 1.0f,
|
||||
bool wrapping = false,
|
||||
uint32_t first_comp = 0, uint32_t num_comps = 4);
|
||||
|
||||
// Timing
|
||||
|
||||
typedef uint64_t timer_ticks;
|
||||
|
|
@ -3319,6 +3570,8 @@ namespace basisu
|
|||
bool m_started, m_stopped;
|
||||
};
|
||||
|
||||
inline double get_interval_timer() { return interval_timer::ticks_to_secs(interval_timer::get_ticks()); }
|
||||
|
||||
// 2D array
|
||||
|
||||
template<typename T>
|
||||
|
|
@ -3372,8 +3625,8 @@ namespace basisu
|
|||
inline const T &operator[] (uint32_t i) const { return m_values[i]; }
|
||||
inline T &operator[] (uint32_t i) { return m_values[i]; }
|
||||
|
||||
inline const T &at_clamped(int x, int y) const { return (*this)(clamp<int>(x, 0, m_width), clamp<int>(y, 0, m_height)); }
|
||||
inline T &at_clamped(int x, int y) { return (*this)(clamp<int>(x, 0, m_width), clamp<int>(y, 0, m_height)); }
|
||||
inline const T &at_clamped(int x, int y) const { return (*this)(clamp<int>(x, 0, m_width - 1), clamp<int>(y, 0, m_height - 1)); }
|
||||
inline T &at_clamped(int x, int y) { return (*this)(clamp<int>(x, 0, m_width - 1), clamp<int>(y, 0, m_height - 1)); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
|
|
@ -3450,7 +3703,327 @@ namespace basisu
|
|||
}
|
||||
};
|
||||
typedef basisu::vector<pixel_block> pixel_block_vec;
|
||||
|
||||
|
||||
struct pixel_block_hdr
|
||||
{
|
||||
vec4F m_pixels[cPixelBlockHeight][cPixelBlockWidth]; // [y][x]
|
||||
|
||||
inline const vec4F& operator() (uint32_t x, uint32_t y) const { assert((x < cPixelBlockWidth) && (y < cPixelBlockHeight)); return m_pixels[y][x]; }
|
||||
inline vec4F& operator() (uint32_t x, uint32_t y) { assert((x < cPixelBlockWidth) && (y < cPixelBlockHeight)); return m_pixels[y][x]; }
|
||||
|
||||
inline const vec4F* get_ptr() const { return &m_pixels[0][0]; }
|
||||
inline vec4F* get_ptr() { return &m_pixels[0][0]; }
|
||||
|
||||
inline void clear() { clear_obj(*this); }
|
||||
|
||||
inline bool operator== (const pixel_block& rhs) const
|
||||
{
|
||||
return memcmp(m_pixels, rhs.m_pixels, sizeof(m_pixels)) == 0;
|
||||
}
|
||||
};
|
||||
typedef basisu::vector<pixel_block_hdr> pixel_block_hdr_vec;
|
||||
|
||||
void tonemap_image_reinhard(image& ldr_img, const imagef& hdr_img, float exposure);
|
||||
bool tonemap_image_compressive(image& dst_img, const imagef& hdr_test_img);
|
||||
|
||||
// Intersection
|
||||
enum eClear { cClear = 0 };
|
||||
enum eInitExpand { cInitExpand = 0 };
|
||||
|
||||
template<typename vector_type>
|
||||
class ray
|
||||
{
|
||||
public:
|
||||
typedef vector_type vector_t;
|
||||
typedef typename vector_type::scalar_type scalar_type;
|
||||
|
||||
inline ray() { }
|
||||
inline ray(eClear) { clear(); }
|
||||
inline ray(const vector_type& origin, const vector_type& direction) : m_origin(origin), m_direction(direction) { }
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
m_origin.clear();
|
||||
m_direction.clear();
|
||||
}
|
||||
|
||||
inline const vector_type& get_origin(void) const { return m_origin; }
|
||||
inline void set_origin(const vector_type& origin) { m_origin = origin; }
|
||||
|
||||
inline const vector_type& get_direction(void) const { return m_direction; }
|
||||
inline void set_direction(const vector_type& direction) { m_direction = direction; }
|
||||
|
||||
inline void set_endpoints(const vector_type& start, const vector_type& end)
|
||||
{
|
||||
m_origin = start;
|
||||
|
||||
m_direction = end - start;
|
||||
m_direction.normalize_in_place();
|
||||
}
|
||||
|
||||
inline vector_type eval(scalar_type t) const
|
||||
{
|
||||
return m_origin + m_direction * t;
|
||||
}
|
||||
|
||||
private:
|
||||
vector_type m_origin;
|
||||
vector_type m_direction;
|
||||
};
|
||||
|
||||
typedef ray<vec2F> ray2F;
|
||||
typedef ray<vec3F> ray3F;
|
||||
|
||||
template<typename T>
|
||||
class vec_interval
|
||||
{
|
||||
public:
|
||||
enum { N = T::num_elements };
|
||||
typedef typename T::scalar_type scalar_type;
|
||||
|
||||
inline vec_interval(const T& v) { m_bounds[0] = v; m_bounds[1] = v; }
|
||||
inline vec_interval(const T& low, const T& high) { m_bounds[0] = low; m_bounds[1] = high; }
|
||||
|
||||
inline vec_interval() { }
|
||||
inline vec_interval(eClear) { clear(); }
|
||||
inline vec_interval(eInitExpand) { init_expand(); }
|
||||
|
||||
inline void clear() { m_bounds[0].clear(); m_bounds[1].clear(); }
|
||||
|
||||
inline void init_expand()
|
||||
{
|
||||
m_bounds[0].set(1e+30f, 1e+30f, 1e+30f);
|
||||
m_bounds[1].set(-1e+30f, -1e+30f, -1e+30f);
|
||||
}
|
||||
|
||||
inline vec_interval expand(const T& p)
|
||||
{
|
||||
for (uint32_t c = 0; c < N; c++)
|
||||
{
|
||||
if (p[c] < m_bounds[0][c])
|
||||
m_bounds[0][c] = p[c];
|
||||
|
||||
if (p[c] > m_bounds[1][c])
|
||||
m_bounds[1][c] = p[c];
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const T& operator[] (uint32_t i) const { assert(i < 2); return m_bounds[i]; }
|
||||
inline T& operator[] (uint32_t i) { assert(i < 2); return m_bounds[i]; }
|
||||
|
||||
const T& get_low() const { return m_bounds[0]; }
|
||||
T& get_low() { return m_bounds[0]; }
|
||||
|
||||
const T& get_high() const { return m_bounds[1]; }
|
||||
T& get_high() { return m_bounds[1]; }
|
||||
|
||||
scalar_type get_dim(uint32_t axis) const { return m_bounds[1][axis] - m_bounds[0][axis]; }
|
||||
|
||||
bool contains(const T& p) const
|
||||
{
|
||||
const T& low = get_low(), high = get_high();
|
||||
|
||||
for (uint32_t i = 0; i < N; i++)
|
||||
{
|
||||
if (p[i] < low[i])
|
||||
return false;
|
||||
|
||||
if (p[i] > high[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
T m_bounds[2];
|
||||
};
|
||||
|
||||
typedef vec_interval<vec1F> vec_interval1F;
|
||||
typedef vec_interval<vec2F> vec_interval2F;
|
||||
typedef vec_interval<vec3F> vec_interval3F;
|
||||
typedef vec_interval<vec4F> vec_interval4F;
|
||||
|
||||
typedef vec_interval2F aabb2F;
|
||||
typedef vec_interval3F aabb3F;
|
||||
|
||||
namespace intersection
|
||||
{
|
||||
enum result
|
||||
{
|
||||
cBackfacing = -1,
|
||||
cFailure = 0,
|
||||
cSuccess,
|
||||
cParallel,
|
||||
cInside,
|
||||
};
|
||||
|
||||
// Returns cInside, cSuccess, or cFailure.
|
||||
// Algorithm: Graphics Gems 1
|
||||
template<typename vector_type, typename scalar_type, typename ray_type, typename aabb_type>
|
||||
result ray_aabb(vector_type& coord, scalar_type& t, const ray_type& ray, const aabb_type& box)
|
||||
{
|
||||
enum
|
||||
{
|
||||
cNumDim = vector_type::num_elements,
|
||||
cRight = 0,
|
||||
cLeft = 1,
|
||||
cMiddle = 2
|
||||
};
|
||||
|
||||
bool inside = true;
|
||||
int quadrant[cNumDim];
|
||||
scalar_type candidate_plane[cNumDim];
|
||||
|
||||
for (int i = 0; i < cNumDim; i++)
|
||||
{
|
||||
if (ray.get_origin()[i] < box[0][i])
|
||||
{
|
||||
quadrant[i] = cLeft;
|
||||
candidate_plane[i] = box[0][i];
|
||||
inside = false;
|
||||
}
|
||||
else if (ray.get_origin()[i] > box[1][i])
|
||||
{
|
||||
quadrant[i] = cRight;
|
||||
candidate_plane[i] = box[1][i];
|
||||
inside = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
quadrant[i] = cMiddle;
|
||||
}
|
||||
}
|
||||
|
||||
if (inside)
|
||||
{
|
||||
coord = ray.get_origin();
|
||||
t = 0.0f;
|
||||
return cInside;
|
||||
}
|
||||
|
||||
scalar_type max_t[cNumDim];
|
||||
for (int i = 0; i < cNumDim; i++)
|
||||
{
|
||||
if ((quadrant[i] != cMiddle) && (ray.get_direction()[i] != 0.0f))
|
||||
max_t[i] = (candidate_plane[i] - ray.get_origin()[i]) / ray.get_direction()[i];
|
||||
else
|
||||
max_t[i] = -1.0f;
|
||||
}
|
||||
|
||||
int which_plane = 0;
|
||||
for (int i = 1; i < cNumDim; i++)
|
||||
if (max_t[which_plane] < max_t[i])
|
||||
which_plane = i;
|
||||
|
||||
if (max_t[which_plane] < 0.0f)
|
||||
return cFailure;
|
||||
|
||||
for (int i = 0; i < cNumDim; i++)
|
||||
{
|
||||
if (i != which_plane)
|
||||
{
|
||||
coord[i] = ray.get_origin()[i] + max_t[which_plane] * ray.get_direction()[i];
|
||||
|
||||
if ((coord[i] < box[0][i]) || (coord[i] > box[1][i]))
|
||||
return cFailure;
|
||||
}
|
||||
else
|
||||
{
|
||||
coord[i] = candidate_plane[i];
|
||||
}
|
||||
|
||||
assert(coord[i] >= box[0][i] && coord[i] <= box[1][i]);
|
||||
}
|
||||
|
||||
t = max_t[which_plane];
|
||||
return cSuccess;
|
||||
}
|
||||
|
||||
template<typename vector_type, typename scalar_type, typename ray_type, typename aabb_type>
|
||||
result ray_aabb(bool& started_within, vector_type& coord, scalar_type& t, const ray_type& ray, const aabb_type& box)
|
||||
{
|
||||
if (!box.contains(ray.get_origin()))
|
||||
{
|
||||
started_within = false;
|
||||
return ray_aabb(coord, t, ray, box);
|
||||
}
|
||||
|
||||
started_within = true;
|
||||
|
||||
typename vector_type::T diag_dist = box.diagonal_length() * 1.5f;
|
||||
ray_type outside_ray(ray.eval(diag_dist), -ray.get_direction());
|
||||
|
||||
result res(ray_aabb(coord, t, outside_ray, box));
|
||||
if (res != cSuccess)
|
||||
return res;
|
||||
|
||||
t = basisu::maximum(0.0f, diag_dist - t);
|
||||
return cSuccess;
|
||||
}
|
||||
|
||||
} // intersect
|
||||
|
||||
// This float->half conversion matches how "F32TO16" works on Intel GPU's.
|
||||
// Input cannot be negative, Inf or Nan.
|
||||
inline basist::half_float float_to_half_non_neg_no_nan_inf(float val)
|
||||
{
|
||||
union { float f; int32_t i; uint32_t u; } fi = { val };
|
||||
const int flt_m = fi.i & 0x7FFFFF, flt_e = (fi.i >> 23) & 0xFF;
|
||||
int e = 0, m = 0;
|
||||
|
||||
assert(((fi.i >> 31) == 0) && (flt_e != 0xFF));
|
||||
|
||||
// not zero or denormal
|
||||
if (flt_e != 0)
|
||||
{
|
||||
int new_exp = flt_e - 127;
|
||||
if (new_exp > 15)
|
||||
e = 31;
|
||||
else if (new_exp < -14)
|
||||
m = lrintf((1 << 24) * fabsf(fi.f));
|
||||
else
|
||||
{
|
||||
e = new_exp + 15;
|
||||
m = lrintf(flt_m * (1.0f / ((float)(1 << 13))));
|
||||
}
|
||||
}
|
||||
|
||||
assert((0 <= m) && (m <= 1024));
|
||||
if (m == 1024)
|
||||
{
|
||||
e++;
|
||||
m = 0;
|
||||
}
|
||||
|
||||
assert((e >= 0) && (e <= 31));
|
||||
assert((m >= 0) && (m <= 1023));
|
||||
|
||||
basist::half_float result = (basist::half_float)((e << 10) | m);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Supports positive and denormals only. No NaN or Inf.
|
||||
inline float fast_half_to_float_pos_not_inf_or_nan(basist::half_float h)
|
||||
{
|
||||
assert(!basist::half_is_signed(h) && !basist::is_half_inf_or_nan(h));
|
||||
|
||||
union fu32
|
||||
{
|
||||
uint32_t u;
|
||||
float f;
|
||||
};
|
||||
|
||||
static const fu32 K = { 0x77800000 };
|
||||
|
||||
fu32 o;
|
||||
o.u = h << 13;
|
||||
o.f *= K.f;
|
||||
|
||||
return o.f;
|
||||
}
|
||||
|
||||
} // namespace basisu
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basis_etc.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basis_etc.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_frontend.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -2347,6 +2347,7 @@ namespace basisu
|
|||
continue;
|
||||
|
||||
uint64_t overall_best_err = 0;
|
||||
(void)overall_best_err;
|
||||
|
||||
uint64_t total_err[4][4][4];
|
||||
clear_obj(total_err);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_frontend.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_gpu_texture.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -15,13 +15,15 @@
|
|||
#include "basisu_gpu_texture.h"
|
||||
#include "basisu_enc.h"
|
||||
#include "basisu_pvrtc1_4.h"
|
||||
#if BASISU_USE_ASTC_DECOMPRESS
|
||||
#include "basisu_astc_decomp.h"
|
||||
#endif
|
||||
#include "3rdparty/android_astc_decomp.h"
|
||||
#include "basisu_bc7enc.h"
|
||||
#include "../transcoder/basisu_astc_hdr_core.h"
|
||||
|
||||
namespace basisu
|
||||
{
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// ETC2 EAC
|
||||
|
||||
void unpack_etc2_eac(const void *pBlock_bits, color_rgba *pPixels)
|
||||
{
|
||||
static_assert(sizeof(eac_a8_block) == 8, "sizeof(eac_a8_block) == 8");
|
||||
|
|
@ -56,6 +58,8 @@ namespace basisu
|
|||
pPixels[15].a = clamp255(base + pTable[pBlock->get_selector(3, 3, selector_bits)] * mul);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// BC1
|
||||
struct bc1_block
|
||||
{
|
||||
enum { cTotalEndpointBytes = 2, cTotalSelectorBytes = 4 };
|
||||
|
|
@ -274,6 +278,9 @@ namespace basisu
|
|||
return used_punchthrough;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// BC3-5
|
||||
|
||||
struct bc4_block
|
||||
{
|
||||
enum { cBC4SelectorBits = 3, cTotalSelectorBytes = 6, cMaxSelectorValues = 8 };
|
||||
|
|
@ -372,7 +379,8 @@ namespace basisu
|
|||
unpack_bc4(pBlock_bits, &pPixels[0].r, sizeof(color_rgba));
|
||||
unpack_bc4((const uint8_t *)pBlock_bits + sizeof(bc4_block), &pPixels[0].g, sizeof(color_rgba));
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// ATC isn't officially documented, so I'm assuming these references:
|
||||
// http://www.guildsoftware.com/papers/2012.Converting.DXTC.to.ATC.pdf
|
||||
// https://github.com/Triang3l/S3TConv/blob/master/s3tconv_atitc.c
|
||||
|
|
@ -426,6 +434,7 @@ namespace basisu
|
|||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// BC7 mode 0-7 decompression.
|
||||
// Instead of one monster routine to unpack all the BC7 modes, we're lumping the 3 subset, 2 subset, 1 subset, and dual plane modes together into simple shared routines.
|
||||
|
||||
|
|
@ -742,6 +751,255 @@ namespace basisu
|
|||
return false;
|
||||
}
|
||||
|
||||
static inline int bc6h_sign_extend(int val, int bits)
|
||||
{
|
||||
assert((bits >= 1) && (bits < 32));
|
||||
assert((val >= 0) && (val < (1 << bits)));
|
||||
return (val << (32 - bits)) >> (32 - bits);
|
||||
}
|
||||
|
||||
static inline int bc6h_apply_delta(int base, int delta, int num_bits, int is_signed)
|
||||
{
|
||||
int bitmask = ((1 << num_bits) - 1);
|
||||
int v = (base + delta) & bitmask;
|
||||
return is_signed ? bc6h_sign_extend(v, num_bits) : v;
|
||||
}
|
||||
|
||||
static int bc6h_dequantize(int val, int bits, int is_signed)
|
||||
{
|
||||
int result;
|
||||
if (is_signed)
|
||||
{
|
||||
if (bits >= 16)
|
||||
result = val;
|
||||
else
|
||||
{
|
||||
int s_flag = 0;
|
||||
if (val < 0)
|
||||
{
|
||||
s_flag = 1;
|
||||
val = -val;
|
||||
}
|
||||
|
||||
if (val == 0)
|
||||
result = 0;
|
||||
else if (val >= ((1 << (bits - 1)) - 1))
|
||||
result = 0x7FFF;
|
||||
else
|
||||
result = ((val << 15) + 0x4000) >> (bits - 1);
|
||||
|
||||
if (s_flag)
|
||||
result = -result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bits >= 15)
|
||||
result = val;
|
||||
else if (!val)
|
||||
result = 0;
|
||||
else if (val == ((1 << bits) - 1))
|
||||
result = 0xFFFF;
|
||||
else
|
||||
result = ((val << 16) + 0x8000) >> bits;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline int bc6h_interpolate(int a, int b, const uint8_t* pWeights, int index)
|
||||
{
|
||||
return (a * (64 - (int)pWeights[index]) + b * (int)pWeights[index] + 32) >> 6;
|
||||
}
|
||||
|
||||
static inline basist::half_float bc6h_convert_to_half(int val, int is_signed)
|
||||
{
|
||||
if (!is_signed)
|
||||
{
|
||||
// scale by 31/64
|
||||
return (basist::half_float)((val * 31) >> 6);
|
||||
}
|
||||
|
||||
// scale by 31/32
|
||||
val = (val < 0) ? -(((-val) * 31) >> 5) : (val * 31) >> 5;
|
||||
|
||||
int s = 0;
|
||||
if (val < 0)
|
||||
{
|
||||
s = 0x8000;
|
||||
val = -val;
|
||||
}
|
||||
|
||||
return (basist::half_float)(s | val);
|
||||
}
|
||||
|
||||
static inline uint32_t bc6h_get_bits(uint32_t num_bits, uint64_t& l, uint64_t& h, uint32_t& total_bits)
|
||||
{
|
||||
assert((num_bits) && (num_bits <= 63));
|
||||
|
||||
uint32_t v = (uint32_t)(l & ((1U << num_bits) - 1U));
|
||||
|
||||
l >>= num_bits;
|
||||
l |= (h << (64U - num_bits));
|
||||
h >>= num_bits;
|
||||
|
||||
total_bits += num_bits;
|
||||
assert(total_bits <= 128);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline uint32_t bc6h_reverse_bits(uint32_t v, uint32_t num_bits)
|
||||
{
|
||||
uint32_t res = 0;
|
||||
for (uint32_t i = 0; i < num_bits; i++)
|
||||
{
|
||||
uint32_t bit = (v & (1u << i)) != 0u;
|
||||
res |= (bit << (num_bits - 1u - i));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline uint64_t bc6h_read_le_qword(const void* p)
|
||||
{
|
||||
const uint8_t* pSrc = static_cast<const uint8_t*>(p);
|
||||
return ((uint64_t)read_le_dword(pSrc)) | (((uint64_t)read_le_dword(pSrc + sizeof(uint32_t))) << 32U);
|
||||
}
|
||||
|
||||
bool unpack_bc6h(const void* pSrc_block, void* pDst_block, bool is_signed, uint32_t dest_pitch_in_halfs)
|
||||
{
|
||||
assert(dest_pitch_in_halfs >= 4 * 3);
|
||||
|
||||
const uint32_t MAX_SUBSETS = 2, MAX_COMPS = 3;
|
||||
|
||||
const uint8_t* pSrc = static_cast<const uint8_t*>(pSrc_block);
|
||||
basist::half_float* pDst = static_cast<basist::half_float*>(pDst_block);
|
||||
|
||||
uint64_t blo = bc6h_read_le_qword(pSrc), bhi = bc6h_read_le_qword(pSrc + sizeof(uint64_t));
|
||||
|
||||
// Unpack mode
|
||||
const int mode = basist::g_bc6h_mode_lookup[blo & 31];
|
||||
if (mode < 0)
|
||||
{
|
||||
for (int y = 0; y < 4; y++)
|
||||
{
|
||||
memset(pDst, 0, sizeof(basist::half_float) * 4);
|
||||
pDst += dest_pitch_in_halfs;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip mode bits
|
||||
uint32_t total_bits_read = 0;
|
||||
bc6h_get_bits((mode < 2) ? 2 : 5, blo, bhi, total_bits_read);
|
||||
|
||||
assert(mode < (int)basist::NUM_BC6H_MODES);
|
||||
|
||||
const uint32_t num_subsets = (mode >= 10) ? 1 : 2;
|
||||
const bool is_mode_9_or_10 = (mode == 9) || (mode == 10);
|
||||
|
||||
// Unpack endpoint components
|
||||
int comps[MAX_SUBSETS][MAX_COMPS][2] = { { { 0 } } }; // [subset][comp][l/h]
|
||||
int part_index = 0;
|
||||
|
||||
uint32_t layout_index = 0;
|
||||
while (layout_index < basist::MAX_BC6H_LAYOUT_INDEX)
|
||||
{
|
||||
const basist::bc6h_bit_layout& layout = basist::g_bc6h_bit_layouts[mode][layout_index];
|
||||
|
||||
if (layout.m_comp < 0)
|
||||
break;
|
||||
|
||||
const int subset = layout.m_index >> 1, lh_index = layout.m_index & 1;
|
||||
assert((layout.m_comp == 3) || ((subset >= 0) && (subset < (int)MAX_SUBSETS)));
|
||||
|
||||
const int last_bit = layout.m_last_bit, first_bit = layout.m_first_bit;
|
||||
assert(last_bit >= 0);
|
||||
|
||||
int& res = (layout.m_comp == 3) ? part_index : comps[subset][layout.m_comp][lh_index];
|
||||
|
||||
if (first_bit < 0)
|
||||
{
|
||||
res |= (bc6h_get_bits(1, blo, bhi, total_bits_read) << last_bit);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int total_bits = iabs(last_bit - first_bit) + 1;
|
||||
const int bit_shift = basisu::minimum(first_bit, last_bit);
|
||||
|
||||
int b = bc6h_get_bits(total_bits, blo, bhi, total_bits_read);
|
||||
|
||||
if (last_bit < first_bit)
|
||||
b = bc6h_reverse_bits(b, total_bits);
|
||||
|
||||
res |= (b << bit_shift);
|
||||
}
|
||||
|
||||
layout_index++;
|
||||
}
|
||||
assert(layout_index != basist::MAX_BC6H_LAYOUT_INDEX);
|
||||
|
||||
// Sign extend/dequantize endpoints
|
||||
const int num_sig_bits = basist::g_bc6h_mode_sig_bits[mode][0];
|
||||
if (is_signed)
|
||||
{
|
||||
for (uint32_t comp = 0; comp < 3; comp++)
|
||||
comps[0][comp][0] = bc6h_sign_extend(comps[0][comp][0], num_sig_bits);
|
||||
}
|
||||
|
||||
if (is_signed || !is_mode_9_or_10)
|
||||
{
|
||||
for (uint32_t subset = 0; subset < num_subsets; subset++)
|
||||
for (uint32_t comp = 0; comp < 3; comp++)
|
||||
for (uint32_t lh = (subset ? 0 : 1); lh < 2; lh++)
|
||||
comps[subset][comp][lh] = bc6h_sign_extend(comps[subset][comp][lh], basist::g_bc6h_mode_sig_bits[mode][1 + comp]);
|
||||
}
|
||||
|
||||
if (!is_mode_9_or_10)
|
||||
{
|
||||
for (uint32_t subset = 0; subset < num_subsets; subset++)
|
||||
for (uint32_t comp = 0; comp < 3; comp++)
|
||||
for (uint32_t lh = (subset ? 0 : 1); lh < 2; lh++)
|
||||
comps[subset][comp][lh] = bc6h_apply_delta(comps[0][comp][0], comps[subset][comp][lh], num_sig_bits, is_signed);
|
||||
}
|
||||
|
||||
for (uint32_t subset = 0; subset < num_subsets; subset++)
|
||||
for (uint32_t comp = 0; comp < 3; comp++)
|
||||
for (uint32_t lh = 0; lh < 2; lh++)
|
||||
comps[subset][comp][lh] = bc6h_dequantize(comps[subset][comp][lh], num_sig_bits, is_signed);
|
||||
|
||||
// Now unpack weights and output texels
|
||||
const int weight_bits = (mode >= 10) ? 4 : 3;
|
||||
const uint8_t* pWeights = (mode >= 10) ? basist::g_bc6h_weight4 : basist::g_bc6h_weight3;
|
||||
|
||||
dest_pitch_in_halfs -= 4 * 3;
|
||||
|
||||
for (uint32_t y = 0; y < 4; y++)
|
||||
{
|
||||
for (uint32_t x = 0; x < 4; x++)
|
||||
{
|
||||
int subset = (num_subsets == 1) ? ((x | y) ? 0 : 0x80) : basist::g_bc6h_2subset_patterns[part_index][y][x];
|
||||
const int num_bits = weight_bits + ((subset & 0x80) ? -1 : 0);
|
||||
|
||||
subset &= 1;
|
||||
|
||||
const int weight_index = bc6h_get_bits(num_bits, blo, bhi, total_bits_read);
|
||||
|
||||
pDst[0] = bc6h_convert_to_half(bc6h_interpolate(comps[subset][0][0], comps[subset][0][1], pWeights, weight_index), is_signed);
|
||||
pDst[1] = bc6h_convert_to_half(bc6h_interpolate(comps[subset][1][0], comps[subset][1][1], pWeights, weight_index), is_signed);
|
||||
pDst[2] = bc6h_convert_to_half(bc6h_interpolate(comps[subset][2][0], comps[subset][2][1], pWeights, weight_index), is_signed);
|
||||
|
||||
pDst += 3;
|
||||
}
|
||||
|
||||
pDst += dest_pitch_in_halfs;
|
||||
}
|
||||
|
||||
assert(total_bits_read == 128);
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// FXT1 (for fun, and because some modern Intel parts support it, and because a subset is like BC1)
|
||||
|
||||
struct fxt1_block
|
||||
{
|
||||
union
|
||||
|
|
@ -901,6 +1159,9 @@ namespace basisu
|
|||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// PVRTC2 (non-interpolated, hard_flag=1 modulation=0 subset only!)
|
||||
|
||||
struct pvrtc2_block
|
||||
{
|
||||
uint8_t m_modulation[4];
|
||||
|
|
@ -1015,6 +1276,9 @@ namespace basisu
|
|||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// ETC2 EAC R11 or RG11
|
||||
|
||||
struct etc2_eac_r11
|
||||
{
|
||||
uint64_t m_base : 8;
|
||||
|
|
@ -1085,13 +1349,16 @@ namespace basisu
|
|||
unpack_etc2_eac_r(pBlock, pPixels, c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// UASTC
|
||||
|
||||
void unpack_uastc(const void* p, color_rgba* pPixels)
|
||||
{
|
||||
basist::unpack_uastc(*static_cast<const basist::uastc_block*>(p), (basist::color32 *)pPixels, false);
|
||||
}
|
||||
|
||||
// Unpacks to RGBA, R, RG, or A
|
||||
|
||||
// Unpacks to RGBA, R, RG, or A. LDR GPU texture formats only.
|
||||
bool unpack_block(texture_format fmt, const void* pBlock, color_rgba* pPixels)
|
||||
{
|
||||
switch (fmt)
|
||||
|
|
@ -1150,14 +1417,24 @@ namespace basisu
|
|||
unpack_etc2_eac(pBlock, pPixels);
|
||||
break;
|
||||
}
|
||||
case texture_format::cASTC4x4:
|
||||
case texture_format::cBC6HSigned:
|
||||
case texture_format::cBC6HUnsigned:
|
||||
case texture_format::cASTC_HDR_4x4:
|
||||
case texture_format::cUASTC_HDR_4x4:
|
||||
{
|
||||
// Can't unpack HDR blocks in unpack_block() because it returns 32bpp pixel data.
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
case texture_format::cASTC_LDR_4x4:
|
||||
{
|
||||
#if BASISU_USE_ASTC_DECOMPRESS
|
||||
const bool astc_srgb = false;
|
||||
basisu_astc::astc::decompress(reinterpret_cast<uint8_t*>(pPixels), static_cast<const uint8_t*>(pBlock), astc_srgb, 4, 4);
|
||||
#else
|
||||
memset(pPixels, 255, 16 * sizeof(color_rgba));
|
||||
#endif
|
||||
bool status = basisu_astc::astc::decompress_ldr(reinterpret_cast<uint8_t*>(pPixels), static_cast<const uint8_t*>(pBlock), astc_srgb, 4, 4);
|
||||
assert(status);
|
||||
|
||||
if (!status)
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
case texture_format::cATC_RGB:
|
||||
|
|
@ -1206,6 +1483,66 @@ namespace basisu
|
|||
return true;
|
||||
}
|
||||
|
||||
bool unpack_block_hdr(texture_format fmt, const void* pBlock, vec4F* pPixels)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case texture_format::cASTC_HDR_4x4:
|
||||
case texture_format::cUASTC_HDR_4x4:
|
||||
{
|
||||
#if 1
|
||||
bool status = basisu_astc::astc::decompress_hdr(&pPixels[0][0], (uint8_t*)pBlock, 4, 4);
|
||||
assert(status);
|
||||
if (!status)
|
||||
return false;
|
||||
#else
|
||||
basist::half_float half_block[16][4];
|
||||
|
||||
astc_helpers::log_astc_block log_blk;
|
||||
if (!astc_helpers::unpack_block(pBlock, log_blk, 4, 4))
|
||||
return false;
|
||||
if (!astc_helpers::decode_block(log_blk, half_block, 4, 4, astc_helpers::cDecodeModeHDR16))
|
||||
return false;
|
||||
|
||||
for (uint32_t p = 0; p < 16; p++)
|
||||
{
|
||||
pPixels[p][0] = basist::half_to_float(half_block[p][0]);
|
||||
pPixels[p][1] = basist::half_to_float(half_block[p][1]);
|
||||
pPixels[p][2] = basist::half_to_float(half_block[p][2]);
|
||||
pPixels[p][3] = basist::half_to_float(half_block[p][3]);
|
||||
}
|
||||
|
||||
//memset(pPixels, 0, sizeof(vec4F) * 16);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
case texture_format::cBC6HSigned:
|
||||
case texture_format::cBC6HUnsigned:
|
||||
{
|
||||
basist::half_float half_block[16][3];
|
||||
|
||||
unpack_bc6h(pBlock, half_block, fmt == texture_format::cBC6HSigned);
|
||||
|
||||
for (uint32_t p = 0; p < 16; p++)
|
||||
{
|
||||
pPixels[p][0] = basist::half_to_float(half_block[p][0]);
|
||||
pPixels[p][1] = basist::half_to_float(half_block[p][1]);
|
||||
pPixels[p][2] = basist::half_to_float(half_block[p][2]);
|
||||
pPixels[p][3] = 1.0f;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gpu_image::unpack(image& img) const
|
||||
{
|
||||
img.resize(get_pixel_width(), get_pixel_height());
|
||||
|
|
@ -1252,7 +1589,48 @@ namespace basisu
|
|||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool gpu_image::unpack_hdr(imagef& img) const
|
||||
{
|
||||
if ((m_fmt != texture_format::cASTC_HDR_4x4) &&
|
||||
(m_fmt != texture_format::cUASTC_HDR_4x4) &&
|
||||
(m_fmt != texture_format::cBC6HUnsigned) &&
|
||||
(m_fmt != texture_format::cBC6HSigned))
|
||||
{
|
||||
// Can't call on LDR images, at least currently. (Could unpack the LDR data and convert to float.)
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
img.resize(get_pixel_width(), get_pixel_height());
|
||||
img.set_all(vec4F(0.0f));
|
||||
|
||||
if (!img.get_width() || !img.get_height())
|
||||
return true;
|
||||
|
||||
assert((m_block_width <= cMaxBlockSize) && (m_block_height <= cMaxBlockSize));
|
||||
vec4F pixels[cMaxBlockSize * cMaxBlockSize];
|
||||
clear_obj(pixels);
|
||||
|
||||
bool success = true;
|
||||
|
||||
for (uint32_t by = 0; by < m_blocks_y; by++)
|
||||
{
|
||||
for (uint32_t bx = 0; bx < m_blocks_x; bx++)
|
||||
{
|
||||
const void* pBlock = get_block_ptr(bx, by);
|
||||
|
||||
if (!unpack_block_hdr(m_fmt, pBlock, pixels))
|
||||
success = false;
|
||||
|
||||
img.set_block_clipped(pixels, bx * m_block_width, by * m_block_height, m_block_width, m_block_height);
|
||||
} // bx
|
||||
} // by
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// KTX1 texture file writing
|
||||
static const uint8_t g_ktx_file_id[12] = { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
|
||||
|
||||
// KTX/GL enums
|
||||
|
|
@ -1273,6 +1651,8 @@ namespace basisu
|
|||
KTX_COMPRESSED_RGBA8_ETC2_EAC = 0x9278,
|
||||
KTX_COMPRESSED_RGBA_BPTC_UNORM = 0x8E8C,
|
||||
KTX_COMPRESSED_SRGB_ALPHA_BPTC_UNORM = 0x8E8D,
|
||||
KTX_COMPRESSED_RGB_BPTC_SIGNED_FLOAT = 0x8E8E,
|
||||
KTX_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x8E8F,
|
||||
KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00,
|
||||
KTX_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02,
|
||||
KTX_COMPRESSED_RGBA_ASTC_4x4_KHR = 0x93B0,
|
||||
|
|
@ -1319,6 +1699,7 @@ namespace basisu
|
|||
uint32_t width = 0, height = 0, total_levels = 0;
|
||||
basisu::texture_format fmt = texture_format::cInvalidTextureFormat;
|
||||
|
||||
// Sanity check the input
|
||||
if (cubemap_flag)
|
||||
{
|
||||
if ((gpu_images.size() % 6) != 0)
|
||||
|
|
@ -1327,7 +1708,7 @@ namespace basisu
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (uint32_t array_index = 0; array_index < gpu_images.size(); array_index++)
|
||||
{
|
||||
const gpu_image_vec &levels = gpu_images[array_index];
|
||||
|
|
@ -1426,6 +1807,18 @@ namespace basisu
|
|||
base_internal_fmt = KTX_RGBA;
|
||||
break;
|
||||
}
|
||||
case texture_format::cBC6HSigned:
|
||||
{
|
||||
internal_fmt = KTX_COMPRESSED_RGB_BPTC_SIGNED_FLOAT;
|
||||
base_internal_fmt = KTX_RGBA;
|
||||
break;
|
||||
}
|
||||
case texture_format::cBC6HUnsigned:
|
||||
{
|
||||
internal_fmt = KTX_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
|
||||
base_internal_fmt = KTX_RGBA;
|
||||
break;
|
||||
}
|
||||
case texture_format::cBC7:
|
||||
{
|
||||
internal_fmt = KTX_COMPRESSED_RGBA_BPTC_UNORM;
|
||||
|
|
@ -1443,7 +1836,10 @@ namespace basisu
|
|||
base_internal_fmt = KTX_RGBA;
|
||||
break;
|
||||
}
|
||||
case texture_format::cASTC4x4:
|
||||
// We use different enums for HDR vs. LDR ASTC, but internally they are both just ASTC.
|
||||
case texture_format::cASTC_LDR_4x4:
|
||||
case texture_format::cASTC_HDR_4x4:
|
||||
case texture_format::cUASTC_HDR_4x4: // UASTC_HDR is just HDR-only ASTC
|
||||
{
|
||||
internal_fmt = KTX_COMPRESSED_RGBA_ASTC_4x4_KHR;
|
||||
base_internal_fmt = KTX_RGBA;
|
||||
|
|
@ -1496,17 +1892,17 @@ namespace basisu
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ktx_header header;
|
||||
header.clear();
|
||||
memcpy(&header.m_identifier, g_ktx_file_id, sizeof(g_ktx_file_id));
|
||||
header.m_endianness = KTX_ENDIAN;
|
||||
|
||||
|
||||
header.m_pixelWidth = width;
|
||||
header.m_pixelHeight = height;
|
||||
|
||||
|
||||
header.m_glTypeSize = 1;
|
||||
|
||||
|
||||
header.m_glInternalFormat = internal_fmt;
|
||||
header.m_glBaseInternalFormat = base_internal_fmt;
|
||||
|
||||
|
|
@ -1517,12 +1913,12 @@ namespace basisu
|
|||
header.m_numberOfMipmapLevels = total_levels;
|
||||
header.m_numberOfFaces = cubemap_flag ? 6 : 1;
|
||||
|
||||
append_vector(ktx_data, (uint8_t *)&header, sizeof(header));
|
||||
append_vector(ktx_data, (uint8_t*)&header, sizeof(header));
|
||||
|
||||
for (uint32_t level_index = 0; level_index < total_levels; level_index++)
|
||||
{
|
||||
uint32_t img_size = gpu_images[0][level_index].get_size_in_bytes();
|
||||
|
||||
|
||||
if ((header.m_numberOfFaces == 1) || (header.m_numberOfArrayElements > 1))
|
||||
{
|
||||
img_size = img_size * header.m_numberOfFaces * maximum<uint32_t>(1, header.m_numberOfArrayElements);
|
||||
|
|
@ -1531,9 +1927,10 @@ namespace basisu
|
|||
assert(img_size && ((img_size & 3) == 0));
|
||||
|
||||
packed_uint<4> packed_img_size(img_size);
|
||||
append_vector(ktx_data, (uint8_t *)&packed_img_size, sizeof(packed_img_size));
|
||||
append_vector(ktx_data, (uint8_t*)&packed_img_size, sizeof(packed_img_size));
|
||||
|
||||
uint32_t bytes_written = 0;
|
||||
(void)bytes_written;
|
||||
|
||||
for (uint32_t array_index = 0; array_index < maximum<uint32_t>(1, header.m_numberOfArrayElements); array_index++)
|
||||
{
|
||||
|
|
@ -1541,11 +1938,11 @@ namespace basisu
|
|||
{
|
||||
const gpu_image& img = gpu_images[cubemap_flag ? (array_index * 6 + face_index) : array_index][level_index];
|
||||
|
||||
append_vector(ktx_data, (uint8_t *)img.get_ptr(), img.get_size_in_bytes());
|
||||
|
||||
append_vector(ktx_data, (uint8_t*)img.get_ptr(), img.get_size_in_bytes());
|
||||
|
||||
bytes_written += img.get_size_in_bytes();
|
||||
}
|
||||
|
||||
|
||||
} // array_index
|
||||
|
||||
} // level_index
|
||||
|
|
@ -1553,7 +1950,58 @@ namespace basisu
|
|||
return true;
|
||||
}
|
||||
|
||||
bool write_compressed_texture_file(const char* pFilename, const basisu::vector<gpu_image_vec>& g, bool cubemap_flag)
|
||||
bool does_dds_support_format(texture_format fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
{
|
||||
case texture_format::cBC1_NV:
|
||||
case texture_format::cBC1_AMD:
|
||||
case texture_format::cBC1:
|
||||
case texture_format::cBC3:
|
||||
case texture_format::cBC4:
|
||||
case texture_format::cBC5:
|
||||
case texture_format::cBC6HSigned:
|
||||
case texture_format::cBC6HUnsigned:
|
||||
case texture_format::cBC7:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only supports the basic DirectX BC texture formats.
|
||||
// gpu_images array is: [face/layer][mipmap level]
|
||||
// For cubemap arrays, # of face/layers must be a multiple of 6.
|
||||
// Accepts 2D, 2D mipmapped, 2D array, 2D array mipmapped
|
||||
// and cubemap, cubemap mipmapped, and cubemap array mipmapped.
|
||||
bool write_dds_file(uint8_vec &dds_data, const basisu::vector<gpu_image_vec>& gpu_images, bool cubemap_flag, bool use_srgb_format)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool write_dds_file(const char* pFilename, const basisu::vector<gpu_image_vec>& gpu_images, bool cubemap_flag, bool use_srgb_format)
|
||||
{
|
||||
uint8_vec dds_data;
|
||||
|
||||
if (!write_dds_file(dds_data, gpu_images, cubemap_flag, use_srgb_format))
|
||||
return false;
|
||||
|
||||
if (!write_vec_to_file(pFilename, dds_data))
|
||||
{
|
||||
fprintf(stderr, "write_dds_file: Failed writing DDS file data\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool read_uncompressed_dds_file(const char* pFilename, basisu::vector<image> &ldr_mips, basisu::vector<imagef>& hdr_mips)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool write_compressed_texture_file(const char* pFilename, const basisu::vector<gpu_image_vec>& g, bool cubemap_flag, bool use_srgb_format)
|
||||
{
|
||||
std::string extension(string_tolower(string_get_extension(pFilename)));
|
||||
|
||||
|
|
@ -1570,8 +2018,8 @@ namespace basisu
|
|||
}
|
||||
else if (extension == "dds")
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
if (!write_dds_file(filedata, g, cubemap_flag, use_srgb_format))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1583,11 +2031,18 @@ namespace basisu
|
|||
return basisu::write_vec_to_file(pFilename, filedata);
|
||||
}
|
||||
|
||||
bool write_compressed_texture_file(const char* pFilename, const gpu_image& g)
|
||||
bool write_compressed_texture_file(const char* pFilename, const gpu_image_vec& g, bool use_srgb_format)
|
||||
{
|
||||
basisu::vector<gpu_image_vec> a;
|
||||
a.push_back(g);
|
||||
return write_compressed_texture_file(pFilename, a, false, use_srgb_format);
|
||||
}
|
||||
|
||||
bool write_compressed_texture_file(const char* pFilename, const gpu_image& g, bool use_srgb_format)
|
||||
{
|
||||
basisu::vector<gpu_image_vec> v;
|
||||
enlarge_vector(v, 1)->push_back(g);
|
||||
return write_compressed_texture_file(pFilename, v, false);
|
||||
return write_compressed_texture_file(pFilename, v, false, use_srgb_format);
|
||||
}
|
||||
|
||||
//const uint32_t OUT_FILE_MAGIC = 'TEXC';
|
||||
|
|
@ -1626,5 +2081,49 @@ namespace basisu
|
|||
|
||||
return fclose(pFile) != EOF;
|
||||
}
|
||||
|
||||
// The .astc texture format is readable using ARM's astcenc, AMD Compressonator, and other engines/tools. It oddly doesn't support mipmaps, limiting
|
||||
// its usefulness/relevance.
|
||||
// https://github.com/ARM-software/astc-encoder/blob/main/Docs/FileFormat.md
|
||||
bool write_astc_file(const char* pFilename, const void* pBlocks, uint32_t block_width, uint32_t block_height, uint32_t dim_x, uint32_t dim_y)
|
||||
{
|
||||
assert(pBlocks && (block_width >= 4) && (block_height >= 4) && (dim_x > 0) && (dim_y > 0));
|
||||
|
||||
uint8_vec file_data;
|
||||
file_data.push_back(0x13);
|
||||
file_data.push_back(0xAB);
|
||||
file_data.push_back(0xA1);
|
||||
file_data.push_back(0x5C);
|
||||
|
||||
file_data.push_back((uint8_t)block_width);
|
||||
file_data.push_back((uint8_t)block_height);
|
||||
file_data.push_back(1);
|
||||
|
||||
file_data.push_back((uint8_t)dim_x);
|
||||
file_data.push_back((uint8_t)(dim_x >> 8));
|
||||
file_data.push_back((uint8_t)(dim_x >> 16));
|
||||
|
||||
file_data.push_back((uint8_t)dim_y);
|
||||
file_data.push_back((uint8_t)(dim_y >> 8));
|
||||
file_data.push_back((uint8_t)(dim_y >> 16));
|
||||
|
||||
file_data.push_back((uint8_t)1);
|
||||
file_data.push_back((uint8_t)0);
|
||||
file_data.push_back((uint8_t)0);
|
||||
|
||||
const uint32_t num_blocks_x = (dim_x + block_width - 1) / block_width;
|
||||
const uint32_t num_blocks_y = (dim_y + block_height - 1) / block_height;
|
||||
|
||||
const uint32_t total_bytes = num_blocks_x * num_blocks_y * 16;
|
||||
|
||||
const size_t cur_size = file_data.size();
|
||||
|
||||
file_data.resize(cur_size + total_bytes);
|
||||
|
||||
memcpy(&file_data[cur_size], pBlocks, total_bytes);
|
||||
|
||||
return write_vec_to_file(pFilename, file_data);
|
||||
}
|
||||
|
||||
} // basisu
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_gpu_texture.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -48,6 +48,7 @@ namespace basisu
|
|||
}
|
||||
|
||||
inline texture_format get_format() const { return m_fmt; }
|
||||
inline bool is_hdr() const { return is_hdr_texture_format(m_fmt); }
|
||||
|
||||
// Width/height in pixels
|
||||
inline uint32_t get_pixel_width() const { return m_width; }
|
||||
|
|
@ -100,9 +101,13 @@ namespace basisu
|
|||
m_blocks.resize(m_blocks_x * m_blocks_y * m_qwords_per_block);
|
||||
}
|
||||
|
||||
// Unpacks LDR textures only.
|
||||
bool unpack(image& img) const;
|
||||
|
||||
// Unpacks HDR textures only.
|
||||
bool unpack_hdr(imagef& img) const;
|
||||
|
||||
void override_dimensions(uint32_t w, uint32_t h)
|
||||
inline void override_dimensions(uint32_t w, uint32_t h)
|
||||
{
|
||||
m_width = w;
|
||||
m_height = h;
|
||||
|
|
@ -116,39 +121,50 @@ namespace basisu
|
|||
|
||||
typedef basisu::vector<gpu_image> gpu_image_vec;
|
||||
|
||||
// KTX file writing
|
||||
|
||||
// KTX1 file writing
|
||||
bool create_ktx_texture_file(uint8_vec &ktx_data, const basisu::vector<gpu_image_vec>& gpu_images, bool cubemap_flag);
|
||||
|
||||
bool write_compressed_texture_file(const char *pFilename, const basisu::vector<gpu_image_vec>& g, bool cubemap_flag);
|
||||
|
||||
inline bool write_compressed_texture_file(const char *pFilename, const gpu_image_vec &g)
|
||||
{
|
||||
basisu::vector<gpu_image_vec> a;
|
||||
a.push_back(g);
|
||||
return write_compressed_texture_file(pFilename, a, false);
|
||||
}
|
||||
bool does_dds_support_format(texture_format fmt);
|
||||
bool write_dds_file(uint8_vec& dds_data, const basisu::vector<gpu_image_vec>& gpu_images, bool cubemap_flag, bool use_srgb_format);
|
||||
bool write_dds_file(const char* pFilename, const basisu::vector<gpu_image_vec>& gpu_images, bool cubemap_flag, bool use_srgb_format);
|
||||
|
||||
bool write_compressed_texture_file(const char *pFilename, const gpu_image &g);
|
||||
// Currently reads 2D 32bpp RGBA, 16-bit HALF RGBA, or 32-bit FLOAT RGBA, with or without mipmaps. No tex arrays or cubemaps, yet.
|
||||
bool read_uncompressed_dds_file(const char* pFilename, basisu::vector<image>& ldr_mips, basisu::vector<imagef>& hdr_mips);
|
||||
|
||||
// Supports DDS and KTX
|
||||
bool write_compressed_texture_file(const char *pFilename, const basisu::vector<gpu_image_vec>& g, bool cubemap_flag, bool use_srgb_format);
|
||||
bool write_compressed_texture_file(const char* pFilename, const gpu_image_vec& g, bool use_srgb_format);
|
||||
bool write_compressed_texture_file(const char *pFilename, const gpu_image &g, bool use_srgb_format);
|
||||
|
||||
bool write_3dfx_out_file(const char* pFilename, const gpu_image& gi);
|
||||
|
||||
// GPU texture block unpacking
|
||||
// For ETC1, use in basisu_etc.h: bool unpack_etc1(const etc_block& block, color_rgba *pDst, bool preserve_alpha)
|
||||
void unpack_etc2_eac(const void *pBlock_bits, color_rgba *pPixels);
|
||||
bool unpack_bc1(const void *pBlock_bits, color_rgba *pPixels, bool set_alpha);
|
||||
void unpack_bc4(const void *pBlock_bits, uint8_t *pPixels, uint32_t stride);
|
||||
bool unpack_bc3(const void *pBlock_bits, color_rgba *pPixels);
|
||||
void unpack_bc5(const void *pBlock_bits, color_rgba *pPixels);
|
||||
bool unpack_bc7_mode6(const void *pBlock_bits, color_rgba *pPixels);
|
||||
bool unpack_bc7(const void* pBlock_bits, color_rgba* pPixels);
|
||||
bool unpack_bc7(const void* pBlock_bits, color_rgba* pPixels); // full format
|
||||
bool unpack_bc6h(const void* pSrc_block, void* pDst_block, bool is_signed, uint32_t dest_pitch_in_halfs = 4 * 3); // full format, outputs HALF values, RGB texels only (not RGBA)
|
||||
void unpack_atc(const void* pBlock_bits, color_rgba* pPixels);
|
||||
// We only support CC_MIXED non-alpha blocks here because that's the only mode the transcoder uses at the moment.
|
||||
bool unpack_fxt1(const void* p, color_rgba* pPixels);
|
||||
// PVRTC2 is currently limited to only what our transcoder outputs (non-interpolated, hard_flag=1 modulation=0). In this mode, PVRTC2 looks much like BC1/ATC.
|
||||
bool unpack_pvrtc2(const void* p, color_rgba* pPixels);
|
||||
void unpack_etc2_eac_r(const void *p, color_rgba* pPixels, uint32_t c);
|
||||
void unpack_etc2_eac_rg(const void* p, color_rgba* pPixels);
|
||||
|
||||
|
||||
// unpack_block() is primarily intended to unpack texture data created by the transcoder.
|
||||
// For some texture formats (like ETC2 RGB, PVRTC2, FXT1) it's not a complete implementation.
|
||||
// For some texture formats (like ETC2 RGB, PVRTC2, FXT1) it's not yet a complete implementation.
|
||||
// Unpacks LDR texture formats only.
|
||||
bool unpack_block(texture_format fmt, const void *pBlock, color_rgba *pPixels);
|
||||
|
||||
|
||||
// Unpacks HDR texture formats only.
|
||||
bool unpack_block_hdr(texture_format fmt, const void* pBlock, vec4F* pPixels);
|
||||
|
||||
bool write_astc_file(const char* pFilename, const void* pBlocks, uint32_t block_width, uint32_t block_height, uint32_t dim_x, uint32_t dim_y);
|
||||
|
||||
} // namespace basisu
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_kernels_declares.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_kernels_imp.h - Do not directly include
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_kernels_sse.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -22,22 +22,6 @@
|
|||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#if __AVX__ || __AVX2__ || __AVX512F__
|
||||
#error Please check your compiler options
|
||||
#endif
|
||||
|
||||
#if CPPSPMD_SSE2
|
||||
#if __SSE4_1__ || __SSE3__ || __SSE4_2__ || __SSSE3__
|
||||
#error SSE4.1/SSE3/SSE4.2/SSSE3 cannot be enabled to use this file
|
||||
#endif
|
||||
#else
|
||||
#if !__SSE4_1__ || !__SSE3__ || !__SSSE3__
|
||||
#error Please check your compiler options
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "cppspmd_sse.h"
|
||||
|
||||
#include "cppspmd_type_aliases.h"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
Forked from the public domain/unlicense version at: https://code.google.com/archive/p/miniz/
|
||||
|
||||
Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
|
@ -1973,7 +1973,7 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe
|
|||
(TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) );
|
||||
if (!probe_len)
|
||||
{
|
||||
*pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break;
|
||||
*pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN); break;
|
||||
}
|
||||
else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len)
|
||||
{
|
||||
|
|
@ -2101,7 +2101,7 @@ static mz_bool tdefl_compress_fast(tdefl_compressor *d)
|
|||
|
||||
total_lz_bytes += cur_match_len;
|
||||
lookahead_pos += cur_match_len;
|
||||
dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE);
|
||||
dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE);
|
||||
cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
|
||||
MZ_ASSERT(lookahead_size >= cur_match_len);
|
||||
lookahead_size -= cur_match_len;
|
||||
|
|
@ -2129,7 +2129,7 @@ static mz_bool tdefl_compress_fast(tdefl_compressor *d)
|
|||
d->m_huff_count[0][lit]++;
|
||||
|
||||
lookahead_pos++;
|
||||
dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE);
|
||||
dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE);
|
||||
cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
|
||||
lookahead_size--;
|
||||
|
||||
|
|
@ -2283,7 +2283,7 @@ static mz_bool tdefl_compress_normal(tdefl_compressor *d)
|
|||
d->m_lookahead_pos += len_to_move;
|
||||
MZ_ASSERT(d->m_lookahead_size >= len_to_move);
|
||||
d->m_lookahead_size -= len_to_move;
|
||||
d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE);
|
||||
d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE);
|
||||
// Check if it's time to flush the current LZ codes to the internal output buffer.
|
||||
if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
|
||||
( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) )
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_opencl.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_opencl.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Note: Undefine or set BASISU_SUPPORT_OPENCL to 0 to completely OpenCL support.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_pvrtc1_4.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_pvrtc1_4.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -231,7 +231,18 @@ namespace basisu
|
|||
|
||||
inline void set_to_black()
|
||||
{
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||
#endif
|
||||
#endif
|
||||
memset(m_blocks.get_ptr(), 0, m_blocks.size_in_bytes());
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool get_block_uses_transparent_modulation(uint32_t bx, uint32_t by) const
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_resampler_filters.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_resampler.cpp
|
||||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_resampler.h
|
||||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_resampler_filters.h
|
||||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_ssim.cpp
|
||||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_ssim.h
|
||||
// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_uastc_enc.cpp
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -13,11 +13,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#include "basisu_uastc_enc.h"
|
||||
|
||||
#if BASISU_USE_ASTC_DECOMPRESS
|
||||
#include "basisu_astc_decomp.h"
|
||||
#endif
|
||||
|
||||
#include "3rdparty/android_astc_decomp.h"
|
||||
#include "basisu_gpu_texture.h"
|
||||
#include "basisu_bc7enc.h"
|
||||
|
||||
|
|
@ -384,6 +380,7 @@ namespace basisu
|
|||
}
|
||||
|
||||
uint32_t total_endpoint_bits = 0;
|
||||
(void)total_endpoint_bits;
|
||||
|
||||
for (uint32_t i = 0; i < total_tq_values; i++)
|
||||
{
|
||||
|
|
@ -428,6 +425,8 @@ namespace basisu
|
|||
#endif
|
||||
|
||||
uint32_t total_weight_bits = 0;
|
||||
(void)total_weight_bits;
|
||||
|
||||
const uint32_t plane_shift = (total_planes == 2) ? 1 : 0;
|
||||
for (uint32_t i = 0; i < 16 * total_planes; i++)
|
||||
{
|
||||
|
|
@ -3175,6 +3174,7 @@ namespace basisu
|
|||
const bool favor_bc7_error = !favor_uastc_error && ((flags & cPackUASTCFavorBC7Error) != 0);
|
||||
//const bool etc1_perceptual = true;
|
||||
|
||||
// TODO: This uses 64KB of stack space!
|
||||
uastc_encode_results results[MAX_ENCODE_RESULTS];
|
||||
|
||||
level = clampi(level, cPackUASTCLevelFastest, cPackUASTCLevelVerySlow);
|
||||
|
|
@ -3567,7 +3567,6 @@ namespace basisu
|
|||
success = basist::unpack_uastc(temp_block, (basist::color32 *)temp_block_unpacked, false);
|
||||
VALIDATE(success);
|
||||
|
||||
#if BASISU_USE_ASTC_DECOMPRESS
|
||||
// Now round trip to packed ASTC and back, then decode to pixels.
|
||||
uint32_t astc_data[4];
|
||||
|
||||
|
|
@ -3580,7 +3579,7 @@ namespace basisu
|
|||
}
|
||||
|
||||
color_rgba decoded_astc_block[4][4];
|
||||
success = basisu_astc::astc::decompress((uint8_t*)decoded_astc_block, (uint8_t*)&astc_data, false, 4, 4);
|
||||
success = basisu_astc::astc::decompress_ldr((uint8_t*)decoded_astc_block, (uint8_t*)&astc_data, false, 4, 4);
|
||||
VALIDATE(success);
|
||||
|
||||
for (uint32_t y = 0; y < 4; y++)
|
||||
|
|
@ -3595,7 +3594,6 @@ namespace basisu
|
|||
VALIDATE(temp_block_unpacked[y][x].c[3] == decoded_uastc_block[y][x].a);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -3789,8 +3787,9 @@ namespace basisu
|
|||
{
|
||||
uint64_t m_sel;
|
||||
uint32_t m_ofs;
|
||||
uint32_t m_pad; // avoid implicit padding for selector_bitsequence_hash
|
||||
selector_bitsequence() { }
|
||||
selector_bitsequence(uint32_t bit_ofs, uint64_t sel) : m_sel(sel), m_ofs(bit_ofs) { }
|
||||
selector_bitsequence(uint32_t bit_ofs, uint64_t sel) : m_sel(sel), m_ofs(bit_ofs), m_pad(0) { }
|
||||
bool operator== (const selector_bitsequence& other) const
|
||||
{
|
||||
return (m_ofs == other.m_ofs) && (m_sel == other.m_sel);
|
||||
|
|
@ -3811,7 +3810,7 @@ namespace basisu
|
|||
{
|
||||
std::size_t operator()(selector_bitsequence const& s) const noexcept
|
||||
{
|
||||
return static_cast<std::size_t>(hash_hsieh((uint8_t *)&s, sizeof(s)) ^ s.m_sel);
|
||||
return hash_hsieh((const uint8_t*)&s, sizeof(s));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
// basisu_uastc_enc.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Do not include this header directly.
|
||||
// Control flow functionality in common between all the headers.
|
||||
//
|
||||
// Copyright 2020-2021 Binomial LLC
|
||||
// Copyright 2020-2024 Binomial LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// Do not include this header directly.
|
||||
//
|
||||
// Copyright 2020-2021 Binomial LLC
|
||||
// Copyright 2020-2024 Binomial LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
@ -646,7 +646,7 @@ CPPSPMD_FORCE_INLINE vint spmd_kernel::count_set_bits(vint x)
|
|||
{
|
||||
vint v = x - (VUINT_SHIFT_RIGHT(x, 1) & 0x55555555);
|
||||
vint v1 = (v & 0x33333333) + (VUINT_SHIFT_RIGHT(v, 2) & 0x33333333);
|
||||
return VUINT_SHIFT_RIGHT(((v1 + VUINT_SHIFT_RIGHT(v1, 4) & 0xF0F0F0F) * 0x1010101), 24);
|
||||
return VUINT_SHIFT_RIGHT(((v1 + (VUINT_SHIFT_RIGHT(v1, 4) & 0xF0F0F0F)) * 0x1010101), 24);
|
||||
}
|
||||
|
||||
CPPSPMD_FORCE_INLINE vint cmple_epu16(const vint &a, const vint &b)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Do not include this header directly.
|
||||
// This header defines shared struct spmd_kernel helpers.
|
||||
//
|
||||
// Copyright 2020-2021 Binomial LLC
|
||||
// Copyright 2020-2024 Binomial LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -450,7 +450,7 @@ struct spmd_kernel
|
|||
CPPSPMD_FORCE_INLINE explicit operator vint() const;
|
||||
|
||||
private:
|
||||
vbool& operator=(const vbool&);
|
||||
//vbool& operator=(const vbool&);
|
||||
};
|
||||
|
||||
friend vbool operator!(const vbool& v);
|
||||
|
|
@ -481,7 +481,7 @@ struct spmd_kernel
|
|||
CPPSPMD_FORCE_INLINE explicit vfloat(int value) : m_value(_mm_set1_ps((float)value)) { }
|
||||
|
||||
private:
|
||||
vfloat& operator=(const vfloat&);
|
||||
//vfloat& operator=(const vfloat&);
|
||||
};
|
||||
|
||||
CPPSPMD_FORCE_INLINE vfloat& store(vfloat& dst, const vfloat& src)
|
||||
|
|
@ -514,7 +514,7 @@ struct spmd_kernel
|
|||
float* m_pValue;
|
||||
|
||||
private:
|
||||
float_lref& operator=(const float_lref&);
|
||||
//float_lref& operator=(const float_lref&);
|
||||
};
|
||||
|
||||
CPPSPMD_FORCE_INLINE const float_lref& store(const float_lref& dst, const vfloat& src)
|
||||
|
|
@ -561,7 +561,7 @@ struct spmd_kernel
|
|||
float* m_pValue;
|
||||
|
||||
private:
|
||||
float_vref& operator=(const float_vref&);
|
||||
//float_vref& operator=(const float_vref&);
|
||||
};
|
||||
|
||||
// Varying ref to varying float
|
||||
|
|
@ -571,7 +571,7 @@ struct spmd_kernel
|
|||
vfloat* m_pValue;
|
||||
|
||||
private:
|
||||
vfloat_vref& operator=(const vfloat_vref&);
|
||||
//vfloat_vref& operator=(const vfloat_vref&);
|
||||
};
|
||||
|
||||
// Varying ref to varying int
|
||||
|
|
@ -581,7 +581,7 @@ struct spmd_kernel
|
|||
vint* m_pValue;
|
||||
|
||||
private:
|
||||
vint_vref& operator=(const vint_vref&);
|
||||
//vint_vref& operator=(const vint_vref&);
|
||||
};
|
||||
|
||||
CPPSPMD_FORCE_INLINE const float_vref& store(const float_vref& dst, const vfloat& src);
|
||||
|
|
@ -624,7 +624,7 @@ struct spmd_kernel
|
|||
int* m_pValue;
|
||||
|
||||
private:
|
||||
int_lref& operator=(const int_lref&);
|
||||
//int_lref& operator=(const int_lref&);
|
||||
};
|
||||
|
||||
CPPSPMD_FORCE_INLINE const int_lref& store(const int_lref& dst, const vint& src)
|
||||
|
|
@ -663,7 +663,7 @@ struct spmd_kernel
|
|||
int16_t* m_pValue;
|
||||
|
||||
private:
|
||||
int16_lref& operator=(const int16_lref&);
|
||||
//int16_lref& operator=(const int16_lref&);
|
||||
};
|
||||
|
||||
CPPSPMD_FORCE_INLINE const int16_lref& store(const int16_lref& dst, const vint& src)
|
||||
|
|
@ -720,7 +720,7 @@ struct spmd_kernel
|
|||
const int* m_pValue;
|
||||
|
||||
private:
|
||||
cint_lref& operator=(const cint_lref&);
|
||||
//cint_lref& operator=(const cint_lref&);
|
||||
};
|
||||
|
||||
CPPSPMD_FORCE_INLINE vint load(const cint_lref& src)
|
||||
|
|
@ -742,7 +742,7 @@ struct spmd_kernel
|
|||
int* m_pValue;
|
||||
|
||||
private:
|
||||
int_vref& operator=(const int_vref&);
|
||||
//int_vref& operator=(const int_vref&);
|
||||
};
|
||||
|
||||
// Varying ref to constant ints
|
||||
|
|
@ -752,7 +752,7 @@ struct spmd_kernel
|
|||
const int* m_pValue;
|
||||
|
||||
private:
|
||||
cint_vref& operator=(const cint_vref&);
|
||||
//cint_vref& operator=(const cint_vref&);
|
||||
};
|
||||
|
||||
// Varying int
|
||||
|
|
@ -810,7 +810,7 @@ struct spmd_kernel
|
|||
}
|
||||
|
||||
private:
|
||||
vint& operator=(const vint&);
|
||||
//vint& operator=(const vint&);
|
||||
};
|
||||
|
||||
// Load/store linear int
|
||||
|
|
@ -1206,7 +1206,7 @@ struct spmd_kernel
|
|||
CPPSPMD_FORCE_INLINE vint load_all(const vint_vref& src)
|
||||
{
|
||||
// TODO: There's surely a better way
|
||||
__m128i k;
|
||||
__m128i k = _mm_setzero_si128();
|
||||
|
||||
k = insert_x(k, ((int*)(&src.m_pValue[extract_x(src.m_vindex)]))[0]);
|
||||
k = insert_y(k, ((int*)(&src.m_pValue[extract_y(src.m_vindex)]))[1]);
|
||||
|
|
@ -1261,7 +1261,7 @@ struct spmd_kernel
|
|||
}
|
||||
|
||||
private:
|
||||
lint& operator=(const lint&);
|
||||
//lint& operator=(const lint&);
|
||||
};
|
||||
|
||||
CPPSPMD_FORCE_INLINE lint& store_all(lint& dst, const lint& src)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// cppspmd_type_aliases.h
|
||||
// Do not include this file directly
|
||||
//
|
||||
// Copyright 2020-2021 Binomial LLC
|
||||
// Copyright 2020-2024 Binomial LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ public:
|
|||
{
|
||||
if ((sizeof(size_t) == sizeof(uint32_t)) && (new_size > 0x7FFFFFFFUL))
|
||||
return 0;
|
||||
m_buf.resize(new_size);
|
||||
m_buf.resize((size_t)new_size);
|
||||
}
|
||||
|
||||
memcpy(&m_buf[(size_t)m_ofs], pBuf, len);
|
||||
|
|
@ -178,11 +178,11 @@ public:
|
|||
return 0;
|
||||
|
||||
uint64_t max_bytes = minimum<uint64_t>(len, m_buf.size() - m_ofs);
|
||||
memcpy(pBuf, &m_buf[(size_t)m_ofs], max_bytes);
|
||||
memcpy(pBuf, &m_buf[(size_t)m_ofs], (size_t)max_bytes);
|
||||
|
||||
m_ofs += max_bytes;
|
||||
|
||||
return max_bytes;
|
||||
return (size_t)max_bytes;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -249,11 +249,11 @@ public:
|
|||
return 0;
|
||||
|
||||
uint64_t max_bytes = minimum<uint64_t>(len, m_buf_size - m_ofs);
|
||||
memcpy(pBuf, &m_pBuf[(size_t)m_ofs], max_bytes);
|
||||
memcpy(pBuf, &m_pBuf[(size_t)m_ofs], (size_t)max_bytes);
|
||||
|
||||
m_ofs += max_bytes;
|
||||
|
||||
return max_bytes;
|
||||
return (size_t)max_bytes;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -1626,8 +1626,8 @@ int png_decoder::png_decode_start()
|
|||
|
||||
if (m_ihdr.m_ilace_type == 1)
|
||||
{
|
||||
int i;
|
||||
uint32_t total_lines, lines_processed;
|
||||
//int i;
|
||||
//uint32_t total_lines, lines_processed;
|
||||
|
||||
m_adam7_pass_size_x[0] = adam7_pass_size(m_ihdr.m_width, 0, 8);
|
||||
m_adam7_pass_size_x[1] = adam7_pass_size(m_ihdr.m_width, 4, 8);
|
||||
|
|
@ -1651,10 +1651,12 @@ int png_decoder::png_decode_start()
|
|||
|
||||
m_pass_y_left = 0;
|
||||
|
||||
#if 0
|
||||
total_lines = lines_processed = 0;
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
total_lines += m_adam7_pass_size_y[i];
|
||||
#endif
|
||||
|
||||
for (; ; )
|
||||
{
|
||||
|
|
@ -1675,7 +1677,7 @@ int png_decoder::png_decode_start()
|
|||
}
|
||||
}
|
||||
|
||||
lines_processed++;
|
||||
//lines_processed++;
|
||||
}
|
||||
|
||||
m_adam7_decoded_flag = TRUE;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue