feat: updated engine version to 4.4-rc1

This commit is contained in:
Sara 2025-02-23 14:38:14 +01:00
parent ee00efde1f
commit 21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions

File diff suppressed because it is too large Load diff

View 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

File diff suppressed because it is too large Load diff

View 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

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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)

View file

@ -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

View file

@ -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.

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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.

View file

@ -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.

View file

@ -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);

View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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.

View file

@ -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"

View file

@ -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))) )

View file

@ -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.

View file

@ -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.
//

View file

@ -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.

View file

@ -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

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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));
}
};

View file

@ -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.

View file

@ -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.

View file

@ -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)

View file

@ -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.

View file

@ -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)

View file

@ -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.

View file

@ -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;