mirror of
https://github.com/godotengine/godot.git
synced 2024-11-21 19:42:43 +00:00
Merge pull request #97582 from BlueCube3310/basisu-hdr
BasisU: Update to 1.50.0 and add HDR support
This commit is contained in:
commit
56ed76a372
@ -339,11 +339,6 @@ Error ResourceImporterLayeredTexture::import(const String &p_source_file, const
|
||||
return err;
|
||||
}
|
||||
|
||||
if (compress_mode == COMPRESS_BASIS_UNIVERSAL && image->get_format() >= Image::FORMAT_RF) {
|
||||
//basis universal does not support float formats, fall back
|
||||
compress_mode = COMPRESS_VRAM_COMPRESSED;
|
||||
}
|
||||
|
||||
if (compress_mode == COMPRESS_VRAM_COMPRESSED) {
|
||||
//if using video ram, optimize
|
||||
if (channel_pack == 0) {
|
||||
|
@ -593,11 +593,6 @@ Error ResourceImporterTexture::import(const String &p_source_file, const String
|
||||
}
|
||||
}
|
||||
|
||||
if (compress_mode == COMPRESS_BASIS_UNIVERSAL && image->get_format() >= Image::FORMAT_RF) {
|
||||
// Basis universal does not support float formats, fallback.
|
||||
compress_mode = COMPRESS_VRAM_COMPRESSED;
|
||||
}
|
||||
|
||||
bool detect_3d = int(p_options["detect_3d/compress_to"]) > 0;
|
||||
bool detect_roughness = roughness == 0;
|
||||
bool detect_normal = normal == 0;
|
||||
|
@ -14,6 +14,8 @@ thirdparty_obj = []
|
||||
thirdparty_dir = "#thirdparty/basis_universal/"
|
||||
# Sync list with upstream CMakeLists.txt
|
||||
encoder_sources = [
|
||||
"3rdparty/android_astc_decomp.cpp",
|
||||
"basisu_astc_hdr_enc.cpp",
|
||||
"basisu_backend.cpp",
|
||||
"basisu_basis_file.cpp",
|
||||
"basisu_bc7enc.cpp",
|
||||
@ -45,6 +47,8 @@ else:
|
||||
if env["builtin_zstd"]:
|
||||
env_basisu.Prepend(CPPPATH=["#thirdparty/zstd"])
|
||||
|
||||
env_basisu.Prepend(CPPPATH=["#thirdparty/tinyexr"])
|
||||
|
||||
if env.dev_build:
|
||||
env_basisu.Append(CPPDEFINES=[("BASISU_DEVEL_MESSAGES", 1), ("BASISD_ENABLE_DEBUG_FLAGS", 1)])
|
||||
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
#include "image_compress_basisu.h"
|
||||
|
||||
#include "core/os/os.h"
|
||||
#include "core/string/print_string.h"
|
||||
#include "servers/rendering_server.h"
|
||||
|
||||
#include <transcoder/basisu_transcoder.h>
|
||||
@ -46,9 +48,48 @@ void basis_universal_init() {
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
template <typename T>
|
||||
inline void _basisu_pad_mipmap(const uint8_t *p_image_mip_data, Vector<uint8_t> &r_mip_data_padded, int p_next_width, int p_next_height, int p_width, int p_height, int64_t p_size) {
|
||||
// Source mip's data interpreted as 32-bit RGBA blocks to help with copying pixel data.
|
||||
const T *mip_src_data = reinterpret_cast<const T *>(p_image_mip_data);
|
||||
|
||||
// Reserve space in the padded buffer.
|
||||
r_mip_data_padded.resize(p_next_width * p_next_height * sizeof(T));
|
||||
T *data_padded_ptr = reinterpret_cast<T *>(r_mip_data_padded.ptrw());
|
||||
|
||||
// Pad mipmap to the nearest block by smearing.
|
||||
int x = 0, y = 0;
|
||||
for (y = 0; y < p_height; y++) {
|
||||
for (x = 0; x < p_width; x++) {
|
||||
data_padded_ptr[p_next_width * y + x] = mip_src_data[p_width * y + x];
|
||||
}
|
||||
|
||||
// First, smear in x.
|
||||
for (; x < p_next_width; x++) {
|
||||
data_padded_ptr[p_next_width * y + x] = data_padded_ptr[p_next_width * y + x - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// Then, smear in y.
|
||||
for (; y < p_next_height; y++) {
|
||||
for (x = 0; x < p_next_width; x++) {
|
||||
data_padded_ptr[p_next_width * y + x] = data_padded_ptr[p_next_width * y + x - p_next_width];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedChannels p_channels) {
|
||||
uint64_t start_time = OS::get_singleton()->get_ticks_msec();
|
||||
|
||||
Ref<Image> image = p_image->duplicate();
|
||||
bool is_hdr = false;
|
||||
|
||||
if (image->get_format() <= Image::FORMAT_RGB565) {
|
||||
image->convert(Image::FORMAT_RGBA8);
|
||||
} else if (image->get_format() <= Image::FORMAT_RGBE9995) {
|
||||
image->convert(Image::FORMAT_RGBAF);
|
||||
is_hdr = true;
|
||||
}
|
||||
|
||||
basisu::basis_compressor_params params;
|
||||
|
||||
@ -74,7 +115,14 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
|
||||
basisu::job_pool job_pool(OS::get_singleton()->get_processor_count());
|
||||
params.m_pJob_pool = &job_pool;
|
||||
|
||||
BasisDecompressFormat decompress_format = BASIS_DECOMPRESS_RG;
|
||||
BasisDecompressFormat decompress_format = BASIS_DECOMPRESS_MAX;
|
||||
|
||||
if (is_hdr) {
|
||||
decompress_format = BASIS_DECOMPRESS_HDR_RGB;
|
||||
params.m_hdr = true;
|
||||
params.m_uastc_hdr_options.set_quality_level(0);
|
||||
|
||||
} else {
|
||||
switch (p_channels) {
|
||||
case Image::USED_CHANNELS_L: {
|
||||
decompress_format = BASIS_DECOMPRESS_RGB;
|
||||
@ -99,6 +147,9 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
|
||||
decompress_format = BASIS_DECOMPRESS_RGBA;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V(decompress_format == BASIS_DECOMPRESS_MAX, Vector<uint8_t>());
|
||||
|
||||
// Copy the source image data with mipmaps into BasisU.
|
||||
{
|
||||
@ -113,9 +164,10 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
|
||||
|
||||
Vector<uint8_t> image_data = image->get_data();
|
||||
basisu::vector<basisu::image> basisu_mipmaps;
|
||||
basisu::vector<basisu::imagef> basisu_mipmaps_hdr;
|
||||
|
||||
// Buffer for storing padded mipmap data.
|
||||
Vector<uint32_t> mip_data_padded;
|
||||
Vector<uint8_t> mip_data_padded;
|
||||
|
||||
for (int32_t i = 0; i <= image->get_mipmap_count(); i++) {
|
||||
int64_t ofs, size;
|
||||
@ -126,31 +178,10 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
|
||||
|
||||
// Pad the mipmap's data if its resolution isn't divisible by 4.
|
||||
if (image->has_mipmaps() && !is_res_div_4 && (width > 2 && height > 2) && (width != next_width || height != next_height)) {
|
||||
// Source mip's data interpreted as 32-bit RGBA blocks to help with copying pixel data.
|
||||
const uint32_t *mip_src_data = reinterpret_cast<const uint32_t *>(image_mip_data);
|
||||
|
||||
// Reserve space in the padded buffer.
|
||||
mip_data_padded.resize(next_width * next_height);
|
||||
uint32_t *data_padded_ptr = mip_data_padded.ptrw();
|
||||
|
||||
// Pad mipmap to the nearest block by smearing.
|
||||
int x = 0, y = 0;
|
||||
for (y = 0; y < height; y++) {
|
||||
for (x = 0; x < width; x++) {
|
||||
data_padded_ptr[next_width * y + x] = mip_src_data[width * y + x];
|
||||
}
|
||||
|
||||
// First, smear in x.
|
||||
for (; x < next_width; x++) {
|
||||
data_padded_ptr[next_width * y + x] = data_padded_ptr[next_width * y + x - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// Then, smear in y.
|
||||
for (; y < next_height; y++) {
|
||||
for (x = 0; x < next_width; x++) {
|
||||
data_padded_ptr[next_width * y + x] = data_padded_ptr[next_width * y + x - next_width];
|
||||
}
|
||||
if (is_hdr) {
|
||||
_basisu_pad_mipmap<BasisRGBAF>(image_mip_data, mip_data_padded, next_width, next_height, width, height, size);
|
||||
} else {
|
||||
_basisu_pad_mipmap<uint32_t>(image_mip_data, mip_data_padded, next_width, next_height, width, height, size);
|
||||
}
|
||||
|
||||
// Override the image_mip_data pointer with our temporary Vector.
|
||||
@ -159,7 +190,7 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
|
||||
// Override the mipmap's properties.
|
||||
width = next_width;
|
||||
height = next_height;
|
||||
size = mip_data_padded.size() * 4;
|
||||
size = mip_data_padded.size();
|
||||
}
|
||||
|
||||
// Get the next mipmap's resolution.
|
||||
@ -167,6 +198,17 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
|
||||
next_height /= 2;
|
||||
|
||||
// Copy the source mipmap's data to a BasisU image.
|
||||
if (is_hdr) {
|
||||
basisu::imagef basisu_image(width, height);
|
||||
memcpy(reinterpret_cast<uint8_t *>(basisu_image.get_ptr()), image_mip_data, size);
|
||||
|
||||
if (i == 0) {
|
||||
params.m_source_images_hdr.push_back(basisu_image);
|
||||
} else {
|
||||
basisu_mipmaps_hdr.push_back(basisu_image);
|
||||
}
|
||||
|
||||
} else {
|
||||
basisu::image basisu_image(width, height);
|
||||
memcpy(basisu_image.get_ptr(), image_mip_data, size);
|
||||
|
||||
@ -176,35 +218,41 @@ Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedCha
|
||||
basisu_mipmaps.push_back(basisu_image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_hdr) {
|
||||
params.m_source_mipmap_images_hdr.push_back(basisu_mipmaps_hdr);
|
||||
} else {
|
||||
params.m_source_mipmap_images.push_back(basisu_mipmaps);
|
||||
}
|
||||
}
|
||||
|
||||
// Encode the image data.
|
||||
Vector<uint8_t> basisu_data;
|
||||
|
||||
basisu::basis_compressor compressor;
|
||||
compressor.init(params);
|
||||
|
||||
int basisu_err = compressor.process();
|
||||
ERR_FAIL_COND_V(basisu_err != basisu::basis_compressor::cECSuccess, basisu_data);
|
||||
ERR_FAIL_COND_V(basisu_err != basisu::basis_compressor::cECSuccess, Vector<uint8_t>());
|
||||
|
||||
const basisu::uint8_vec &basisu_out = compressor.get_output_basis_file();
|
||||
basisu_data.resize(basisu_out.size() + 4);
|
||||
const basisu::uint8_vec &basisu_encoded = compressor.get_output_basis_file();
|
||||
|
||||
// Copy the encoded data to the buffer.
|
||||
{
|
||||
uint8_t *wb = basisu_data.ptrw();
|
||||
*(uint32_t *)wb = decompress_format;
|
||||
Vector<uint8_t> basisu_data;
|
||||
basisu_data.resize(basisu_encoded.size() + 4);
|
||||
uint8_t *basisu_data_ptr = basisu_data.ptrw();
|
||||
|
||||
memcpy(wb + 4, basisu_out.get_ptr(), basisu_out.size());
|
||||
}
|
||||
// Copy the encoded BasisU data into the output buffer.
|
||||
*(uint32_t *)basisu_data_ptr = decompress_format;
|
||||
memcpy(basisu_data_ptr + 4, basisu_encoded.get_ptr(), basisu_encoded.size());
|
||||
|
||||
print_verbose(vformat("BasisU: Encoding a %dx%d image with %d mipmaps took %d ms.", p_image->get_width(), p_image->get_height(), p_image->get_mipmap_count(), OS::get_singleton()->get_ticks_msec() - start_time));
|
||||
|
||||
return basisu_data;
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
|
||||
uint64_t start_time = OS::get_singleton()->get_ticks_msec();
|
||||
|
||||
Ref<Image> image;
|
||||
ERR_FAIL_NULL_V_MSG(p_data, image, "Cannot unpack invalid BasisUniversal data.");
|
||||
|
||||
@ -320,6 +368,23 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
|
||||
}
|
||||
|
||||
} break;
|
||||
case BASIS_DECOMPRESS_HDR_RGB: {
|
||||
if (bptc_supported) {
|
||||
basisu_format = basist::transcoder_texture_format::cTFBC6H;
|
||||
image_format = Image::FORMAT_BPTC_RGBFU;
|
||||
} else if (astc_supported) {
|
||||
basisu_format = basist::transcoder_texture_format::cTFASTC_HDR_4x4_RGBA;
|
||||
image_format = Image::FORMAT_ASTC_4x4_HDR;
|
||||
} else {
|
||||
// No supported VRAM compression formats, decompress.
|
||||
basisu_format = basist::transcoder_texture_format::cTFRGB_9E5;
|
||||
image_format = Image::FORMAT_RGBE9995;
|
||||
}
|
||||
|
||||
} break;
|
||||
default: {
|
||||
ERR_FAIL_V(image);
|
||||
} break;
|
||||
}
|
||||
|
||||
src_ptr += 4;
|
||||
@ -371,6 +436,9 @@ Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size) {
|
||||
}
|
||||
}
|
||||
|
||||
print_verbose(vformat("BasisU: Transcoding a %dx%d image with %d mipmaps into %s took %d ms.",
|
||||
image->get_width(), image->get_height(), image->get_mipmap_count(), Image::get_format_name(image_format), OS::get_singleton()->get_ticks_msec() - start_time));
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
|
@ -39,11 +39,20 @@ enum BasisDecompressFormat {
|
||||
BASIS_DECOMPRESS_RGBA,
|
||||
BASIS_DECOMPRESS_RG_AS_RA,
|
||||
BASIS_DECOMPRESS_R,
|
||||
BASIS_DECOMPRESS_HDR_RGB,
|
||||
BASIS_DECOMPRESS_MAX
|
||||
};
|
||||
|
||||
void basis_universal_init();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
struct BasisRGBAF {
|
||||
uint32_t r;
|
||||
uint32_t g;
|
||||
uint32_t b;
|
||||
uint32_t a;
|
||||
};
|
||||
|
||||
Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedChannels p_channels);
|
||||
#endif
|
||||
|
||||
|
5
thirdparty/README.md
vendored
5
thirdparty/README.md
vendored
@ -59,12 +59,13 @@ Files extracted from upstream source:
|
||||
## basis_universal
|
||||
|
||||
- Upstream: https://github.com/BinomialLLC/basis_universal
|
||||
- Version: 1.16.4 (900e40fb5d2502927360fe2f31762bdbb624455f, 2023)
|
||||
- Version: 1.50.0 (051ad6d8a64bb95a79e8601c317055fd1782ad3e, 2024)
|
||||
- License: Apache 2.0
|
||||
|
||||
Files extracted from upstream source:
|
||||
|
||||
- `encoder/` and `transcoder/` folders, minus `jpgd.{cpp,h}`
|
||||
- `encoder/` and `transcoder/` folders, with the following files removed from `encoder`:
|
||||
`jpgd.{cpp,h}`, `3rdparty/{qoi.h,tinydds.h,tinyexr.cpp,tinyexr.h}`
|
||||
- `LICENSE`
|
||||
|
||||
Applied upstream PR https://github.com/BinomialLLC/basis_universal/pull/344 to
|
||||
|
2052
thirdparty/basis_universal/encoder/3rdparty/android_astc_decomp.cpp
vendored
Normal file
2052
thirdparty/basis_universal/encoder/3rdparty/android_astc_decomp.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
45
thirdparty/basis_universal/encoder/3rdparty/android_astc_decomp.h
vendored
Normal file
45
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
thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.cpp
vendored
Normal file
3310
thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
224
thirdparty/basis_universal/encoder/basisu_astc_hdr_enc.h
vendored
Normal file
224
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.
|
||||
|
1602
thirdparty/basis_universal/encoder/basisu_comp.cpp
vendored
1602
thirdparty/basis_universal/encoder/basisu_comp.cpp
vendored
File diff suppressed because it is too large
Load Diff
104
thirdparty/basis_universal/encoder/basisu_comp.h
vendored
104
thirdparty/basis_universal/encoder/basisu_comp.h
vendored
@ -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;
|
||||
|
||||
// Filename of the output basis file
|
||||
basisu::vector< basisu::vector<imagef> > m_source_mipmap_images_hdr;
|
||||
|
||||
// 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.
|
||||
|
1628
thirdparty/basis_universal/encoder/basisu_enc.cpp
vendored
1628
thirdparty/basis_universal/encoder/basisu_enc.cpp
vendored
File diff suppressed because it is too large
Load Diff
599
thirdparty/basis_universal/encoder/basisu_enc.h
vendored
599
thirdparty/basis_universal/encoder/basisu_enc.h
vendored
@ -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)
|
||||
@ -131,6 +144,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
|
||||
|
||||
inline uint32_t bitmix32c(uint32_t v)
|
||||
@ -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)
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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]; }
|
||||
|
||||
@ -3214,18 +3289,127 @@ 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()
|
||||
{
|
||||
@ -3451,6 +3704,326 @@ 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 };
|
||||
@ -373,6 +380,7 @@ namespace basisu
|
||||
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;
|
||||
@ -1086,12 +1350,15 @@ namespace basisu
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// 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());
|
||||
@ -1253,6 +1590,47 @@ 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)
|
||||
@ -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;
|
||||
@ -1534,6 +1930,7 @@ namespace basisu
|
||||
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++)
|
||||
{
|
||||
@ -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,7 +2018,7 @@ namespace basisu
|
||||
}
|
||||
else if (extension == "dds")
|
||||
{
|
||||
// TODO
|
||||
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;
|
||||
|
||||
void override_dimensions(uint32_t w, uint32_t h)
|
||||
// Unpacks HDR textures only.
|
||||
bool unpack_hdr(imagef& img) const;
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
// 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);
|
||||
|
||||
bool write_compressed_texture_file(const char *pFilename, const gpu_image &g);
|
||||
// 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.
|
||||
|
28
thirdparty/basis_universal/encoder/cppspmd_sse.h
vendored
28
thirdparty/basis_universal/encoder/cppspmd_sse.h
vendored
@ -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;
|
||||
|
23
thirdparty/basis_universal/patches/external-tinyexr.patch
vendored
Normal file
23
thirdparty/basis_universal/patches/external-tinyexr.patch
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
diff --git a/thirdparty/basis_universal/encoder/basisu_enc.cpp b/thirdparty/basis_universal/encoder/basisu_enc.cpp
|
||||
index 6c0ac0ad370..2bf486a0287 100644
|
||||
--- a/thirdparty/basis_universal/encoder/basisu_enc.cpp
|
||||
+++ b/thirdparty/basis_universal/encoder/basisu_enc.cpp
|
||||
@@ -27,7 +27,7 @@
|
||||
#ifndef TINYEXR_USE_ZFP
|
||||
#define TINYEXR_USE_ZFP (1)
|
||||
#endif
|
||||
-#include "3rdparty/tinyexr.h"
|
||||
+#include <tinyexr.h>
|
||||
|
||||
#ifndef MINIZ_HEADER_FILE_ONLY
|
||||
#define MINIZ_HEADER_FILE_ONLY
|
||||
@@ -3257,7 +3257,8 @@ namespace basisu
|
||||
float* out_rgba = nullptr;
|
||||
const char* err = nullptr;
|
||||
|
||||
- int status = LoadEXRWithLayer(&out_rgba, &width, &height, pFilename, nullptr, &err, &n_chans);
|
||||
+ int status = LoadEXRWithLayer(&out_rgba, &width, &height, pFilename, nullptr, &err);
|
||||
+ n_chans = 4;
|
||||
if (status != 0)
|
||||
{
|
||||
error_printf("Failed loading .EXR image \"%s\"! (TinyEXR error: %s)\n", pFilename, err ? err : "?");
|
446
thirdparty/basis_universal/patches/remove-tinydds-qoi.patch
vendored
Normal file
446
thirdparty/basis_universal/patches/remove-tinydds-qoi.patch
vendored
Normal file
@ -0,0 +1,446 @@
|
||||
diff --git a/thirdparty/basis_universal/encoder/basisu_enc.cpp b/thirdparty/basis_universal/encoder/basisu_enc.cpp
|
||||
index 2bf486a0287..fff98e83014 100644
|
||||
--- a/thirdparty/basis_universal/encoder/basisu_enc.cpp
|
||||
+++ b/thirdparty/basis_universal/encoder/basisu_enc.cpp
|
||||
@@ -37,9 +37,6 @@
|
||||
#endif
|
||||
#include "basisu_miniz.h"
|
||||
|
||||
-#define QOI_IMPLEMENTATION
|
||||
-#include "3rdparty/qoi.h"
|
||||
-
|
||||
#if defined(_WIN32)
|
||||
// For QueryPerformanceCounter/QueryPerformanceFrequency
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
@@ -408,16 +405,7 @@ namespace basisu
|
||||
|
||||
bool load_qoi(const char* pFilename, image& img)
|
||||
{
|
||||
- qoi_desc desc;
|
||||
- clear_obj(desc);
|
||||
-
|
||||
- void* p = qoi_read(pFilename, &desc, 4);
|
||||
- if (!p)
|
||||
- return false;
|
||||
-
|
||||
- img.grant_ownership(static_cast<color_rgba *>(p), desc.width, desc.height);
|
||||
-
|
||||
- return true;
|
||||
+ return false;
|
||||
}
|
||||
|
||||
bool load_png(const uint8_t *pBuf, size_t buf_size, image &img, const char *pFilename)
|
||||
diff --git a/thirdparty/basis_universal/encoder/basisu_gpu_texture.cpp b/thirdparty/basis_universal/encoder/basisu_gpu_texture.cpp
|
||||
index 000869a5337..342446b8fd4 100644
|
||||
--- a/thirdparty/basis_universal/encoder/basisu_gpu_texture.cpp
|
||||
+++ b/thirdparty/basis_universal/encoder/basisu_gpu_texture.cpp
|
||||
@@ -19,9 +19,6 @@
|
||||
#include "basisu_bc7enc.h"
|
||||
#include "../transcoder/basisu_astc_hdr_core.h"
|
||||
|
||||
-#define TINYDDS_IMPLEMENTATION
|
||||
-#include "3rdparty/tinydds.h"
|
||||
-
|
||||
namespace basisu
|
||||
{
|
||||
//------------------------------------------------------------------------------------------------
|
||||
@@ -1979,208 +1976,8 @@ namespace basisu
|
||||
// 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)
|
||||
- {
|
||||
- if (!gpu_images.size())
|
||||
- {
|
||||
- assert(0);
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- // Sanity check the input
|
||||
- uint32_t slices = 1;
|
||||
- if (cubemap_flag)
|
||||
- {
|
||||
- if ((gpu_images.size() % 6) != 0)
|
||||
- {
|
||||
- assert(0);
|
||||
- return false;
|
||||
- }
|
||||
- slices = gpu_images.size() / 6;
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- slices = gpu_images.size();
|
||||
- }
|
||||
-
|
||||
- uint32_t width = 0, height = 0, total_levels = 0;
|
||||
- basisu::texture_format fmt = texture_format::cInvalidTextureFormat;
|
||||
-
|
||||
- // Sanity check the input for consistent # of dimensions and mip levels
|
||||
- for (uint32_t array_index = 0; array_index < gpu_images.size(); array_index++)
|
||||
- {
|
||||
- const gpu_image_vec& levels = gpu_images[array_index];
|
||||
-
|
||||
- if (!levels.size())
|
||||
- {
|
||||
- // Empty mip chain
|
||||
- assert(0);
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- if (!array_index)
|
||||
- {
|
||||
- width = levels[0].get_pixel_width();
|
||||
- height = levels[0].get_pixel_height();
|
||||
- total_levels = (uint32_t)levels.size();
|
||||
- fmt = levels[0].get_format();
|
||||
- }
|
||||
- else
|
||||
- {
|
||||
- if ((width != levels[0].get_pixel_width()) ||
|
||||
- (height != levels[0].get_pixel_height()) ||
|
||||
- (total_levels != levels.size()))
|
||||
- {
|
||||
- // All cubemap/texture array faces must be the same dimension
|
||||
- assert(0);
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- for (uint32_t level_index = 0; level_index < levels.size(); level_index++)
|
||||
- {
|
||||
- if (level_index)
|
||||
- {
|
||||
- if ((levels[level_index].get_pixel_width() != maximum<uint32_t>(1, levels[0].get_pixel_width() >> level_index)) ||
|
||||
- (levels[level_index].get_pixel_height() != maximum<uint32_t>(1, levels[0].get_pixel_height() >> level_index)))
|
||||
- {
|
||||
- // Malformed mipmap chain
|
||||
- assert(0);
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- if (fmt != levels[level_index].get_format())
|
||||
- {
|
||||
- // All input textures must use the same GPU format
|
||||
- assert(0);
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- // No mipmap levels
|
||||
- if (!total_levels)
|
||||
- {
|
||||
- assert(0);
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- // Create the DDS mipmap level data
|
||||
- uint8_vec mipmaps[32];
|
||||
-
|
||||
- // See https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dds-file-layout-for-cubic-environment-maps
|
||||
- // DDS cubemap organization is cubemap face 0 followed by all mips, then cubemap face 1 followed by all mips, etc.
|
||||
- // Unfortunately tinydds.h's writer doesn't handle this case correctly, so we work around it here.
|
||||
- // This also applies with 2D texture arrays, too. RenderDoc and ddsview (DirectXTex) views each type (cubemap array and 2D texture array) correctly.
|
||||
- // Also see "Using Texture Arrays in Direct3D 10/11":
|
||||
- // https://learn.microsoft.com/en-us/windows/win32/direct3ddds/dx-graphics-dds-pguide
|
||||
- for (uint32_t array_index = 0; array_index < gpu_images.size(); array_index++)
|
||||
- {
|
||||
- const gpu_image_vec& levels = gpu_images[array_index];
|
||||
-
|
||||
- for (uint32_t level_index = 0; level_index < levels.size(); level_index++)
|
||||
- {
|
||||
- append_vector(mipmaps[0], (uint8_t*)levels[level_index].get_ptr(), levels[level_index].get_size_in_bytes());
|
||||
-
|
||||
- } // level_index
|
||||
- } // array_index
|
||||
-
|
||||
-#if 0
|
||||
- // This organization, required by tinydds.h's API, is wrong.
|
||||
- {
|
||||
- for (uint32_t array_index = 0; array_index < gpu_images.size(); array_index++)
|
||||
- {
|
||||
- const gpu_image_vec& levels = gpu_images[array_index];
|
||||
-
|
||||
- for (uint32_t level_index = 0; level_index < levels.size(); level_index++)
|
||||
- {
|
||||
- append_vector(mipmaps[level_index], (uint8_t*)levels[level_index].get_ptr(), levels[level_index].get_size_in_bytes());
|
||||
-
|
||||
- } // level_index
|
||||
- } // array_index
|
||||
- }
|
||||
-#endif
|
||||
-
|
||||
- // Write DDS file using tinydds
|
||||
- TinyDDS_WriteCallbacks cbs;
|
||||
- cbs.error = [](void* user, char const* msg) { BASISU_NOTE_UNUSED(user); fprintf(stderr, "tinydds: %s\n", msg); };
|
||||
- cbs.alloc = [](void* user, size_t size) -> void* { BASISU_NOTE_UNUSED(user); return malloc(size); };
|
||||
- cbs.free = [](void* user, void* memory) { BASISU_NOTE_UNUSED(user); free(memory); };
|
||||
- cbs.write = [](void* user, void const* buffer, size_t byteCount) { BASISU_NOTE_UNUSED(user); uint8_vec* pVec = (uint8_vec*)user; append_vector(*pVec, (const uint8_t*)buffer, byteCount); };
|
||||
-
|
||||
- uint32_t mipmap_sizes[32];
|
||||
- const void* mipmap_ptrs[32];
|
||||
-
|
||||
- clear_obj(mipmap_sizes);
|
||||
- clear_obj(mipmap_ptrs);
|
||||
-
|
||||
- assert(total_levels < 32);
|
||||
- for (uint32_t i = 0; i < total_levels; i++)
|
||||
- {
|
||||
- mipmap_sizes[i] = mipmaps[i].size_in_bytes();
|
||||
- mipmap_ptrs[i] = mipmaps[i].get_ptr();
|
||||
- }
|
||||
-
|
||||
- // Select tinydds texture format
|
||||
- uint32_t tinydds_fmt = 0;
|
||||
-
|
||||
- switch (fmt)
|
||||
- {
|
||||
- case texture_format::cBC1_NV:
|
||||
- case texture_format::cBC1_AMD:
|
||||
- case texture_format::cBC1:
|
||||
- tinydds_fmt = use_srgb_format ? TDDS_BC1_RGBA_SRGB_BLOCK : TDDS_BC1_RGBA_UNORM_BLOCK;
|
||||
- break;
|
||||
- case texture_format::cBC3:
|
||||
- tinydds_fmt = use_srgb_format ? TDDS_BC3_SRGB_BLOCK : TDDS_BC3_UNORM_BLOCK;
|
||||
- break;
|
||||
- case texture_format::cBC4:
|
||||
- tinydds_fmt = TDDS_BC4_UNORM_BLOCK;
|
||||
- break;
|
||||
- case texture_format::cBC5:
|
||||
- tinydds_fmt = TDDS_BC5_UNORM_BLOCK;
|
||||
- break;
|
||||
- case texture_format::cBC6HSigned:
|
||||
- tinydds_fmt = TDDS_BC6H_SFLOAT_BLOCK;
|
||||
- break;
|
||||
- case texture_format::cBC6HUnsigned:
|
||||
- tinydds_fmt = TDDS_BC6H_UFLOAT_BLOCK;
|
||||
- break;
|
||||
- case texture_format::cBC7:
|
||||
- tinydds_fmt = use_srgb_format ? TDDS_BC7_SRGB_BLOCK : TDDS_BC7_UNORM_BLOCK;
|
||||
- break;
|
||||
- default:
|
||||
- {
|
||||
- fprintf(stderr, "Warning: Unsupported format in write_dds_file().\n");
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- // DirectXTex's DDSView doesn't handle odd sizes textures correctly. RenderDoc loads them fine, however.
|
||||
- // Trying to work around this here results in invalid mipmaps.
|
||||
- //width = (width + 3) & ~3;
|
||||
- //height = (height + 3) & ~3;
|
||||
-
|
||||
- bool status = TinyDDS_WriteImage(&cbs,
|
||||
- &dds_data,
|
||||
- width,
|
||||
- height,
|
||||
- 1,
|
||||
- slices,
|
||||
- total_levels,
|
||||
- (TinyDDS_Format)tinydds_fmt,
|
||||
- cubemap_flag,
|
||||
- true,
|
||||
- mipmap_sizes,
|
||||
- mipmap_ptrs);
|
||||
-
|
||||
- if (!status)
|
||||
- {
|
||||
- fprintf(stderr, "write_dds_file: Failed creating DDS file\n");
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- return true;
|
||||
+ {
|
||||
+ return false;
|
||||
}
|
||||
|
||||
bool write_dds_file(const char* pFilename, const basisu::vector<gpu_image_vec>& gpu_images, bool cubemap_flag, bool use_srgb_format)
|
||||
@@ -2201,188 +1998,6 @@ namespace basisu
|
||||
|
||||
bool read_uncompressed_dds_file(const char* pFilename, basisu::vector<image> &ldr_mips, basisu::vector<imagef>& hdr_mips)
|
||||
{
|
||||
- const uint32_t MAX_IMAGE_DIM = 16384;
|
||||
-
|
||||
- TinyDDS_Callbacks cbs;
|
||||
-
|
||||
- cbs.errorFn = [](void* user, char const* msg) { BASISU_NOTE_UNUSED(user); fprintf(stderr, "tinydds: %s\n", msg); };
|
||||
- cbs.allocFn = [](void* user, size_t size) -> void* { BASISU_NOTE_UNUSED(user); return malloc(size); };
|
||||
- cbs.freeFn = [](void* user, void* memory) { BASISU_NOTE_UNUSED(user); free(memory); };
|
||||
- cbs.readFn = [](void* user, void* buffer, size_t byteCount) -> size_t { return (size_t)fread(buffer, 1, byteCount, (FILE*)user); };
|
||||
-
|
||||
-#ifdef _MSC_VER
|
||||
- cbs.seekFn = [](void* user, int64_t ofs) -> bool { return _fseeki64((FILE*)user, ofs, SEEK_SET) == 0; };
|
||||
- cbs.tellFn = [](void* user) -> int64_t { return _ftelli64((FILE*)user); };
|
||||
-#else
|
||||
- cbs.seekFn = [](void* user, int64_t ofs) -> bool { return fseek((FILE*)user, (long)ofs, SEEK_SET) == 0; };
|
||||
- cbs.tellFn = [](void* user) -> int64_t { return (int64_t)ftell((FILE*)user); };
|
||||
-#endif
|
||||
-
|
||||
- FILE* pFile = fopen_safe(pFilename, "rb");
|
||||
- if (!pFile)
|
||||
- {
|
||||
- error_printf("Can't open .DDS file \"%s\"\n", pFilename);
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- // These are the formats AMD Compressonator supports in its UI.
|
||||
- enum dds_fmt
|
||||
- {
|
||||
- cRGBA32,
|
||||
- cRGBA_HALF,
|
||||
- cRGBA_FLOAT
|
||||
- };
|
||||
-
|
||||
- bool status = false;
|
||||
- dds_fmt fmt = cRGBA32;
|
||||
- uint32_t width = 0, height = 0;
|
||||
- bool hdr_flag = false;
|
||||
- TinyDDS_Format tfmt = TDDS_UNDEFINED;
|
||||
-
|
||||
- TinyDDS_ContextHandle ctx = TinyDDS_CreateContext(&cbs, pFile);
|
||||
- if (!ctx)
|
||||
- goto failure;
|
||||
-
|
||||
- status = TinyDDS_ReadHeader(ctx);
|
||||
- if (!status)
|
||||
- {
|
||||
- error_printf("Failed parsing DDS header in file \"%s\"\n", pFilename);
|
||||
- goto failure;
|
||||
- }
|
||||
-
|
||||
- if ((!TinyDDS_Is2D(ctx)) || (TinyDDS_ArraySlices(ctx) > 1) || (TinyDDS_IsCubemap(ctx)))
|
||||
- {
|
||||
- error_printf("Unsupported DDS texture type in file \"%s\"\n", pFilename);
|
||||
- goto failure;
|
||||
- }
|
||||
-
|
||||
- width = TinyDDS_Width(ctx);
|
||||
- height = TinyDDS_Height(ctx);
|
||||
-
|
||||
- if (!width || !height)
|
||||
- {
|
||||
- error_printf("DDS texture dimensions invalid in file \"%s\"\n", pFilename);
|
||||
- goto failure;
|
||||
- }
|
||||
-
|
||||
- if ((width > MAX_IMAGE_DIM) || (height > MAX_IMAGE_DIM))
|
||||
- {
|
||||
- error_printf("DDS texture dimensions too large in file \"%s\"\n", pFilename);
|
||||
- goto failure;
|
||||
- }
|
||||
-
|
||||
- tfmt = TinyDDS_GetFormat(ctx);
|
||||
- switch (tfmt)
|
||||
- {
|
||||
- case TDDS_R8G8B8A8_SRGB:
|
||||
- case TDDS_R8G8B8A8_UNORM:
|
||||
- case TDDS_B8G8R8A8_SRGB:
|
||||
- case TDDS_B8G8R8A8_UNORM:
|
||||
- fmt = cRGBA32;
|
||||
- break;
|
||||
- case TDDS_R16G16B16A16_SFLOAT:
|
||||
- fmt = cRGBA_HALF;
|
||||
- hdr_flag = true;
|
||||
- break;
|
||||
- case TDDS_R32G32B32A32_SFLOAT:
|
||||
- fmt = cRGBA_FLOAT;
|
||||
- hdr_flag = true;
|
||||
- break;
|
||||
- default:
|
||||
- error_printf("File \"%s\" has an unsupported DDS texture format (only supports RGBA/BGRA 32bpp, RGBA HALF float, or RGBA FLOAT)\n", pFilename);
|
||||
- goto failure;
|
||||
- }
|
||||
-
|
||||
- if (hdr_flag)
|
||||
- hdr_mips.resize(TinyDDS_NumberOfMipmaps(ctx));
|
||||
- else
|
||||
- ldr_mips.resize(TinyDDS_NumberOfMipmaps(ctx));
|
||||
-
|
||||
- for (uint32_t level = 0; level < TinyDDS_NumberOfMipmaps(ctx); level++)
|
||||
- {
|
||||
- const uint32_t level_width = TinyDDS_MipMapReduce(width, level);
|
||||
- const uint32_t level_height = TinyDDS_MipMapReduce(height, level);
|
||||
- const uint32_t total_level_texels = level_width * level_height;
|
||||
-
|
||||
- const void* pImage = TinyDDS_ImageRawData(ctx, level);
|
||||
- const uint32_t image_size = TinyDDS_ImageSize(ctx, level);
|
||||
-
|
||||
- if (fmt == cRGBA32)
|
||||
- {
|
||||
- ldr_mips[level].resize(level_width, level_height);
|
||||
-
|
||||
- if ((ldr_mips[level].get_total_pixels() * sizeof(uint32_t) != image_size))
|
||||
- {
|
||||
- assert(0);
|
||||
- goto failure;
|
||||
- }
|
||||
-
|
||||
- memcpy(ldr_mips[level].get_ptr(), pImage, image_size);
|
||||
-
|
||||
- if ((tfmt == TDDS_B8G8R8A8_SRGB) || (tfmt == TDDS_B8G8R8A8_UNORM))
|
||||
- {
|
||||
- // Swap R and B components.
|
||||
- uint32_t *pTexels = (uint32_t *)ldr_mips[level].get_ptr();
|
||||
- for (uint32_t i = 0; i < total_level_texels; i++)
|
||||
- {
|
||||
- const uint32_t v = pTexels[i];
|
||||
- const uint32_t r = (v >> 16) & 0xFF;
|
||||
- const uint32_t b = v & 0xFF;
|
||||
- pTexels[i] = r | (b << 16) | (v & 0xFF00FF00);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- else if (fmt == cRGBA_FLOAT)
|
||||
- {
|
||||
- hdr_mips[level].resize(level_width, level_height);
|
||||
-
|
||||
- if ((hdr_mips[level].get_total_pixels() * sizeof(float) * 4 != image_size))
|
||||
- {
|
||||
- assert(0);
|
||||
- goto failure;
|
||||
- }
|
||||
-
|
||||
- memcpy(hdr_mips[level].get_ptr(), pImage, image_size);
|
||||
- }
|
||||
- else if (fmt == cRGBA_HALF)
|
||||
- {
|
||||
- hdr_mips[level].resize(level_width, level_height);
|
||||
-
|
||||
- if ((hdr_mips[level].get_total_pixels() * sizeof(basist::half_float) * 4 != image_size))
|
||||
- {
|
||||
- assert(0);
|
||||
- goto failure;
|
||||
- }
|
||||
-
|
||||
- // Unpack half to float.
|
||||
- const basist::half_float* pSrc_comps = static_cast<const basist::half_float*>(pImage);
|
||||
- vec4F* pDst_texels = hdr_mips[level].get_ptr();
|
||||
-
|
||||
- for (uint32_t i = 0; i < total_level_texels; i++)
|
||||
- {
|
||||
- (*pDst_texels)[0] = basist::half_to_float(pSrc_comps[0]);
|
||||
- (*pDst_texels)[1] = basist::half_to_float(pSrc_comps[1]);
|
||||
- (*pDst_texels)[2] = basist::half_to_float(pSrc_comps[2]);
|
||||
- (*pDst_texels)[3] = basist::half_to_float(pSrc_comps[3]);
|
||||
-
|
||||
- pSrc_comps += 4;
|
||||
- pDst_texels++;
|
||||
- } // y
|
||||
- }
|
||||
- } // level
|
||||
-
|
||||
- TinyDDS_DestroyContext(ctx);
|
||||
- fclose(pFile);
|
||||
-
|
||||
- return true;
|
||||
-
|
||||
- failure:
|
||||
- if (ctx)
|
||||
- TinyDDS_DestroyContext(ctx);
|
||||
-
|
||||
- if (pFile)
|
||||
- fclose(pFile);
|
||||
-
|
||||
return false;
|
||||
}
|
||||
|
101
thirdparty/basis_universal/transcoder/basisu.h
vendored
101
thirdparty/basis_universal/transcoder/basisu.h
vendored
@ -1,5 +1,5 @@
|
||||
// basisu.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -117,13 +117,26 @@ namespace basisu
|
||||
typedef basisu::vector<uint64_t> uint64_vec;
|
||||
typedef basisu::vector<int> int_vec;
|
||||
typedef basisu::vector<bool> bool_vec;
|
||||
typedef basisu::vector<float> float_vec;
|
||||
|
||||
void enable_debug_printf(bool enabled);
|
||||
void debug_printf(const char *pFmt, ...);
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <typename T> inline void clear_obj(T& obj) { memset(&obj, 0, sizeof(obj)); }
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
|
||||
template <typename T0, typename T1> inline T0 lerp(T0 a, T0 b, T1 c) { return a + (b - a) * c; }
|
||||
|
||||
template <typename S> inline S maximum(S a, S b) { return (a > b) ? a : b; }
|
||||
@ -162,10 +175,45 @@ namespace basisu
|
||||
template<typename T> inline T open_range_check(T v, T minv, T maxv) { assert(v >= minv && v < maxv); BASISU_NOTE_UNUSED(minv); BASISU_NOTE_UNUSED(maxv); return v; }
|
||||
template<typename T> inline T open_range_check(T v, T maxv) { assert(v < maxv); BASISU_NOTE_UNUSED(maxv); return v; }
|
||||
|
||||
// Open interval
|
||||
inline bool in_bounds(int v, int l, int h)
|
||||
{
|
||||
return (v >= l) && (v < h);
|
||||
}
|
||||
|
||||
// Closed interval
|
||||
inline bool in_range(int v, int l, int h)
|
||||
{
|
||||
return (v >= l) && (v <= h);
|
||||
}
|
||||
|
||||
inline uint32_t total_bits(uint32_t v) { uint32_t l = 0; for ( ; v > 0U; ++l) v >>= 1; return l; }
|
||||
|
||||
template<typename T> inline T saturate(T val) { return clamp(val, 0.0f, 1.0f); }
|
||||
|
||||
inline uint32_t get_bit(uint32_t src, int ndx)
|
||||
{
|
||||
assert(in_bounds(ndx, 0, 32));
|
||||
return (src >> ndx) & 1;
|
||||
}
|
||||
|
||||
inline bool is_bit_set(uint32_t src, int ndx)
|
||||
{
|
||||
return get_bit(src, ndx) != 0;
|
||||
}
|
||||
|
||||
inline uint32_t get_bits(uint32_t val, int low, int high)
|
||||
{
|
||||
const int num_bits = (high - low) + 1;
|
||||
assert(in_range(num_bits, 1, 32));
|
||||
|
||||
val >>= low;
|
||||
if (num_bits != 32)
|
||||
val &= ((1u << num_bits) - 1);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
template<typename T, typename R> inline void append_vector(T &vec, const R *pObjs, size_t n)
|
||||
{
|
||||
if (n)
|
||||
@ -267,6 +315,11 @@ namespace basisu
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline uint32_t read_le_word(const uint8_t* pBytes)
|
||||
{
|
||||
return (pBytes[1] << 8U) | (pBytes[0]);
|
||||
}
|
||||
|
||||
static inline uint32_t read_le_dword(const uint8_t *pBytes)
|
||||
{
|
||||
return (pBytes[3] << 24U) | (pBytes[2] << 16U) | (pBytes[1] << 8U) | (pBytes[0]);
|
||||
@ -303,6 +356,10 @@ namespace basisu
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#endif
|
||||
inline operator uint32_t() const
|
||||
{
|
||||
switch (NumBytes)
|
||||
@ -354,6 +411,9 @@ namespace basisu
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
};
|
||||
|
||||
enum eZero { cZero };
|
||||
@ -402,8 +462,11 @@ namespace basisu
|
||||
cBC3, // DXT5 (BC4/DXT5A block followed by a BC1/DXT1 block)
|
||||
cBC4, // DXT5A
|
||||
cBC5, // 3DC/DXN (two BC4/DXT5A blocks)
|
||||
cBC6HSigned, // HDR
|
||||
cBC6HUnsigned, // HDR
|
||||
cBC7,
|
||||
cASTC4x4, // LDR only
|
||||
cASTC_LDR_4x4, // ASTC 4x4 LDR only
|
||||
cASTC_HDR_4x4, // ASTC 4x4 HDR only (but may use LDR ASTC blocks internally)
|
||||
cPVRTC1_4_RGB,
|
||||
cPVRTC1_4_RGBA,
|
||||
cATC_RGB,
|
||||
@ -413,6 +476,7 @@ namespace basisu
|
||||
cETC2_R11_EAC,
|
||||
cETC2_RG11_EAC,
|
||||
cUASTC4x4,
|
||||
cUASTC_HDR_4x4,
|
||||
cBC1_NV,
|
||||
cBC1_AMD,
|
||||
|
||||
@ -421,9 +485,13 @@ namespace basisu
|
||||
cRGB565,
|
||||
cBGR565,
|
||||
cRGBA4444,
|
||||
cABGR4444
|
||||
cABGR4444,
|
||||
cRGBA_HALF,
|
||||
cRGB_HALF,
|
||||
cRGB_9E5
|
||||
};
|
||||
|
||||
// This is bytes per block for GPU formats, or bytes per texel for uncompressed formats.
|
||||
inline uint32_t get_bytes_per_block(texture_format fmt)
|
||||
{
|
||||
switch (fmt)
|
||||
@ -443,13 +511,27 @@ namespace basisu
|
||||
case texture_format::cETC2_R11_EAC:
|
||||
return 8;
|
||||
case texture_format::cRGBA32:
|
||||
return sizeof(uint32_t) * 16;
|
||||
case texture_format::cRGB_9E5:
|
||||
return sizeof(uint32_t);
|
||||
case texture_format::cRGB_HALF:
|
||||
return sizeof(uint16_t) * 3;
|
||||
case texture_format::cRGBA_HALF:
|
||||
return sizeof(uint16_t) * 4;
|
||||
case texture_format::cRGB565:
|
||||
case texture_format::cBGR565:
|
||||
case texture_format::cRGBA4444:
|
||||
case texture_format::cABGR4444:
|
||||
return sizeof(uint16_t);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Everything else is 16 bytes/block.
|
||||
return 16;
|
||||
}
|
||||
|
||||
// This is qwords per block for GPU formats, or not valid for uncompressed formats.
|
||||
inline uint32_t get_qwords_per_block(texture_format fmt)
|
||||
{
|
||||
return get_bytes_per_block(fmt) >> 3;
|
||||
@ -474,5 +556,16 @@ namespace basisu
|
||||
return 4;
|
||||
}
|
||||
|
||||
inline bool is_hdr_texture_format(texture_format fmt)
|
||||
{
|
||||
if (fmt == texture_format::cASTC_HDR_4x4)
|
||||
return true;
|
||||
if (fmt == texture_format::cUASTC_HDR_4x4)
|
||||
return true;
|
||||
if ((fmt == texture_format::cBC6HSigned) || (fmt == texture_format::cBC6HUnsigned))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace basisu
|
||||
|
||||
|
102
thirdparty/basis_universal/transcoder/basisu_astc_hdr_core.h
vendored
Normal file
102
thirdparty/basis_universal/transcoder/basisu_astc_hdr_core.h
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
// File: basisu_astc_hdr_core.h
|
||||
#pragma once
|
||||
#include "basisu_astc_helpers.h"
|
||||
|
||||
namespace basist
|
||||
{
|
||||
struct astc_blk
|
||||
{
|
||||
uint8_t m_vals[16];
|
||||
};
|
||||
|
||||
// ASTC_HDR_MAX_VAL is the maximum color component value that can be encoded.
|
||||
// If the input has values higher than this, they need to be linearly scaled so all values are between [0,ASTC_HDR_MAX_VAL], and the linear scaling inverted in the shader.
|
||||
const float ASTC_HDR_MAX_VAL = 65216.0f; // actually MAX_QLOG12_VAL
|
||||
|
||||
// Maximum usable QLOG encodings, and their floating point equivalent values, that don't result in NaN/Inf's.
|
||||
const uint32_t MAX_QLOG7 = 123;
|
||||
//const float MAX_QLOG7_VAL = 55296.0f;
|
||||
|
||||
const uint32_t MAX_QLOG8 = 247;
|
||||
//const float MAX_QLOG8_VAL = 60416.0f;
|
||||
|
||||
const uint32_t MAX_QLOG9 = 495;
|
||||
//const float MAX_QLOG9_VAL = 62976.0f;
|
||||
|
||||
const uint32_t MAX_QLOG10 = 991;
|
||||
//const float MAX_QLOG10_VAL = 64256.0f;
|
||||
|
||||
const uint32_t MAX_QLOG11 = 1983;
|
||||
//const float MAX_QLOG11_VAL = 64896.0f;
|
||||
|
||||
const uint32_t MAX_QLOG12 = 3967;
|
||||
//const float MAX_QLOG12_VAL = 65216.0f;
|
||||
|
||||
const uint32_t MAX_QLOG16 = 63487;
|
||||
const float MAX_QLOG16_VAL = 65504.0f;
|
||||
|
||||
const uint32_t NUM_MODE11_ENDPOINTS = 6, NUM_MODE7_ENDPOINTS = 4;
|
||||
|
||||
// Notes:
|
||||
// qlog16_to_half(half_to_qlog16(half_val_as_int)) == half_val_as_int (is lossless)
|
||||
// However, this is not lossless in the general sense.
|
||||
inline half_float qlog16_to_half_slow(uint32_t qlog16)
|
||||
{
|
||||
assert(qlog16 <= 0xFFFF);
|
||||
|
||||
int C = qlog16;
|
||||
|
||||
int E = (C & 0xF800) >> 11;
|
||||
int M = C & 0x7FF;
|
||||
|
||||
int Mt;
|
||||
if (M < 512)
|
||||
Mt = 3 * M;
|
||||
else if (M >= 1536)
|
||||
Mt = 5 * M - 2048;
|
||||
else
|
||||
Mt = 4 * M - 512;
|
||||
|
||||
int Cf = (E << 10) + (Mt >> 3);
|
||||
return (half_float)Cf;
|
||||
}
|
||||
|
||||
// This is not lossless
|
||||
inline half_float qlog_to_half_slow(uint32_t qlog, uint32_t bits)
|
||||
{
|
||||
assert((bits >= 7U) && (bits <= 16U));
|
||||
assert(qlog < (1U << bits));
|
||||
|
||||
int C = qlog << (16 - bits);
|
||||
return qlog16_to_half_slow(C);
|
||||
}
|
||||
|
||||
void astc_hdr_core_init();
|
||||
|
||||
void decode_mode7_to_qlog12_ise20(
|
||||
const uint8_t* pEndpoints,
|
||||
int e[2][3],
|
||||
int* pScale);
|
||||
|
||||
bool decode_mode7_to_qlog12(
|
||||
const uint8_t* pEndpoints,
|
||||
int e[2][3],
|
||||
int* pScale,
|
||||
uint32_t ise_endpoint_range);
|
||||
|
||||
void decode_mode11_to_qlog12_ise20(
|
||||
const uint8_t* pEndpoints,
|
||||
int e[2][3]);
|
||||
|
||||
bool decode_mode11_to_qlog12(
|
||||
const uint8_t* pEndpoints,
|
||||
int e[2][3],
|
||||
uint32_t ise_endpoint_range);
|
||||
|
||||
bool transcode_bc6h_1subset(half_float h_e[3][2], const astc_helpers::log_astc_block& best_blk, bc6h_block& transcoded_bc6h_blk);
|
||||
bool transcode_bc6h_2subsets(uint32_t common_part_index, const astc_helpers::log_astc_block& best_blk, bc6h_block& transcoded_bc6h_blk);
|
||||
|
||||
bool astc_hdr_transcode_to_bc6h(const astc_blk& src_blk, bc6h_block& dst_blk);
|
||||
bool astc_hdr_transcode_to_bc6h(const astc_helpers::log_astc_block& log_blk, bc6h_block& dst_blk);
|
||||
|
||||
} // namespace basist
|
3587
thirdparty/basis_universal/transcoder/basisu_astc_helpers.h
vendored
Normal file
3587
thirdparty/basis_universal/transcoder/basisu_astc_helpers.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -188,8 +188,9 @@ namespace basisu
|
||||
|
||||
#define BASISU_IS_SCALAR_TYPE(T) (scalar_type<T>::cFlag)
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__<5
|
||||
#define BASISU_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)
|
||||
#if !defined(BASISU_HAVE_STD_TRIVIALLY_COPYABLE) && defined(__GNUC__) && __GNUC__<5
|
||||
//#define BASISU_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)
|
||||
#define BASISU_IS_TRIVIALLY_COPYABLE(...) __is_trivially_copyable(__VA_ARGS__)
|
||||
#else
|
||||
#define BASISU_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value
|
||||
#endif
|
||||
@ -286,8 +287,19 @@ namespace basisu
|
||||
|
||||
if (BASISU_IS_BITWISE_COPYABLE(T))
|
||||
{
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||
#endif
|
||||
#endif
|
||||
if ((m_p) && (other.m_p))
|
||||
memcpy(m_p, other.m_p, m_size * sizeof(T));
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -330,8 +342,19 @@ namespace basisu
|
||||
|
||||
if (BASISU_IS_BITWISE_COPYABLE(T))
|
||||
{
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||
#endif
|
||||
#endif
|
||||
if ((m_p) && (other.m_p))
|
||||
memcpy(m_p, other.m_p, other.m_size * sizeof(T));
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -501,7 +524,7 @@ namespace basisu
|
||||
|
||||
if (new_capacity > m_capacity)
|
||||
{
|
||||
if (!increase_capacity(new_capacity, false))
|
||||
if (!increase_capacity(new_capacity, false, true))
|
||||
return false;
|
||||
}
|
||||
else if (new_capacity < m_capacity)
|
||||
@ -509,7 +532,8 @@ namespace basisu
|
||||
// Must work around the lack of a "decrease_capacity()" method.
|
||||
// This case is rare enough in practice that it's probably not worth implementing an optimized in-place resize.
|
||||
vector tmp;
|
||||
tmp.increase_capacity(helpers::maximum(m_size, new_capacity), false);
|
||||
if (!tmp.increase_capacity(helpers::maximum(m_size, new_capacity), false, true))
|
||||
return false;
|
||||
tmp = *this;
|
||||
swap(tmp);
|
||||
}
|
||||
@ -750,7 +774,21 @@ namespace basisu
|
||||
}
|
||||
|
||||
// Copy "down" the objects to preserve, filling in the empty slots.
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
memmove(pDst, pSrc, num_to_move * sizeof(T));
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1003,7 +1041,21 @@ namespace basisu
|
||||
inline void set_all(const T& o)
|
||||
{
|
||||
if ((sizeof(T) == 1) && (scalar_type<T>::cFlag))
|
||||
{
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wclass-memaccess"
|
||||
#endif
|
||||
#endif
|
||||
memset(m_p, *reinterpret_cast<const uint8_t*>(&o), m_size);
|
||||
|
||||
#ifndef __EMSCRIPTEN__
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
T* pDst = m_p;
|
||||
@ -1029,7 +1081,7 @@ namespace basisu
|
||||
// Important: This method is used in Basis Universal. If you change how this container allocates memory, you'll need to change any users of this method.
|
||||
inline bool grant_ownership(T* p, uint32_t size, uint32_t capacity)
|
||||
{
|
||||
// To to prevent the caller from obviously shooting themselves in the foot.
|
||||
// To prevent the caller from obviously shooting themselves in the foot.
|
||||
if (((p + capacity) > m_p) && (p < (m_p + m_capacity)))
|
||||
{
|
||||
// Can grant ownership of a block inside the container itself!
|
||||
|
@ -19,23 +19,30 @@ namespace basisu
|
||||
if (m_capacity >= min_new_capacity)
|
||||
return true;
|
||||
|
||||
size_t new_capacity = min_new_capacity;
|
||||
if ((grow_hint) && (!helpers::is_power_of_2((uint64_t)new_capacity)))
|
||||
{
|
||||
new_capacity = (size_t)helpers::next_pow2((uint64_t)new_capacity);
|
||||
uint64_t new_capacity_u64 = min_new_capacity;
|
||||
if ((grow_hint) && (!helpers::is_power_of_2(new_capacity_u64)))
|
||||
new_capacity_u64 = helpers::next_pow2(new_capacity_u64);
|
||||
|
||||
assert(new_capacity && (new_capacity > m_capacity));
|
||||
|
||||
if (new_capacity < min_new_capacity)
|
||||
size_t new_capacity = (size_t)new_capacity_u64;
|
||||
if (new_capacity != new_capacity_u64)
|
||||
{
|
||||
if (nofail)
|
||||
return false;
|
||||
fprintf(stderr, "vector too large\n");
|
||||
fprintf(stderr, "elemental_vector::increase_capacity: vector too large\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
const uint64_t desired_size_u64 = (uint64_t)element_size * new_capacity;
|
||||
|
||||
const size_t desired_size = (size_t)desired_size_u64;
|
||||
if (desired_size_u64 != desired_size)
|
||||
{
|
||||
if (nofail)
|
||||
return false;
|
||||
fprintf(stderr, "elemental_vector::increase_capacity: vector too large\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
const size_t desired_size = element_size * new_capacity;
|
||||
size_t actual_size = 0;
|
||||
if (!pMover)
|
||||
{
|
||||
@ -46,11 +53,7 @@ namespace basisu
|
||||
return false;
|
||||
|
||||
char buf[256];
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(buf, sizeof(buf), "vector: realloc() failed allocating %u bytes", (uint32_t)desired_size);
|
||||
#else
|
||||
sprintf(buf, "vector: realloc() failed allocating %u bytes", (uint32_t)desired_size);
|
||||
#endif
|
||||
snprintf(buf, sizeof(buf), "elemental_vector::increase_capacity: realloc() failed allocating %zu bytes", desired_size);
|
||||
fprintf(stderr, "%s", buf);
|
||||
abort();
|
||||
}
|
||||
@ -75,11 +78,7 @@ namespace basisu
|
||||
return false;
|
||||
|
||||
char buf[256];
|
||||
#ifdef _MSC_VER
|
||||
sprintf_s(buf, sizeof(buf), "vector: malloc() failed allocating %u bytes", (uint32_t)desired_size);
|
||||
#else
|
||||
sprintf(buf, "vector: malloc() failed allocating %u bytes", (uint32_t)desired_size);
|
||||
#endif
|
||||
snprintf(buf, sizeof(buf), "elemental_vector::increase_capacity: malloc() failed allocating %zu bytes", desired_size);
|
||||
fprintf(stderr, "%s", buf);
|
||||
abort();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
// basis_file_headers.h
|
||||
// Copyright (C) 2019-2020 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.
|
||||
@ -89,7 +89,8 @@ namespace basist
|
||||
enum class basis_tex_format
|
||||
{
|
||||
cETC1S = 0,
|
||||
cUASTC4x4 = 1
|
||||
cUASTC4x4 = 1,
|
||||
cUASTC_HDR_4x4 = 2
|
||||
};
|
||||
|
||||
struct basis_file_header
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
// basisu_transcoder.h
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -29,6 +29,7 @@
|
||||
|
||||
// Set BASISU_FORCE_DEVEL_MESSAGES to 1 to enable debug printf()'s whenever an error occurs, for easier debugging during development.
|
||||
#ifndef BASISU_FORCE_DEVEL_MESSAGES
|
||||
// TODO - disable before checking in
|
||||
#define BASISU_FORCE_DEVEL_MESSAGES 0
|
||||
#endif
|
||||
|
||||
@ -66,7 +67,8 @@ namespace basist
|
||||
cTFPVRTC1_4_RGBA = 9, // Opaque+alpha, most useful for simple opacity maps. If .basis file doesn't have alpha cTFPVRTC1_4_RGB will be used instead. Lowest quality of any supported texture format.
|
||||
|
||||
// ASTC (mobile, Intel devices, hopefully all desktop GPU's one day)
|
||||
cTFASTC_4x4_RGBA = 10, // Opaque+alpha, ASTC 4x4, alpha channel will be opaque for opaque .basis files. Transcoder uses RGB/RGBA/L/LA modes, void extent, and up to two ([0,47] and [0,255]) endpoint precisions.
|
||||
cTFASTC_4x4_RGBA = 10, // LDR. Opaque+alpha, ASTC 4x4, alpha channel will be opaque for opaque .basis files.
|
||||
// LDR: Transcoder uses RGB/RGBA/L/LA modes, void extent, and up to two ([0,47] and [0,255]) endpoint precisions.
|
||||
|
||||
// ATC (mobile, Adreno devices, this is a niche format)
|
||||
cTFATC_RGB = 11, // Opaque, RGB or alpha if cDecodeFlagsTranscodeAlphaDataToOpaqueFormats flag is specified. ATI ATC (GL_ATC_RGB_AMD)
|
||||
@ -83,13 +85,22 @@ namespace basist
|
||||
cTFETC2_EAC_R11 = 20, // R only (ETC2 EAC R11 unsigned)
|
||||
cTFETC2_EAC_RG11 = 21, // RG only (ETC2 EAC RG11 unsigned), R=opaque.r, G=alpha - for tangent space normal maps
|
||||
|
||||
cTFBC6H = 22, // HDR, RGB only, unsigned
|
||||
cTFASTC_HDR_4x4_RGBA = 23, // HDR, RGBA (currently UASTC HDR is only RGB), unsigned
|
||||
|
||||
// Uncompressed (raw pixel) formats
|
||||
// Note these uncompressed formats (RGBA32, 565, and 4444) can only be transcoded to from LDR input files (ETC1S or UASTC LDR).
|
||||
cTFRGBA32 = 13, // 32bpp RGBA image stored in raster (not block) order in memory, R is first byte, A is last byte.
|
||||
cTFRGB565 = 14, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 11
|
||||
cTFBGR565 = 15, // 16bpp RGB image stored in raster (not block) order in memory, R at bit position 0
|
||||
cTFRGBA4444 = 16, // 16bpp RGBA image stored in raster (not block) order in memory, R at bit position 12, A at bit position 0
|
||||
|
||||
cTFTotalTextureFormats = 22,
|
||||
// Note these uncompressed formats (HALF and 9E5) can only be transcoded to from HDR input files (UASTC HDR).
|
||||
cTFRGB_HALF = 24, // 48bpp RGB half (16-bits/component, 3 components)
|
||||
cTFRGBA_HALF = 25, // 64bpp RGBA half (16-bits/component, 4 components) (A will always currently 1.0, UASTC_HDR doesn't support alpha)
|
||||
cTFRGB_9E5 = 26, // 32bpp RGB 9E5 (shared exponent, positive only, see GL_EXT_texture_shared_exponent)
|
||||
|
||||
cTFTotalTextureFormats = 27,
|
||||
|
||||
// Old enums for compatibility with code compiled against previous versions
|
||||
cTFETC1 = cTFETC1_RGB,
|
||||
@ -124,6 +135,9 @@ namespace basist
|
||||
// Returns true if the format supports an alpha channel.
|
||||
bool basis_transcoder_format_has_alpha(transcoder_texture_format fmt);
|
||||
|
||||
// Returns true if the format is HDR.
|
||||
bool basis_transcoder_format_is_hdr(transcoder_texture_format fmt);
|
||||
|
||||
// Returns the basisu::texture_format corresponding to the specified transcoder_texture_format.
|
||||
basisu::texture_format basis_get_basisu_texture_format(transcoder_texture_format fmt);
|
||||
|
||||
@ -142,7 +156,7 @@ namespace basist
|
||||
// Returns the block height for the specified texture format, which is currently always 4.
|
||||
uint32_t basis_get_block_height(transcoder_texture_format tex_type);
|
||||
|
||||
// Returns true if the specified format was enabled at compile time.
|
||||
// Returns true if the specified format was enabled at compile time, and is supported for the specific basis/ktx2 texture format (ETC1S, UASTC, or UASTC HDR).
|
||||
bool basis_is_format_supported(transcoder_texture_format tex_type, basis_tex_format fmt = basis_tex_format::cETC1S);
|
||||
|
||||
// Validates that the output buffer is large enough to hold the entire transcoded texture.
|
||||
@ -317,6 +331,42 @@ namespace basist
|
||||
int channel0 = -1, int channel1 = -1);
|
||||
};
|
||||
|
||||
class basisu_lowlevel_uastc_hdr_transcoder
|
||||
{
|
||||
friend class basisu_transcoder;
|
||||
|
||||
public:
|
||||
basisu_lowlevel_uastc_hdr_transcoder();
|
||||
|
||||
bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
|
||||
uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, bool has_alpha, const uint32_t orig_width, const uint32_t orig_height, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
|
||||
basisu_transcoder_state* pState = nullptr, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1, uint32_t decode_flags = 0);
|
||||
|
||||
bool transcode_slice(void* pDst_blocks, uint32_t num_blocks_x, uint32_t num_blocks_y, const uint8_t* pImage_data, uint32_t image_data_size, block_format fmt,
|
||||
uint32_t output_block_or_pixel_stride_in_bytes, bool bc1_allow_threecolor_blocks, const basis_file_header& header, const basis_slice_desc& slice_desc, uint32_t output_row_pitch_in_blocks_or_pixels = 0,
|
||||
basisu_transcoder_state* pState = nullptr, uint32_t output_rows_in_pixels = 0, int channel0 = -1, int channel1 = -1, uint32_t decode_flags = 0)
|
||||
{
|
||||
return transcode_slice(pDst_blocks, num_blocks_x, num_blocks_y, pImage_data, image_data_size, fmt,
|
||||
output_block_or_pixel_stride_in_bytes, bc1_allow_threecolor_blocks, (header.m_flags & cBASISHeaderFlagHasAlphaSlices) != 0, slice_desc.m_orig_width, slice_desc.m_orig_height, output_row_pitch_in_blocks_or_pixels,
|
||||
pState, output_rows_in_pixels, channel0, channel1, decode_flags);
|
||||
}
|
||||
|
||||
// Container independent transcoding
|
||||
bool transcode_image(
|
||||
transcoder_texture_format target_format,
|
||||
void* pOutput_blocks, uint32_t output_blocks_buf_size_in_blocks_or_pixels,
|
||||
const uint8_t* pCompressed_data, uint32_t compressed_data_length,
|
||||
uint32_t num_blocks_x, uint32_t num_blocks_y, uint32_t orig_width, uint32_t orig_height, uint32_t level_index,
|
||||
uint32_t slice_offset, uint32_t slice_length,
|
||||
uint32_t decode_flags = 0,
|
||||
bool has_alpha = false,
|
||||
bool is_video = false,
|
||||
uint32_t output_row_pitch_in_blocks_or_pixels = 0,
|
||||
basisu_transcoder_state* pState = nullptr,
|
||||
uint32_t output_rows_in_pixels = 0,
|
||||
int channel0 = -1, int channel1 = -1);
|
||||
};
|
||||
|
||||
struct basisu_slice_info
|
||||
{
|
||||
uint32_t m_orig_width;
|
||||
@ -530,6 +580,7 @@ namespace basist
|
||||
private:
|
||||
mutable basisu_lowlevel_etc1s_transcoder m_lowlevel_etc1s_decoder;
|
||||
mutable basisu_lowlevel_uastc_transcoder m_lowlevel_uastc_decoder;
|
||||
mutable basisu_lowlevel_uastc_hdr_transcoder m_lowlevel_uastc_hdr_decoder;
|
||||
|
||||
bool m_ready_to_transcode;
|
||||
|
||||
@ -612,10 +663,12 @@ namespace basist
|
||||
#pragma pack(pop)
|
||||
|
||||
const uint32_t KTX2_VK_FORMAT_UNDEFINED = 0;
|
||||
const uint32_t KTX2_FORMAT_UASTC_4x4_SFLOAT_BLOCK = 1000066000; // TODO, is this correct?
|
||||
const uint32_t KTX2_KDF_DF_MODEL_UASTC = 166;
|
||||
const uint32_t KTX2_KDF_DF_MODEL_UASTC_HDR = 167;
|
||||
const uint32_t KTX2_KDF_DF_MODEL_ETC1S = 163;
|
||||
const uint32_t KTX2_IMAGE_IS_P_FRAME = 2;
|
||||
const uint32_t KTX2_UASTC_BLOCK_SIZE = 16;
|
||||
const uint32_t KTX2_UASTC_BLOCK_SIZE = 16; // also the block size for UASTC_HDR
|
||||
const uint32_t KTX2_MAX_SUPPORTED_LEVEL_COUNT = 16; // this is an implementation specific constraint and can be increased
|
||||
|
||||
// The KTX2 transfer functions supported by KTX2
|
||||
@ -800,13 +853,15 @@ namespace basist
|
||||
// Returns 0 or the number of layers in the texture array or texture video. Valid after init().
|
||||
uint32_t get_layers() const { return m_header.m_layer_count; }
|
||||
|
||||
// Returns cETC1S or cUASTC4x4. Valid after init().
|
||||
// Returns cETC1S, cUASTC4x4, or cUASTC_HDR_4x4. Valid after init().
|
||||
basist::basis_tex_format get_format() const { return m_format; }
|
||||
|
||||
bool is_etc1s() const { return get_format() == basist::basis_tex_format::cETC1S; }
|
||||
|
||||
bool is_uastc() const { return get_format() == basist::basis_tex_format::cUASTC4x4; }
|
||||
|
||||
bool is_hdr() const { return get_format() == basist::basis_tex_format::cUASTC_HDR_4x4; }
|
||||
|
||||
// Returns true if the ETC1S file has two planes (typically RGBA, or RRRG), or true if the UASTC file has alpha data. Valid after init().
|
||||
uint32_t get_has_alpha() const { return m_has_alpha; }
|
||||
|
||||
@ -913,6 +968,7 @@ namespace basist
|
||||
|
||||
basist::basisu_lowlevel_etc1s_transcoder m_etc1s_transcoder;
|
||||
basist::basisu_lowlevel_uastc_transcoder m_uastc_transcoder;
|
||||
basist::basisu_lowlevel_uastc_hdr_transcoder m_uastc_hdr_transcoder;
|
||||
|
||||
ktx2_transcoder_state m_def_transcoder_state;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
// basisu_transcoder_internal.h - Universal texture format transcoder library.
|
||||
// Copyright (C) 2019-2021 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2019-2024 Binomial LLC. All Rights Reserved.
|
||||
//
|
||||
// Important: If compiling with gcc, be sure strict aliasing is disabled: -fno-strict-aliasing
|
||||
//
|
||||
@ -20,8 +20,9 @@
|
||||
#pragma warning (disable: 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
#define BASISD_LIB_VERSION 116
|
||||
#define BASISD_VERSION_STRING "01.16"
|
||||
// v1.50: Added UASTC HDR support
|
||||
#define BASISD_LIB_VERSION 150
|
||||
#define BASISD_VERSION_STRING "01.50"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define BASISD_BUILD_DEBUG
|
||||
@ -82,8 +83,14 @@ namespace basist
|
||||
cRGBA4444_ALPHA,
|
||||
cRGBA4444_COLOR_OPAQUE,
|
||||
cRGBA4444,
|
||||
cRGBA_HALF,
|
||||
cRGB_HALF,
|
||||
cRGB_9E5,
|
||||
|
||||
cUASTC_4x4,
|
||||
cUASTC_4x4, // LDR, universal
|
||||
cUASTC_HDR_4x4, // HDR, transcodes only to 4x4 HDR ASTC, BC6H, or uncompressed
|
||||
cBC6H,
|
||||
cASTC_HDR_4x4,
|
||||
|
||||
cTotalBlockFormats
|
||||
};
|
||||
@ -264,8 +271,8 @@ namespace basist
|
||||
}
|
||||
|
||||
const basisu::uint8_vec &get_code_sizes() const { return m_code_sizes; }
|
||||
const basisu::int_vec get_lookup() const { return m_lookup; }
|
||||
const basisu::int16_vec get_tree() const { return m_tree; }
|
||||
const basisu::int_vec &get_lookup() const { return m_lookup; }
|
||||
const basisu::int16_vec &get_tree() const { return m_tree; }
|
||||
|
||||
bool is_valid() const { return m_code_sizes.size() > 0; }
|
||||
|
||||
@ -790,6 +797,197 @@ namespace basist
|
||||
|
||||
bool basis_block_format_is_uncompressed(block_format tex_type);
|
||||
|
||||
//------------------------------------
|
||||
|
||||
typedef uint16_t half_float;
|
||||
|
||||
const double MIN_DENORM_HALF_FLOAT = 0.000000059604645; // smallest positive subnormal number
|
||||
const double MIN_HALF_FLOAT = 0.00006103515625; // smallest positive normal number
|
||||
const double MAX_HALF_FLOAT = 65504.0; // largest normal number
|
||||
|
||||
inline uint32_t get_bits(uint32_t val, int low, int high)
|
||||
{
|
||||
const int num_bits = (high - low) + 1;
|
||||
assert((num_bits >= 1) && (num_bits <= 32));
|
||||
|
||||
val >>= low;
|
||||
if (num_bits != 32)
|
||||
val &= ((1u << num_bits) - 1);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
inline bool is_half_inf_or_nan(half_float v)
|
||||
{
|
||||
return get_bits(v, 10, 14) == 31;
|
||||
}
|
||||
|
||||
inline bool is_half_denorm(half_float v)
|
||||
{
|
||||
int e = (v >> 10) & 31;
|
||||
return !e;
|
||||
}
|
||||
|
||||
inline int get_half_exp(half_float v)
|
||||
{
|
||||
int e = ((v >> 10) & 31);
|
||||
return e ? (e - 15) : -14;
|
||||
}
|
||||
|
||||
inline int get_half_mantissa(half_float v)
|
||||
{
|
||||
if (is_half_denorm(v))
|
||||
return v & 0x3FF;
|
||||
return (v & 0x3FF) | 0x400;
|
||||
}
|
||||
|
||||
inline float get_half_mantissaf(half_float v)
|
||||
{
|
||||
return ((float)get_half_mantissa(v)) / 1024.0f;
|
||||
}
|
||||
|
||||
inline int get_half_sign(half_float v)
|
||||
{
|
||||
return v ? ((v & 0x8000) ? -1 : 1) : 0;
|
||||
}
|
||||
|
||||
inline bool half_is_signed(half_float v)
|
||||
{
|
||||
return (v & 0x8000) != 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int hexp = get_half_exp(Cf);
|
||||
float hman = get_half_mantissaf(Cf);
|
||||
int hsign = get_half_sign(Cf);
|
||||
float k = powf(2.0f, hexp) * hman * hsign;
|
||||
if (is_half_inf_or_nan(Cf))
|
||||
k = std::numeric_limits<float>::quiet_NaN();
|
||||
#endif
|
||||
|
||||
half_float float_to_half(float val);
|
||||
|
||||
inline float half_to_float(half_float hval)
|
||||
{
|
||||
union { float f; uint32_t u; } x = { 0 };
|
||||
|
||||
uint32_t s = ((uint32_t)hval >> 15) & 1;
|
||||
uint32_t e = ((uint32_t)hval >> 10) & 0x1F;
|
||||
uint32_t m = (uint32_t)hval & 0x3FF;
|
||||
|
||||
if (!e)
|
||||
{
|
||||
if (!m)
|
||||
{
|
||||
// +- 0
|
||||
x.u = s << 31;
|
||||
return x.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// denormalized
|
||||
while (!(m & 0x00000400))
|
||||
{
|
||||
m <<= 1;
|
||||
--e;
|
||||
}
|
||||
|
||||
++e;
|
||||
m &= ~0x00000400;
|
||||
}
|
||||
}
|
||||
else if (e == 31)
|
||||
{
|
||||
if (m == 0)
|
||||
{
|
||||
// +/- INF
|
||||
x.u = (s << 31) | 0x7f800000;
|
||||
return x.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// +/- NaN
|
||||
x.u = (s << 31) | 0x7f800000 | (m << 13);
|
||||
return x.f;
|
||||
}
|
||||
}
|
||||
|
||||
e = e + (127 - 15);
|
||||
m = m << 13;
|
||||
|
||||
assert(s <= 1);
|
||||
assert(m <= 0x7FFFFF);
|
||||
assert(e <= 255);
|
||||
|
||||
x.u = m | (e << 23) | (s << 31);
|
||||
return x.f;
|
||||
}
|
||||
|
||||
// Originally from bc6h_enc.h
|
||||
|
||||
void bc6h_enc_init();
|
||||
|
||||
const uint32_t MAX_BLOG16_VAL = 0xFFFF;
|
||||
|
||||
// BC6H internals
|
||||
const uint32_t NUM_BC6H_MODES = 14;
|
||||
const uint32_t BC6H_LAST_MODE_INDEX = 13;
|
||||
const uint32_t BC6H_FIRST_1SUBSET_MODE_INDEX = 10; // in the MS docs, this is "mode 11" (where the first mode is 1), 60 bits for endpoints (10.10, 10.10, 10.10), 63 bits for weights
|
||||
const uint32_t TOTAL_BC6H_PARTITION_PATTERNS = 32;
|
||||
|
||||
extern const uint8_t g_bc6h_mode_sig_bits[NUM_BC6H_MODES][4]; // base, r, g, b
|
||||
|
||||
struct bc6h_bit_layout
|
||||
{
|
||||
int8_t m_comp; // R=0,G=1,B=2,D=3 (D=partition index)
|
||||
int8_t m_index; // 0-3, 0-1 Low/High subset 1, 2-3 Low/High subset 2, -1=partition index (d)
|
||||
int8_t m_last_bit;
|
||||
int8_t m_first_bit; // may be -1 if a single bit, may be >m_last_bit if reversed
|
||||
};
|
||||
|
||||
const uint32_t MAX_BC6H_LAYOUT_INDEX = 25;
|
||||
extern const bc6h_bit_layout g_bc6h_bit_layouts[NUM_BC6H_MODES][MAX_BC6H_LAYOUT_INDEX];
|
||||
|
||||
extern const uint8_t g_bc6h_2subset_patterns[TOTAL_BC6H_PARTITION_PATTERNS][4][4]; // [y][x]
|
||||
|
||||
extern const uint8_t g_bc6h_weight3[8];
|
||||
extern const uint8_t g_bc6h_weight4[16];
|
||||
|
||||
extern const int8_t g_bc6h_mode_lookup[32];
|
||||
|
||||
// Converts b16 to half float
|
||||
inline half_float bc6h_blog16_to_half(uint32_t comp)
|
||||
{
|
||||
assert(comp <= 0xFFFF);
|
||||
|
||||
// scale the magnitude by 31/64
|
||||
comp = (comp * 31u) >> 6u;
|
||||
return (half_float)comp;
|
||||
}
|
||||
|
||||
const uint32_t MAX_BC6H_HALF_FLOAT_AS_UINT = 0x7BFF;
|
||||
|
||||
// Inverts bc6h_blog16_to_half().
|
||||
// Returns the nearest blog16 given a half value.
|
||||
inline uint32_t bc6h_half_to_blog16(half_float h)
|
||||
{
|
||||
assert(h <= MAX_BC6H_HALF_FLOAT_AS_UINT);
|
||||
return (h * 64 + 30) / 31;
|
||||
}
|
||||
|
||||
struct bc6h_block
|
||||
{
|
||||
uint8_t m_bytes[16];
|
||||
};
|
||||
|
||||
void bc6h_enc_block_mode10(bc6h_block* pPacked_block, const half_float pEndpoints[3][2], const uint8_t* pWeights);
|
||||
void bc6h_enc_block_1subset_4bit_weights(bc6h_block* pPacked_block, const half_float pEndpoints[3][2], const uint8_t* pWeights);
|
||||
void bc6h_enc_block_1subset_mode9_3bit_weights(bc6h_block* pPacked_block, const half_float pEndpoints[3][2], const uint8_t* pWeights);
|
||||
void bc6h_enc_block_1subset_3bit_weights(bc6h_block* pPacked_block, const half_float pEndpoints[3][2], const uint8_t* pWeights);
|
||||
void bc6h_enc_block_2subset_mode9_3bit_weights(bc6h_block* pPacked_block, uint32_t common_part_index, const half_float pEndpoints[2][3][2], const uint8_t* pWeights); // pEndpoints[subset][comp][lh_index]
|
||||
void bc6h_enc_block_2subset_3bit_weights(bc6h_block* pPacked_block, uint32_t common_part_index, const half_float pEndpoints[2][3][2], const uint8_t* pWeights); // pEndpoints[subset][comp][lh_index]
|
||||
bool bc6h_enc_block_solid_color(bc6h_block* pPacked_block, const half_float pColor[3]);
|
||||
|
||||
} // namespace basist
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright (C) 2017-2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2017-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,4 +1,4 @@
|
||||
// Copyright (C) 2017-2019 Binomial LLC. All Rights Reserved.
|
||||
// Copyright (C) 2017-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,6 +13,7 @@ namespace basist
|
||||
const uint32_t UASTC_MODE_INDEX_SOLID_COLOR = 8;
|
||||
|
||||
const uint32_t TOTAL_ASTC_BC7_COMMON_PARTITIONS2 = 30;
|
||||
const uint32_t TOTAL_ASTC_BC6H_COMMON_PARTITIONS2 = 27; // BC6H only supports only 5-bit pattern indices, BC7 supports 4-bit or 6-bit
|
||||
const uint32_t TOTAL_ASTC_BC7_COMMON_PARTITIONS3 = 11;
|
||||
const uint32_t TOTAL_BC7_3_ASTC2_COMMON_PARTITIONS = 19;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user