diff --git a/CMakeLists.txt b/CMakeLists.txt index d1e4562..3f632e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,25 +54,25 @@ if (NOT MSVC) endif() set(BASISU_SRC_LIST ${COMMON_SRC_LIST} - basisu_backend.cpp - basisu_basis_file.cpp - basisu_comp.cpp - basisu_enc.cpp - basisu_etc.cpp - basisu_frontend.cpp - basisu_global_selector_palette_helpers.cpp - basisu_gpu_texture.cpp - basisu_pvrtc1_4.cpp - basisu_resampler.cpp - basisu_resample_filters.cpp - basisu_ssim.cpp basisu_tool.cpp - basisu_astc_decomp.cpp - basisu_uastc_enc.cpp - basisu_bc7enc.cpp - lodepng.cpp - apg_bmp.c - jpgd.cpp + encoder/basisu_backend.cpp + encoder/basisu_basis_file.cpp + encoder/basisu_comp.cpp + encoder/basisu_enc.cpp + encoder/basisu_etc.cpp + encoder/basisu_frontend.cpp + encoder/basisu_global_selector_palette_helpers.cpp + encoder/basisu_gpu_texture.cpp + encoder/basisu_pvrtc1_4.cpp + encoder/basisu_resampler.cpp + encoder/basisu_resample_filters.cpp + encoder/basisu_ssim.cpp + encoder/basisu_astc_decomp.cpp + encoder/basisu_uastc_enc.cpp + encoder/basisu_bc7enc.cpp + encoder/lodepng.cpp + encoder/apg_bmp.c + encoder/jpgd.cpp transcoder/basisu_transcoder.cpp ) diff --git a/README.md b/README.md index eda5f82..b9b8579 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,12 @@ The encoder uses [lodepng](https://lodev.org/lodepng/) for loading and saving PN The encoder uses [tcuAstcUtil.cpp](https://chromium.googlesource.com/external/deqp/+/refs/heads/master/framework/common/tcuAstcUtil.cpp), from the [Android drawElements Quality Program (deqp) Testing Suite](https://source.android.com/devices/graphics/deqp-testing), for unpacking the transcoder's ASTC output for testing/validation purposes. This code is Copyright 2016 The Android Open Source Project, and uses the Apache 2.0 license. We have modified the code so it has no external dependencies, and disabled HDR support. +### WebAssembly Support Using Emscripten + +Both the transcoder and now the compressor (as of 12/17/2020) may be compiled using emscripten to WebAssembly and used on the web. Currently, multithreading is not supported by the encoder when compiled with emscripten. An simple Web encoding demo is in webgl/encode_test. + +To enable compression support compile the JavaScript wrappers in webgl/transcoding/basis_wrappers.cpp with BASISU_SUPPORT_ENCODING set to 1. See the webgl/encoding directory. + ### Legal/IP/license stuff Basis Universal uses texture compression formats or technologies created by several companies: ARM Holdings, AMD, Ericsson, Microsoft, and Imagination Technologies Limited. All are supported by various open standards or API's from [The Khronos Group](https://www.khronos.org/), such as OpenGL 4.5, OpenGL ES, or Vulkan. diff --git a/basisu.vcxproj b/basisu.vcxproj index 3407176..f4ad5fd 100644 --- a/basisu.vcxproj +++ b/basisu.vcxproj @@ -147,52 +147,51 @@ - - - - - - + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - diff --git a/basisu.vcxproj.filters b/basisu.vcxproj.filters index 1764b4b..4f7afed 100644 --- a/basisu.vcxproj.filters +++ b/basisu.vcxproj.filters @@ -1,44 +1,66 @@  - - - - - - - - - - - - transcoder - - - - - - + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + - - - - - - - - - - - - - - transcoder @@ -51,15 +73,66 @@ transcoder - - - - transcoder - - + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + + + encoder + @@ -91,5 +164,8 @@ {7a54aaad-1d10-4bdf-b8e9-c14ed2263ed8} + + {518dd5c5-a7e1-4e79-8bb4-253e2d540c2c} + \ No newline at end of file diff --git a/basisu_tool.cpp b/basisu_tool.cpp index 3591ed2..aa168dc 100644 --- a/basisu_tool.cpp +++ b/basisu_tool.cpp @@ -18,15 +18,15 @@ #include "transcoder/basisu.h" #include "transcoder/basisu_transcoder_internal.h" -#include "basisu_enc.h" -#include "basisu_etc.h" -#include "basisu_gpu_texture.h" -#include "basisu_frontend.h" -#include "basisu_backend.h" +#include "encoder/basisu_enc.h" +#include "encoder/basisu_etc.h" +#include "encoder/basisu_gpu_texture.h" +#include "encoder/basisu_frontend.h" +#include "encoder/basisu_backend.h" #include "transcoder/basisu_global_selector_palette.h" -#include "basisu_comp.h" +#include "encoder/basisu_comp.h" #include "transcoder/basisu_transcoder.h" -#include "basisu_ssim.h" +#include "encoder/basisu_ssim.h" // Set BASISU_CATCH_EXCEPTIONS if you want exceptions to crash the app, otherwise main() catches them. #define BASISU_CATCH_EXCEPTIONS 0 @@ -408,7 +408,7 @@ public: else if (strcasecmp(pArg, "-force_alpha") == 0) m_comp_params.m_force_alpha = true; else if ((strcasecmp(pArg, "-separate_rg_to_color_alpha") == 0) || - (strcasecmp(pArg, "-seperate_rg_to_color_alpha") == 0)) // was mispelled for a while - whoops! + (strcasecmp(pArg, "-seperate_rg_to_color_alpha") == 0)) // was mispelled for a while - whoops! { m_comp_params.m_swizzle[0] = 0; m_comp_params.m_swizzle[1] = 0; @@ -1591,11 +1591,11 @@ static bool compare_mode(command_line_params &opts) return true; } -#include "basisu_astc_decomp.h" -#include "basisu_pvrtc1_4.h" +#include "encoder/basisu_astc_decomp.h" +#include "encoder/basisu_pvrtc1_4.h" #define MINIZ_HEADER_FILE_ONLY -#include "basisu_miniz.h" +#include "encoder/basisu_miniz.h" static bool bench_mode(command_line_params& opts) { #if 0 diff --git a/encoder/basisu_astc_decomp.cpp b/encoder/basisu_astc_decomp.cpp index 81a1800..f8d40d7 100644 --- a/encoder/basisu_astc_decomp.cpp +++ b/encoder/basisu_astc_decomp.cpp @@ -50,6 +50,13 @@ typedef uint64_t deUint64; #define DE_ASSERT assert +#ifdef _MSC_VER +#pragma warning (disable:4505) // unreferenced local function has been removed +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +#endif + namespace basisu_astc { static bool inBounds(int v, int l, int h) @@ -1548,3 +1555,7 @@ bool decompress(uint8_t *pDst, const uint8_t * data, bool isSRGB, int blockWidth } // astc } // basisu_astc + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif \ No newline at end of file diff --git a/encoder/basisu_astc_decomp.h b/encoder/basisu_astc_decomp.h index 6cd053b..9ec2e46 100644 --- a/encoder/basisu_astc_decomp.h +++ b/encoder/basisu_astc_decomp.h @@ -23,7 +23,7 @@ * \brief ASTC Utilities. *//*--------------------------------------------------------------------*/ -#include "transcoder/basisu.h" // to pick up the iterator debug level madness +#include "../transcoder/basisu.h" // to pick up the iterator debug level madness #include #include diff --git a/encoder/basisu_backend.h b/encoder/basisu_backend.h index 171ca83..e8518e2 100644 --- a/encoder/basisu_backend.h +++ b/encoder/basisu_backend.h @@ -14,10 +14,10 @@ // limitations under the License. #pragma once -#include "transcoder/basisu.h" +#include "../transcoder/basisu.h" #include "basisu_enc.h" -#include "transcoder/basisu_transcoder_internal.h" -#include "transcoder/basisu_global_selector_palette.h" +#include "../transcoder/basisu_transcoder_internal.h" +#include "../transcoder/basisu_global_selector_palette.h" #include "basisu_frontend.h" namespace basisu diff --git a/encoder/basisu_basis_file.cpp b/encoder/basisu_basis_file.cpp index ce6acd6..9662a9a 100644 --- a/encoder/basisu_basis_file.cpp +++ b/encoder/basisu_basis_file.cpp @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #include "basisu_basis_file.h" -#include "transcoder/basisu_transcoder.h" +#include "../transcoder/basisu_transcoder.h" // The output file version. Keep in sync with BASISD_SUPPORTED_BASIS_VERSION. #define BASIS_FILE_VERSION (0x13) diff --git a/encoder/basisu_basis_file.h b/encoder/basisu_basis_file.h index df3abbd..7d9c577 100644 --- a/encoder/basisu_basis_file.h +++ b/encoder/basisu_basis_file.h @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #pragma once -#include "transcoder/basisu_file_headers.h" +#include "../transcoder/basisu_file_headers.h" #include "basisu_backend.h" namespace basisu diff --git a/encoder/basisu_bc7enc.h b/encoder/basisu_bc7enc.h index 0d7a090..3af606f 100644 --- a/encoder/basisu_bc7enc.h +++ b/encoder/basisu_bc7enc.h @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #include "basisu_enc.h" -#include "transcoder/basisu_transcoder_uastc.h" +#include "../transcoder/basisu_transcoder_uastc.h" namespace basisu { diff --git a/encoder/basisu_comp.cpp b/encoder/basisu_comp.cpp index 7f39a66..fdaf3f0 100644 --- a/encoder/basisu_comp.cpp +++ b/encoder/basisu_comp.cpp @@ -202,8 +202,11 @@ namespace basisu const uint32_t first_index = block_index_iter; const uint32_t last_index = minimum(total_blocks, block_index_iter + N); + // FIXME: This sucks, but we're having a stack size related problem with std::function with emscripten. +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job([this, first_index, last_index, num_blocks_x, num_blocks_y, total_blocks, &source_image, &tex, &total_blocks_processed] { +#endif BASISU_NOTE_UNUSED(num_blocks_y); for (uint32_t block_index = first_index; block_index < last_index; block_index++) @@ -228,11 +231,16 @@ namespace basisu } } + +#ifndef __EMSCRIPTEN__ }); +#endif } // block_index_iter +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif if (m_params.m_rdo_uastc) { @@ -412,17 +420,16 @@ namespace basisu m_params.m_swizzle[2] != 2 || m_params.m_swizzle[3] != 3) { - // Apply swizzle to incoming data + // Used for XY normal maps in RG - puts X in color, Y in alpha for (uint32_t y = 0; y < file_image.get_height(); y++) for (uint32_t x = 0; x < file_image.get_width(); x++) { const color_rgba &c = file_image(x, y); file_image(x, y).set_noclamp_rgba(c[m_params.m_swizzle[0]], c[m_params.m_swizzle[1]], c[m_params.m_swizzle[2]], c[m_params.m_swizzle[3]]); } - alpha_swizzled = m_params.m_swizzle[3] != 3; } - + bool has_alpha = false; if (m_params.m_force_alpha || alpha_swizzled) has_alpha = true; @@ -636,14 +643,20 @@ namespace basisu } } - printf("Total basis file slices: %u\n", (uint32_t)m_slice_descs.size()); + if (m_params.m_status_output) + { + printf("Total basis file slices: %u\n", (uint32_t)m_slice_descs.size()); + } for (uint32_t i = 0; i < m_slice_descs.size(); i++) { const basisu_backend_slice_desc &slice_desc = m_slice_descs[i]; - printf("Slice: %u, alpha: %u, orig width/height: %ux%u, width/height: %ux%u, first_block: %u, image_index: %u, mip_level: %u, iframe: %u\n", - i, slice_desc.m_alpha, slice_desc.m_orig_width, slice_desc.m_orig_height, slice_desc.m_width, slice_desc.m_height, slice_desc.m_first_block_index, slice_desc.m_source_file_index, slice_desc.m_mip_index, slice_desc.m_iframe); + if (m_params.m_status_output) + { + printf("Slice: %u, alpha: %u, orig width/height: %ux%u, width/height: %ux%u, first_block: %u, image_index: %u, mip_level: %u, iframe: %u\n", + i, slice_desc.m_alpha, slice_desc.m_orig_width, slice_desc.m_orig_height, slice_desc.m_width, slice_desc.m_height, slice_desc.m_first_block_index, slice_desc.m_source_file_index, slice_desc.m_mip_index, slice_desc.m_iframe); + } if (m_any_source_image_has_alpha) { @@ -1222,7 +1235,6 @@ namespace basisu const uint8_vec& comp_data = m_basis_file.get_compressed_data(); if (m_params.m_write_output_basis_files) { - const std::string& basis_filename = m_params.m_out_filename; if (!write_vec_to_file(basis_filename.c_str(), comp_data)) @@ -1233,6 +1245,7 @@ namespace basisu printf("Wrote output .basis file \"%s\"\n", basis_filename.c_str()); } + size_t comp_size = 0; if ((m_params.m_compute_stats) && (m_params.m_uastc) && (comp_data.size())) { diff --git a/encoder/basisu_comp.h b/encoder/basisu_comp.h index aa77bef..7722e3f 100644 --- a/encoder/basisu_comp.h +++ b/encoder/basisu_comp.h @@ -16,8 +16,8 @@ #include "basisu_frontend.h" #include "basisu_backend.h" #include "basisu_basis_file.h" -#include "transcoder/basisu_global_selector_palette.h" -#include "transcoder/basisu_transcoder.h" +#include "../transcoder/basisu_global_selector_palette.h" +#include "../transcoder/basisu_transcoder.h" #include "basisu_uastc_enc.h" namespace basisu @@ -41,6 +41,10 @@ namespace basisu const uint32_t BASISU_MAX_SLICES = 0xFFFFFF; + const int BASISU_RDO_UASTC_DICT_SIZE_DEFAULT = 32768; + const int BASISU_RDO_UASTC_DICT_SIZE_MIN = 256; + const int BASISU_RDO_UASTC_DICT_SIZE_MAX = 65536; + struct image_stats { image_stats() @@ -181,7 +185,7 @@ namespace basisu T m_max; bool m_changed; }; - + struct basis_compressor_params { basis_compressor_params() : @@ -199,7 +203,7 @@ namespace basisu m_quality_level(-1), m_pack_uastc_flags(cPackUASTCLevelDefault), m_rdo_uastc_quality_scalar(1.0f, 0.001f, 10.0f), - m_rdo_uastc_dict_size(32768, 256, 65536), + m_rdo_uastc_dict_size(BASISU_RDO_UASTC_DICT_SIZE_DEFAULT, BASISU_RDO_UASTC_DICT_SIZE_MIN, BASISU_RDO_UASTC_DICT_SIZE_MAX), m_rdo_uastc_max_allowed_rms_increase_ratio(UASTC_RDO_DEFAULT_MAX_ALLOWED_RMS_INCREASE_RATIO, .01f, 100.0f), m_rdo_uastc_skip_block_rms_thresh(UASTC_RDO_DEFAULT_SKIP_BLOCK_RMS_THRESH, .01f, 100.0f), m_pJob_pool(nullptr) @@ -212,6 +216,7 @@ namespace basisu m_pSel_codebook = NULL; m_uastc.clear(); + m_status_output.clear(); m_source_filenames.clear(); m_source_alpha_filenames.clear(); @@ -298,6 +303,9 @@ namespace basisu // Flip images across Y axis bool_param m_y_flip; + + // If true, the compressor will print basis status to stdout during compression. + bool_param m_status_output; // Output debug information during compression bool_param m_debug; @@ -339,8 +347,8 @@ namespace basisu // Always put alpha slices in the output basis file, even when the input doesn't have alpha bool_param m_force_alpha; bool_param m_multithreading; - - // Swizzle incoming channels + + // Split the R channel to RGB and the G channel to alpha, then write a basis file with alpha channels char m_swizzle[4]; bool_param m_renormalize; @@ -363,7 +371,7 @@ namespace basisu param m_mip_smallest_dimension; // Codebook size (quality) control. - // If m_quality_level != -1, it controls the quality level. It ranges from [0,255]. + // If m_quality_level != -1, it controls the quality level. It ranges from [0,255] or [BASISU_QUALITY_MIN, BASISU_QUALITY_MAX]. // Otherwise m_max_endpoint_clusters/m_max_selector_clusters controls the codebook sizes directly. uint32_t m_max_endpoint_clusters; uint32_t m_max_selector_clusters; diff --git a/encoder/basisu_enc.cpp b/encoder/basisu_enc.cpp index 0c5f883..87b69dc 100644 --- a/encoder/basisu_enc.cpp +++ b/encoder/basisu_enc.cpp @@ -17,7 +17,7 @@ #include "basisu_resampler.h" #include "basisu_resampler_filters.h" #include "basisu_etc.h" -#include "transcoder/basisu_transcoder.h" +#include "../transcoder/basisu_transcoder.h" #include "basisu_bc7enc.h" #include "apg_bmp.h" #include "jpgd.h" @@ -282,38 +282,36 @@ namespace basisu return true; } - - bool load_png(const char* pFilename, image& img) + + bool load_png(const uint8_t *pBuf, size_t buf_size, image &img, const char *pFilename) { - std::vector buffer; - unsigned err = lodepng::load_file(buffer, std::string(pFilename)); - if (err) + if (!buf_size) return false; - unsigned w = 0, h = 0; - - if (sizeof(void *) == sizeof(uint32_t)) + unsigned err = 0, w = 0, h = 0; + + if (sizeof(void*) == sizeof(uint32_t)) { // Inspect the image first on 32-bit builds, to see if the image would require too much memory. lodepng::State state; - err = lodepng_inspect(&w, &h, &state, &buffer[0], buffer.size()); + err = lodepng_inspect(&w, &h, &state, pBuf, buf_size); if ((err != 0) || (!w) || (!h)) return false; const uint32_t exepected_alloc_size = w * h * sizeof(uint32_t); - + // If the file is too large on 32-bit builds then just bail now, to prevent causing a memory exception. if (exepected_alloc_size >= MAX_32BIT_ALLOC_SIZE) { - error_printf("Image \"%s\" is too large (%ux%u) to process in a 32-bit build!\n", pFilename, w, h); + error_printf("Image \"%s\" is too large (%ux%u) to process in a 32-bit build!\n", (pFilename != nullptr) ? pFilename : "", w, h); return false; } - + w = h = 0; } - + std::vector out; - err = lodepng::decode(out, w, h, &buffer[0], buffer.size()); + err = lodepng::decode(out, w, h, pBuf, buf_size); if ((err != 0) || (!w) || (!h)) return false; @@ -326,6 +324,17 @@ namespace basisu return true; } + + bool load_png(const char* pFilename, image& img) + { + std::vector buffer; + unsigned err = lodepng::load_file(buffer, std::string(pFilename)); + if (err) + return false; + + + return load_png(buffer.data(), buffer.size(), img, pFilename); + } bool load_jpg(const char *pFilename, image& img) { @@ -391,7 +400,7 @@ namespace basisu if ((!has_alpha) || ((image_save_flags & cImageSaveIgnoreAlpha) != 0)) { const uint64_t total_bytes = (uint64_t)img.get_width() * 3U * (uint64_t)img.get_height(); - uint8_vec rgb_pixels(total_bytes); + uint8_vec rgb_pixels(static_cast(total_bytes)); uint8_t *pDst = &rgb_pixels[0]; for (uint32_t y = 0; y < img.get_height(); y++) @@ -1464,13 +1473,15 @@ namespace basisu std::unique_lock lock(m_mutex); m_queue.emplace_back(std::move(job)); - + const size_t queue_size = m_queue.size(); lock.unlock(); if (queue_size > 1) + { m_has_work.notify_one(); + } } void job_pool::wait_for_all() diff --git a/encoder/basisu_enc.h b/encoder/basisu_enc.h index 80a8074..58719ad 100644 --- a/encoder/basisu_enc.h +++ b/encoder/basisu_enc.h @@ -13,8 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. #pragma once -#include "transcoder/basisu.h" -#include "transcoder/basisu_transcoder_internal.h" +#include "../transcoder/basisu.h" +#include "../transcoder/basisu_transcoder_internal.h" #include #include @@ -1690,7 +1690,9 @@ namespace basisu for (uint32_t thread_iter = 0; thread_iter < max_threads; thread_iter++) { +#ifndef __EMSCRIPTEN__ pJob_pool->add_job( [thread_iter, &local_clusters, &local_parent_clusters, &success_flags, &quantizers, &initial_codebook, &q, &limit_clusterizers, &max_codebook_size, &max_threads, &max_parent_codebook_size] { +#endif Quantizer& lq = quantizers[thread_iter]; uint_vec& cluster_indices = initial_codebook[thread_iter]; @@ -1731,11 +1733,15 @@ namespace basisu } } +#ifndef __EMSCRIPTEN__ } ); +#endif } // thread_iter +#ifndef __EMSCRIPTEN__ pJob_pool->wait_for_all(); +#endif uint32_t total_clusters = 0, total_parent_clusters = 0; @@ -2856,7 +2862,8 @@ namespace basisu }; // Image saving/loading/resampling - + + bool load_png(const uint8_t* pBuf, size_t buf_size, image& img, const char* pFilename = nullptr); bool load_png(const char* pFilename, image& img); inline bool load_png(const std::string &filename, image &img) { return load_png(filename.c_str(), img); } diff --git a/encoder/basisu_etc.h b/encoder/basisu_etc.h index d8b0468..0c8a7be 100644 --- a/encoder/basisu_etc.h +++ b/encoder/basisu_etc.h @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #pragma once -#include "transcoder/basisu.h" +#include "../transcoder/basisu.h" #include "basisu_enc.h" #include diff --git a/encoder/basisu_frontend.cpp b/encoder/basisu_frontend.cpp index b09aa61..35ad68f 100644 --- a/encoder/basisu_frontend.cpp +++ b/encoder/basisu_frontend.cpp @@ -17,7 +17,7 @@ // This code originally supported full ETC1 and ETC1S, so there's some legacy stuff to be cleaned up in here. // Add endpoint tiling support (where we force adjacent blocks to use the same endpoints during quantization), for a ~10% or more increase in bitrate at same SSIM. The backend already supports this. // -#include "transcoder/basisu.h" +#include "../transcoder/basisu.h" #include "basisu_frontend.h" #include #include @@ -78,6 +78,7 @@ namespace basisu { if (!p.m_pGlobal_sel_codebook) { + debug_printf("basisu_frontend::init: No global sel codebook!\n"); assert(0); return false; } @@ -481,8 +482,10 @@ namespace basisu { const uint32_t first_index = block_index_iter; const uint32_t last_index = minimum(m_total_blocks, first_index + N); - + +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index] { +#endif for (uint32_t block_index = first_index; block_index < last_index; block_index++) { @@ -507,7 +510,7 @@ namespace basisu optimizer.init(optimizer_params, optimizer_results); optimizer.compute(); - + etc_block &blk = m_etc1_blocks_etc1s[block_index]; memset(&blk, 0, sizeof(blk)); @@ -520,10 +523,15 @@ namespace basisu blk.set_selector(x, y, selectors[x + y * 4]); } +#ifndef __EMSCRIPTEN__ } ); +#endif + } - + +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif } void basisu_frontend::init_endpoint_training_vectors() @@ -540,7 +548,9 @@ namespace basisu const uint32_t first_index = block_index_iter; const uint32_t last_index = minimum(m_total_blocks, first_index + N); +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index, &training_vecs] { +#endif for (uint32_t block_index = first_index; block_index < last_index; block_index++) { @@ -562,11 +572,15 @@ namespace basisu } // block_index; +#ifndef __EMSCRIPTEN__ } ); +#endif } // block_index_iter +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif } void basisu_frontend::generate_endpoint_clusters() @@ -707,7 +721,9 @@ namespace basisu const uint32_t first_index = cluster_index_iter; const uint32_t last_index = minimum((uint32_t)m_endpoint_clusters.size(), cluster_index_iter + N); +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index] { +#endif for (uint32_t cluster_index = first_index; cluster_index < last_index; cluster_index++) { @@ -775,10 +791,15 @@ namespace basisu } } // cluster_index +#ifndef __EMSCRIPTEN__ } ); +#endif + } // cluster_index_iter +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif vector_sort(m_subblock_endpoint_quant_err_vec); } @@ -893,8 +914,10 @@ namespace basisu { const uint32_t first_index = cluster_index_iter; const uint32_t last_index = minimum((uint32_t)m_endpoint_clusters.size(), cluster_index_iter + N); - + +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index, step ] { +#endif for (uint32_t cluster_index = first_index; cluster_index < last_index; cluster_index++) { @@ -1012,11 +1035,15 @@ namespace basisu } // cluster_index +#ifndef __EMSCRIPTEN__ } ); +#endif } // cluster_index_iter +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif } bool basisu_frontend::check_etc1s_constraints() const @@ -1081,7 +1108,9 @@ namespace basisu const uint32_t first_index = block_index_iter; const uint32_t last_index = minimum(m_total_blocks, first_index + N); +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index, &best_cluster_indices, &block_clusters] { +#endif for (uint32_t block_index = first_index; block_index < last_index; block_index++) { @@ -1154,12 +1183,16 @@ namespace basisu best_cluster_indices[block_index] = best_cluster_index; } // block_index - + +#ifndef __EMSCRIPTEN__ } ); +#endif } // block_index_iter - + +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif std::vector > optimized_endpoint_clusters(m_endpoint_clusters.size()); uint32_t total_subblocks_reassigned = 0; @@ -1264,7 +1297,9 @@ namespace basisu const uint32_t first_index = block_index_iter; const uint32_t last_index = minimum(m_total_blocks, first_index + N); +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index] { +#endif for (uint32_t block_index = first_index; block_index < last_index; block_index++) { @@ -1288,12 +1323,16 @@ namespace basisu blk.determine_selectors(pSource_pixels, m_params.m_perceptual); } // block_index - + +#ifndef __EMSCRIPTEN__ } ); +#endif } // block_index_iter +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif m_orig_encoded_blocks = m_encoded_blocks; } @@ -1355,7 +1394,9 @@ namespace basisu const uint32_t first_index = block_index_iter; const uint32_t last_index = minimum(m_total_blocks, first_index + N); +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index, &training_vecs] { +#endif for (uint32_t block_index = first_index; block_index < last_index; block_index++) { @@ -1382,11 +1423,15 @@ namespace basisu } // block_index +#ifndef __EMSCRIPTEN__ } ); +#endif } // block_index_iter +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif vec16F_clusterizer selector_clusterizer; for (uint32_t i = 0; i < m_total_blocks; i++) @@ -1474,8 +1519,10 @@ namespace basisu { const uint32_t first_index = cluster_index_iter; const uint32_t last_index = minimum((uint32_t)total_selector_clusters, cluster_index_iter + N); - + +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index, &total_clusters_processed, &total_selector_clusters] { +#endif for (uint32_t cluster_index = first_index; cluster_index < last_index; cluster_index++) { @@ -1528,11 +1575,15 @@ namespace basisu } // cluster_index +#ifndef __EMSCRIPTEN__ } ); +#endif } // cluster_index_iter +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif } else { @@ -1552,8 +1603,10 @@ namespace basisu { const uint32_t first_index = cluster_index_iter; const uint32_t last_index = minimum((uint32_t)total_selector_clusters, cluster_index_iter + N); - + +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index, &uses_hybrid_sel_codebook, &total_clusters_processed, &total_selector_clusters] { +#endif for (uint32_t cluster_index = first_index; cluster_index < last_index; cluster_index++) { @@ -1667,11 +1720,15 @@ namespace basisu } // cluster_index +#ifndef __EMSCRIPTEN__ } ); +#endif } // cluster_index_iter +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif } // if (m_params.m_pGlobal_sel_codebook) @@ -1741,7 +1798,9 @@ namespace basisu const uint32_t first_index = block_index_iter; const uint32_t last_index = minimum(m_total_blocks, first_index + N); +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index, &new_cluster_indices] { +#endif for (uint32_t block_index = first_index; block_index < last_index; block_index++) { @@ -1804,11 +1863,15 @@ namespace basisu } // block_index +#ifndef __EMSCRIPTEN__ } ); +#endif } // block_index_iter - + +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif m_selector_cluster_indices.swap(new_cluster_indices); } @@ -2112,8 +2175,11 @@ namespace basisu { const uint32_t first_index = cluster_index_iter; const uint32_t last_index = minimum((uint32_t)new_endpoint_cluster_block_indices.size(), cluster_index_iter + N); - + +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->add_job( [this, first_index, last_index, &cluster_improved, &cluster_valid, &new_endpoint_cluster_block_indices, &pBlock_selector_indices ] { +#endif + for (uint32_t cluster_index = first_index; cluster_index < last_index; cluster_index++) { const std::vector& cluster_block_indices = new_endpoint_cluster_block_indices[cluster_index]; @@ -2198,11 +2264,16 @@ namespace basisu cluster_valid[cluster_index] = true; } // cluster_index + +#ifndef __EMSCRIPTEN__ } ); +#endif } // cluster_index_iter +#ifndef __EMSCRIPTEN__ m_params.m_pJob_pool->wait_for_all(); +#endif uint32_t total_unused_clusters = 0; uint32_t total_improved_clusters = 0; diff --git a/encoder/basisu_frontend.h b/encoder/basisu_frontend.h index e4ccf14..e5f7954 100644 --- a/encoder/basisu_frontend.h +++ b/encoder/basisu_frontend.h @@ -17,7 +17,7 @@ #include "basisu_etc.h" #include "basisu_gpu_texture.h" #include "basisu_global_selector_palette_helpers.h" -#include "transcoder/basisu_file_headers.h" +#include "../transcoder/basisu_file_headers.h" namespace basisu { diff --git a/encoder/basisu_global_selector_palette_helpers.h b/encoder/basisu_global_selector_palette_helpers.h index 32692c5..9e9cdbd 100644 --- a/encoder/basisu_global_selector_palette_helpers.h +++ b/encoder/basisu_global_selector_palette_helpers.h @@ -14,9 +14,9 @@ // limitations under the License. #pragma once -#include "transcoder/basisu.h" +#include "../transcoder/basisu.h" #include "basisu_etc.h" -#include "transcoder/basisu_global_selector_palette.h" +#include "../transcoder/basisu_global_selector_palette.h" namespace basisu { diff --git a/encoder/basisu_gpu_texture.h b/encoder/basisu_gpu_texture.h index 7cf2b41..7ca9272 100644 --- a/encoder/basisu_gpu_texture.h +++ b/encoder/basisu_gpu_texture.h @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #pragma once -#include "transcoder/basisu.h" +#include "../transcoder/basisu.h" #include "basisu_etc.h" namespace basisu diff --git a/encoder/basisu_resample_filters.cpp b/encoder/basisu_resample_filters.cpp index 39df8bd..c0adb13 100644 --- a/encoder/basisu_resample_filters.cpp +++ b/encoder/basisu_resample_filters.cpp @@ -310,10 +310,22 @@ namespace basisu const resample_filter g_resample_filters[] = { - { "box", box_filter, BOX_FILTER_SUPPORT }, { "tent", tent_filter, TENT_FILTER_SUPPORT }, { "bell", bell_filter, BELL_SUPPORT }, { "b-spline", B_spline_filter, B_SPLINE_SUPPORT }, - { "mitchell", mitchell_filter, MITCHELL_SUPPORT }, { "lanczos3", lanczos3_filter, LANCZOS3_SUPPORT }, { "blackman", blackman_filter, BLACKMAN_SUPPORT }, { "lanczos4", lanczos4_filter, LANCZOS4_SUPPORT }, - { "lanczos6", lanczos6_filter, LANCZOS6_SUPPORT }, { "lanczos12", lanczos12_filter, LANCZOS12_SUPPORT }, { "kaiser", kaiser_filter, KAISER_SUPPORT }, { "gaussian", gaussian_filter, GAUSSIAN_SUPPORT }, - { "catmullrom", catmull_rom_filter, CATMULL_ROM_SUPPORT }, { "quadratic_interp", quadratic_interp_filter, QUADRATIC_SUPPORT }, { "quadratic_approx", quadratic_approx_filter, QUADRATIC_SUPPORT }, { "quadratic_mix", quadratic_mix_filter, QUADRATIC_SUPPORT }, + { "box", box_filter, BOX_FILTER_SUPPORT }, + { "tent", tent_filter, TENT_FILTER_SUPPORT }, + { "bell", bell_filter, BELL_SUPPORT }, + { "b-spline", B_spline_filter, B_SPLINE_SUPPORT }, + { "mitchell", mitchell_filter, MITCHELL_SUPPORT }, + { "blackman", blackman_filter, BLACKMAN_SUPPORT }, + { "lanczos3", lanczos3_filter, LANCZOS3_SUPPORT }, + { "lanczos4", lanczos4_filter, LANCZOS4_SUPPORT }, + { "lanczos6", lanczos6_filter, LANCZOS6_SUPPORT }, + { "lanczos12", lanczos12_filter, LANCZOS12_SUPPORT }, + { "kaiser", kaiser_filter, KAISER_SUPPORT }, + { "gaussian", gaussian_filter, GAUSSIAN_SUPPORT }, + { "catmullrom", catmull_rom_filter, CATMULL_ROM_SUPPORT }, + { "quadratic_interp", quadratic_interp_filter, QUADRATIC_SUPPORT }, + { "quadratic_approx", quadratic_approx_filter, QUADRATIC_SUPPORT }, + { "quadratic_mix", quadratic_mix_filter, QUADRATIC_SUPPORT }, }; const int g_num_resample_filters = BASISU_ARRAY_SIZE(g_resample_filters); diff --git a/encoder/basisu_resampler.h b/encoder/basisu_resampler.h index c3f2e05..dc0978c 100644 --- a/encoder/basisu_resampler.h +++ b/encoder/basisu_resampler.h @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. #pragma once -#include "transcoder/basisu.h" +#include "../transcoder/basisu.h" #define BASISU_RESAMPLER_DEBUG_OPS (0) #define BASISU_RESAMPLER_DEFAULT_FILTER "lanczos4" diff --git a/encoder/basisu_resampler_filters.h b/encoder/basisu_resampler_filters.h index 5659c5f..0ebb51c 100644 --- a/encoder/basisu_resampler_filters.h +++ b/encoder/basisu_resampler_filters.h @@ -14,7 +14,7 @@ // limitations under the License. #pragma once -#include "transcoder/basisu.h" +#include "../transcoder/basisu.h" namespace basisu { diff --git a/encoder/basisu_uastc_enc.cpp b/encoder/basisu_uastc_enc.cpp index c4fb9eb..9b75b84 100644 --- a/encoder/basisu_uastc_enc.cpp +++ b/encoder/basisu_uastc_enc.cpp @@ -3098,6 +3098,11 @@ namespace basisu void encode_uastc(const uint8_t* pRGBAPixels, uastc_block& output_block, uint32_t flags) { +// printf("encode_uastc: \n"); +// for (int i = 0; i < 16; i++) +// printf("[%u %u %u %u] ", pRGBAPixels[i * 4 + 0], pRGBAPixels[i * 4 + 1], pRGBAPixels[i * 4 + 2], pRGBAPixels[i * 4 + 3]); +// printf("\n"); + const color_rgba(*block)[4] = reinterpret_cast(pRGBAPixels); bool solid_color = true, has_alpha = false, is_la = true; @@ -3139,6 +3144,8 @@ namespace basisu pack_uastc(output_block, solid_results, etc1_blk, etc1_bias, eac_a8_blk, false, false); +// printf(" Solid\n"); + return; } @@ -3594,7 +3601,13 @@ namespace basisu // Finally, pack the UASTC block with its hints and we're done. pack_uastc(output_block, best_results, etc1_blk, etc1_bias, eac_a8_blk, bc1_hint0, bc1_hint1); + +// printf(" Packed: "); +// for (int i = 0; i < 16; i++) +// printf("%X ", output_block.m_bytes[i]); +// printf("\n"); } + static bool uastc_recompute_hints(basist::uastc_block* pBlock, const color_rgba* pBlock_pixels, uint32_t flags, const unpacked_uastc_block *pUnpacked_blk) { unpacked_uastc_block unpacked_blk; @@ -3761,7 +3774,7 @@ namespace basisu { std::size_t operator()(selector_bitsequence const& s) const noexcept { - return hash_hsieh((uint8_t *)&s, sizeof(s)) ^ s.m_sel; + return static_cast(hash_hsieh((uint8_t *)&s, sizeof(s)) ^ s.m_sel); } }; @@ -4053,7 +4066,9 @@ namespace basisu const uint32_t first_index = block_index_iter; const uint32_t last_index = minimum(num_blocks, block_index_iter + blocks_per_job); +#ifndef __EMSCRIPTEN__ pJob_pool->add_job([first_index, last_index, pBlocks, pBlock_pixels, ¶ms, flags, &total_skipped, &total_modified, &total_refined, &all_succeeded, &stat_mutex] { +#endif uint32_t job_skipped = 0, job_modified = 0, job_refined = 0; @@ -4068,11 +4083,16 @@ namespace basisu total_refined += job_refined; } +#ifndef __EMSCRIPTEN__ } ); +#endif + } // block_index_iter +#ifndef __EMSCRIPTEN__ pJob_pool->wait_for_all(); +#endif status = all_succeeded; } diff --git a/encoder/basisu_uastc_enc.h b/encoder/basisu_uastc_enc.h index 0ccad7d..eeb2525 100644 --- a/encoder/basisu_uastc_enc.h +++ b/encoder/basisu_uastc_enc.h @@ -15,7 +15,7 @@ #pragma once #include "basisu_etc.h" -#include "transcoder/basisu_transcoder_uastc.h" +#include "../transcoder/basisu_transcoder_uastc.h" namespace basisu { diff --git a/transcoder/basisu_transcoder.cpp b/transcoder/basisu_transcoder.cpp index 9366f0a..a77bb82 100644 --- a/transcoder/basisu_transcoder.cpp +++ b/transcoder/basisu_transcoder.cpp @@ -9577,7 +9577,7 @@ namespace basist 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, - bool basis_file_has_alpha_slices, + bool has_alpha, bool is_video, uint32_t output_row_pitch_in_blocks_or_pixels, basisu_transcoder_state* pState, @@ -9603,7 +9603,7 @@ namespace basist } } - if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA) && (!basis_file_has_alpha_slices)) + if ((target_format == transcoder_texture_format::cTFPVRTC1_4_RGBA) && (!has_alpha)) { // Switch to PVRTC1 RGB if the input doesn't have alpha. target_format = transcoder_texture_format::cTFPVRTC1_4_RGB; @@ -9628,7 +9628,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC1, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1); if (!status) { @@ -9640,7 +9640,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_RGBA, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC2_RGBA, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to ETC2 failed\n"); @@ -9652,7 +9652,7 @@ namespace basist // TODO: ETC1S allows BC1 from alpha channel. That doesn't seem actually useful, though. //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC1, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC1, - bytes_per_block_or_pixel, true, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1); + bytes_per_block_or_pixel, true, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC1 failed\n"); @@ -9663,7 +9663,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC3, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC3, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, channel0, channel1); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC3 failed\n"); @@ -9674,10 +9674,10 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC4, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState, // nullptr, 0, - // ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0); + // ((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC4, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, - ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, + ((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC4 failed\n"); @@ -9690,7 +9690,7 @@ namespace basist // nullptr, 0, // 0, 3); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC5, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, 0, 3); if (!status) { @@ -9703,7 +9703,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBC7, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBC7, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to BC7 failed\n"); @@ -9714,7 +9714,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGB, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cPVRTC1_4_RGB, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to PVRTC1 RGB 4bpp failed\n"); @@ -9725,7 +9725,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cPVRTC1_4_RGBA, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cPVRTC1_4_RGBA, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to PVRTC1 RGBA 4bpp failed\n"); @@ -9736,7 +9736,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cASTC_4x4, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cASTC_4x4, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to ASTC 4x4 failed\n"); @@ -9768,10 +9768,10 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cETC2_EAC_R11, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState, // nullptr, 0, - // ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0); + // ((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC2_EAC_R11, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, - ((basis_file_has_alpha_slices) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, + ((has_alpha) && (transcode_alpha_data_to_opaque_formats)) ? 3 : 0); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to EAC R11 failed\n"); @@ -9784,7 +9784,7 @@ namespace basist // nullptr, 0, // 0, 3); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cETC2_EAC_RG11, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels, 0, 3); if (!status) { @@ -9796,7 +9796,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGBA32, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cRGBA32, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGBA32 failed\n"); @@ -9807,7 +9807,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGB565, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cRGB565, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGB565 failed\n"); @@ -9818,7 +9818,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cBGR565, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cBGR565, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGB565 failed\n"); @@ -9829,7 +9829,7 @@ namespace basist { //status = transcode_slice(pData, data_size, slice_index, pOutput_blocks, output_blocks_buf_size_in_blocks_or_pixels, block_format::cRGBA4444, bytes_per_block_or_pixel, decode_flags, output_row_pitch_in_blocks_or_pixels, pState); status = transcode_slice(pOutput_blocks, num_blocks_x, num_blocks_y, pCompressed_data + slice_offset, slice_length, block_format::cRGBA4444, - bytes_per_block_or_pixel, false, basis_file_has_alpha_slices, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); + bytes_per_block_or_pixel, false, has_alpha, orig_width, orig_height, output_row_pitch_in_blocks_or_pixels, pState, output_rows_in_pixels); if (!status) { BASISU_DEVEL_ERROR("basisu_lowlevel_uastc_transcoder::transcode_image: transcode_slice() to RGBA4444 failed\n"); @@ -10239,6 +10239,21 @@ namespace basist image_info.m_total_blocks = image_info.m_num_blocks_x * image_info.m_num_blocks_y; image_info.m_first_slice_index = slice_index; + image_info.m_rgb_file_ofs = slice_desc.m_file_ofs; + image_info.m_rgb_file_len = slice_desc.m_file_size; + image_info.m_alpha_file_ofs = 0; + image_info.m_alpha_file_len = 0; + + if (pHeader->m_tex_format == (int)basis_tex_format::cETC1S) + { + if (pHeader->m_flags & cBASISHeaderFlagHasAlphaSlices) + { + assert((slice_index + 1) < (int)pHeader->m_total_slices); + image_info.m_alpha_file_ofs = pSlice_descs[slice_index + 1].m_file_ofs; + image_info.m_alpha_file_len = pSlice_descs[slice_index + 1].m_file_size; + } + } + return true; } @@ -10258,11 +10273,14 @@ namespace basist file_info.m_total_header_size = sizeof(basis_file_header) + pHeader->m_total_slices * sizeof(basis_slice_desc); file_info.m_total_selectors = pHeader->m_total_selectors; + file_info.m_selector_codebook_ofs = pHeader->m_selector_cb_file_ofs; file_info.m_selector_codebook_size = pHeader->m_selector_cb_file_size; file_info.m_total_endpoints = pHeader->m_total_endpoints; + file_info.m_endpoint_codebook_ofs = pHeader->m_endpoint_cb_file_ofs; file_info.m_endpoint_codebook_size = pHeader->m_endpoint_cb_file_size; + file_info.m_tables_ofs = pHeader->m_tables_file_ofs; file_info.m_tables_size = pHeader->m_tables_file_size; file_info.m_tex_format = static_cast(static_cast(pHeader->m_tex_format)); @@ -12454,7 +12472,12 @@ namespace basist bits = read_bits64(blk.m_bytes, bit_ofs, std::min(64, 128 - (int)bit_ofs)); else { +#ifdef __EMSCRIPTEN__ + bits = blk.m_dwords[2]; + bits |= (((uint64_t)blk.m_dwords[3]) << 32U); +#else bits = blk.m_qwords[1]; +#endif if (bit_ofs >= 64U) bits >>= (bit_ofs - 64U); diff --git a/transcoder/basisu_transcoder.h b/transcoder/basisu_transcoder.h index 41e7c39..a58ca08 100644 --- a/transcoder/basisu_transcoder.h +++ b/transcoder/basisu_transcoder.h @@ -280,7 +280,7 @@ namespace basist 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 basis_file_has_alpha_slices = false, + bool has_alpha = false, bool is_video = false, uint32_t output_row_pitch_in_blocks_or_pixels = 0, basisu_transcoder_state* pState = nullptr, @@ -351,6 +351,11 @@ namespace basist uint32_t m_total_blocks; uint32_t m_first_slice_index; + + uint32_t m_rgb_file_ofs; + uint32_t m_rgb_file_len; + uint32_t m_alpha_file_ofs; + uint32_t m_alpha_file_len; bool m_alpha_flag; // true if the image has alpha data bool m_iframe_flag; // true if the image is an I-Frame @@ -362,12 +367,16 @@ namespace basist uint32_t m_total_header_size; uint32_t m_total_selectors; + uint32_t m_selector_codebook_ofs; uint32_t m_selector_codebook_size; uint32_t m_total_endpoints; + uint32_t m_endpoint_codebook_ofs; uint32_t m_endpoint_codebook_size; + uint32_t m_tables_ofs; uint32_t m_tables_size; + uint32_t m_slices_size; basis_texture_type m_tex_type; diff --git a/transcoder/basisu_transcoder_uastc.h b/transcoder/basisu_transcoder_uastc.h index 7d520dc..d501a2a 100644 --- a/transcoder/basisu_transcoder_uastc.h +++ b/transcoder/basisu_transcoder_uastc.h @@ -205,7 +205,10 @@ namespace basist { uint8_t m_bytes[16]; uint32_t m_dwords[4]; + +#ifndef __EMSCRIPTEN__ uint64_t m_qwords[2]; +#endif }; }; diff --git a/webgl/index.html b/webgl/index.html index 4273e04..cfb482e 100644 --- a/webgl/index.html +++ b/webgl/index.html @@ -11,5 +11,6 @@

diff --git a/webgl/texture/index.html b/webgl/texture/index.html index b0d7473..b346ece 100644 --- a/webgl/texture/index.html +++ b/webgl/texture/index.html @@ -103,6 +103,7 @@ COMPRESSED_RGB_ETC1_WEBGL = 0x8D64; COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00; COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02; +// Same as the Module.transcoder_texture_format enum BASIS_FORMAT = { cTFETC1: 0, cTFETC2: 1, @@ -120,6 +121,11 @@ BASIS_FORMAT = { cTFRGB565: 14, cTFBGR565: 15, cTFRGBA4444: 16, + cTFFXT1_RGB: 17, + cTFPVRTC2_4_RGB: 18, + cTFPVRTC2_4_RGBA: 19, + cTFETC2_EAC_R11: 20, + cTFETC2_EAC_RG11: 21 }; BASIS_FORMAT_NAMES = {}; @@ -149,6 +155,61 @@ function redraw() renderer.drawTexture(tex, displayWidth, displayHeight, drawMode); } +function dumpBasisFileDesc(basisFile) +{ + var basisFileDesc = basisFile.getFileDesc(); + + log('------'); + log('getFileDesc():'); + log('version: ' + basisFileDesc.version); + log('us per frame: ' + basisFileDesc.usPerFrame); + log('total images: ' + basisFileDesc.totalImages); + log('userdata0: ' + basisFileDesc.userdata0 + ' userdata1: ' + basisFileDesc.userdata1); + log('texFormat: ' + basisFileDesc.texFormat); + log('yFlipped: ' + basisFileDesc.yFlipped + ' hasAlphaSlices: ' + basisFileDesc.hasAlphaSlices); + + if (basisFileDesc.texFormat == Module.basis_tex_format.cETC1S.value) + { + log('numEndpoints: ' + basisFileDesc.numEndpoints); + log('endpointPaletteOfs: ' + basisFileDesc.endpointPaletteOfs); + log('endpointPaletteLen: ' + basisFileDesc.endpointPaletteLen); + log('numSelectors: ' + basisFileDesc.numSelectors); + log('selectorPaletteOfs: ' + basisFileDesc.selectorPaletteOfs); + log('selectorPaletteLen: ' + basisFileDesc.selectorPaletteLen); + log('tablesOfs: ' + basisFileDesc.tablesOfs); + log('tablesLen: ' + basisFileDesc.tablesLen); + } + log('------'); + log('getImageDesc() for all images:'); + var image_index; + for (image_index = 0; image_index < basisFileDesc.totalImages; image_index++) + { + log('image: ' + image_index); + + var basisImageDesc = basisFile.getImageDesc(image_index); + + log('origWidth: ' + basisImageDesc.origWidth + ' origWidth: ' + basisImageDesc.origHeight); + log('numBlocksX: ' + basisImageDesc.numBlocksX + ' origWidth: ' + basisImageDesc.numBlocksY); + log('numLevels: ' + basisImageDesc.numLevels); + log('alphaFlag: ' + basisImageDesc.alphaFlag + ' iframeFlag: ' + basisImageDesc.iframeFlag); + + log('getImageLevelDesc() for all mipmap levels:'); + var level_index; + for (level_index = 0; level_index < basisImageDesc.numLevels; level_index++) + { + var basisImageLevelDesc = basisFile.getImageLevelDesc(image_index, level_index); + + log('level: ' + level_index + + ' rgb_file_offset: ' + basisImageLevelDesc.rgbFileOfs + ' rgb_file_len: ' + basisImageLevelDesc.rgbFileLen); + + if (basisFileDesc.hasAlphaSlices) + log('alpha_file_offset: ' + basisImageLevelDesc.alphaFileOfs + ' alpha_file_len: ' + basisImageLevelDesc.alphaFileLen); + } + } + + log('------'); +} + function dataLoaded(data) { log('Done loading .basis file, decoded header:'); @@ -165,7 +226,9 @@ function dataLoaded(data) images = basisFile.getNumImages(); levels = basisFile.getNumLevels(0); has_alpha = basisFile.getHasAlpha(); - + + dumpBasisFileDesc(basisFile); + if (!width || !height || !images || !levels) { console.warn('Invalid .basis file'); basisFile.close(); @@ -237,6 +300,8 @@ function dataLoaded(data) } elem('format').innerText = formatString; + + log('format: ' + format); if (!basisFile.startTranscoding()) { log('startTranscoding failed'); @@ -245,20 +310,146 @@ function dataLoaded(data) basisFile.delete(); return; } - + + const isUncompressedFormat = Module.formatIsUncompressed(format); + + const blockWidth = isUncompressedFormat ? 1 : 4, blockHeight = isUncompressedFormat ? 1 : 4; + + const bytesPerBlockOrPixel = Module.getBytesPerBlockOrPixel(format); + log('isUncompressedFormat: ' + isUncompressedFormat + ' bytesPerBlockOrPixel: ' + bytesPerBlockOrPixel); + const dstSize = basisFile.getImageTranscodedSizeInBytes(0, 0, format); const dst = new Uint8Array(dstSize); - log(dstSize); +// log('getImageTranscodedSizeInBytes() returned ' + dstSize); -// if (!basisFile.transcodeImage(dst, 0, 0, format, 1, 0)) { - if (!basisFile.transcodeImage(dst, 0, 0, format, 0, 0)) { - log('basisFile.transcodeImage failed'); - console.warn('transcodeImage failed'); - basisFile.close(); - basisFile.delete(); - - return; + // Use the low or high level transcoding API's. The high level API's require .basis files, while the low-level API's just work off blobs of memory and parameters. + if (elem('ContainerIndependentTranscoding').checked) + { + // Always transcode the first image and the first mipmap level + const image_index = 0; + const level_index = 0; + + // Get the .basis file description + var basisFileDesc = basisFile.getFileDesc(); + + // Get the description of the file's first image (there could be multiple images, for texture arrays or videos) + var basisImageDesc = basisFile.getImageDesc(image_index); + + // Get the description of this image's mipmap level + var basisImageLevelDesc = basisFile.getImageLevelDesc(image_index, level_index); + + var status = false; + + // If we're transcoding to ETC1S, use the LowLevelETC1SImageTranscoder class. Otherwise use the transcodeUASTCImage() function. + if (basisFileDesc.texFormat == Module.basis_tex_format.cETC1S.value) + { + // Create an instance of the LowLevelETC1SImageTranscoder class. + const etc1s_transcoder = new Module.LowLevelETC1SImageTranscoder(); + + // Create Uint8Array's pointing into the various bits of the .basis file holding the compressed data for the codebooks and the Huffman tables. + var selectorPalette = new Uint8Array(data, basisFileDesc.selectorPaletteOfs, basisFileDesc.selectorPaletteLen); + var endpointPalette = new Uint8Array(data, basisFileDesc.endpointPaletteOfs, basisFileDesc.endpointPaletteLen); + var tables = new Uint8Array(data, basisFileDesc.tablesOfs, basisFileDesc.tablesLen); + + // Create a Uint8Array pointing to the image's compressed data. + // If it's an opaque .basis file, there will only be RGB data. For transparant .basis files, each RGB slice will be immediately followed by an alpha slice. + // Compressed ETC1S alpha data is guaranteed to immediately follow the RGB data (it's always at odd slices in the .basis file). + var compData = new Uint8Array(data, basisImageLevelDesc.rgbFileOfs, basisImageLevelDesc.rgbFileLen + basisImageLevelDesc.alphaFileLen); + + // Decompress the palettes. This only has to be done once for each .basis file. + var status = etc1s_transcoder.decodePalettes(basisFileDesc.numEndpoints, endpointPalette, basisFileDesc.numSelectors, selectorPalette); + if (status) + { + // Decompress the Huffman tables. This only has to be done once for each .basis file. + status = etc1s_transcoder.decodeTables(tables); + if (status) + { + // Now transcode the image using the container independent transcode API. This API does not interpret any .basis file structures - only the compressed ETC1S data. + status = etc1s_transcoder.transcodeImage( + format, + dst, dstSize / bytesPerBlockOrPixel, + compData, + basisImageDesc.numBlocksX, basisImageDesc.numBlocksY, basisImageDesc.origWidth, basisImageDesc.origHeight, level_index, + 0, basisImageLevelDesc.rgbFileLen, basisFileDesc.hasAlphaSlices ? basisImageLevelDesc.rgbFileLen : 0, basisImageLevelDesc.alphaFileLen, + 0, + basisFileDesc.hasAlphaSlices, + basisFileDesc.isVideo, + 0, + 0); + + if (!status) + log('transcodeImage() failed'); + } + else + { + log('decodeTables() failed'); + } + } + else + { + log('decodePalettes() failed'); + } + + etc1s_transcoder.delete(); + + if (!status) + { + log('etc1s_transcoder failed'); + console.warn('etc1s_transcoder failed'); + basisFile.close(); + basisFile.delete(); + return; + } + else + { + log('Successfully called etc1s_transcoder.transcodeImage()'); + } + } + else + { + // Create a Uint8Array pointing to the image's compressed data. + var compData = new Uint8Array(data, basisImageLevelDesc.rgbFileOfs, basisImageLevelDesc.rgbFileLen); + + // Transcode the UASTC texture data to the desired output format. + status = Module.transcodeUASTCImage( + format, + dst, dstSize / bytesPerBlockOrPixel, + compData, + basisImageDesc.numBlocksX, basisImageDesc.numBlocksY, basisImageDesc.origWidth, basisImageDesc.origHeight, level_index, + 0, basisImageLevelDesc.rgbFileLen, + 0, + basisFileDesc.hasAlphaSlices, + basisFileDesc.isVideo, + 0, + 0, + -1, -1); + + if (!status) + { + log('transcodeUASTCImage() failed'); + console.warn('transcodeUASTCImage() failed'); + basisFile.close(); + basisFile.delete(); + return; + } + else + { + log('Successfully called transcodeUASTCImage()'); + } + } + } + else + { + // Use the high-level transcode API, which requires a .basis file. + if (!basisFile.transcodeImage(dst, 0, 0, format, 0, 0)) { + log('basisFile.transcodeImage failed'); + console.warn('transcodeImage failed'); + basisFile.close(); + basisFile.delete(); + + return; + } } const elapsed = performance.now() - startTime; @@ -347,13 +538,18 @@ function viewAlpha() { drawMode = 2; redraw(); }

.basis file: - +

+ +
+
+ Use Container Independent Transcoding API's: +