diff --git a/.gitignore b/.gitignore
index 6766a52..2c3281d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
__pycache__
Binaries
Source/*.o
+Source/*.so
Source/astcenc-*
Source/astcenc-*
Source/VS2019/*Release
@@ -14,3 +15,5 @@ Test/DocOut
Test/Images/Kodak
Test/Images/Scratch*
TestOutput
+Docs/LibraryInterface.md
+Docs/Profiling.md
diff --git a/Source/Makefile b/Source/Makefile
index 9d62421..ec5c74d 100644
--- a/Source/Makefile
+++ b/Source/Makefile
@@ -33,35 +33,37 @@ VEC?=avx2
DBG?=0
SOURCES = \
- astc_averages_and_directions.cpp \
- astc_block_sizes2.cpp \
- astc_color_quantize.cpp \
- astc_color_unquantize.cpp \
- astc_compress_symbolic.cpp \
- astc_compute_variance.cpp \
- astc_decompress_symbolic.cpp \
- astc_encoding_choice_error.cpp \
- astc_error_metrics.cpp \
- astc_find_best_partitioning.cpp \
- astc_ideal_endpoints_and_weights.cpp \
- astc_image.cpp \
- astc_image_load_store.cpp \
- astc_integer_sequence.cpp \
- astc_kmeans_partitioning.cpp \
- astc_main.cpp \
- astc_mathlib.cpp \
- astc_mathlib_softfloat.cpp \
- astc_partition_tables.cpp \
- astc_percentile_tables.cpp \
- astc_pick_best_endpoint_format.cpp \
- astc_platform_isa_detection.cpp \
- astc_platform_dependents.cpp \
- astc_quantization.cpp \
- astc_symbolic_physical.cpp \
- astc_toplevel.cpp \
- astc_toplevel_help.cpp \
- astc_weight_align.cpp \
- astc_weight_quant_xfer_tables.cpp
+ astcenc_averages_and_directions.cpp \
+ astcenc_block_sizes2.cpp \
+ astcenc_color_quantize.cpp \
+ astcenc_color_unquantize.cpp \
+ astcenc_compress_symbolic.cpp \
+ astcenc_compute_variance.cpp \
+ astcenc_decompress_symbolic.cpp \
+ astcenc_encoding_choice_error.cpp \
+ astcenc_entry.cpp \
+ astcenc_find_best_partitioning.cpp \
+ astcenc_ideal_endpoints_and_weights.cpp \
+ astcenc_image.cpp \
+ astcenc_integer_sequence.cpp \
+ astcenc_kmeans_partitioning.cpp \
+ astcenc_mathlib.cpp \
+ astcenc_mathlib_softfloat.cpp \
+ astcenc_partition_tables.cpp \
+ astcenc_percentile_tables.cpp \
+ astcenc_pick_best_endpoint_format.cpp \
+ astcenc_platform_dependents.cpp \
+ astcenc_platform_isa_detection.cpp \
+ astcenc_quantization.cpp \
+ astcenc_symbolic_physical.cpp \
+ astcenc_weight_align.cpp \
+ astcenc_weight_quant_xfer_tables.cpp \
+ astcenccli_error_metrics.cpp \
+ astcenccli_image.cpp \
+ astcenccli_image_load_store.cpp \
+ astcenccli_platform_dependents.cpp \
+ astcenccli_toplevel.cpp \
+ astcenccli_toplevel_help.cpp
EXTERNAL_SOURCES = \
stb_image.h \
@@ -69,8 +71,10 @@ EXTERNAL_SOURCES = \
tinyexr.h
HEADERS = \
- astc_codec_internals.h \
- astc_mathlib.h \
+ astcenc.h \
+ astcenc_internal.h \
+ astcenc_mathlib.h \
+ astcenccli_internal.h \
stb_image.h \
stb_image_write.h \
tinyexr.h
@@ -81,28 +85,28 @@ EXTERNAL_OBJECTS = $(EXTERNAL_SOURCES:.h=-$(VEC).o)
BINARY = astcenc-$(VEC)
-CXXFLAGS = -std=c++14 -mfpmath=sse \
+CXXFLAGS = -std=c++14 -fvisibility=hidden -mfpmath=sse \
-Wall -Wextra -Wpedantic -Werror -Werror=shadow -Wdouble-promotion
# Validate that the DBG parameter is a supported value, and patch CXXFLAGS
ifeq ($(DBG),0)
-CXXFLAGS += -O3
+CXXFLAGS += -O3 -DNDEBUG
else
CXXFLAGS += -O0 -g
endif
# Validate that the VEC parameter is a supported value, and patch CXXFLAGS
ifeq ($(VEC),nointrin)
-CXXFLAGS += -msse2 -DASTC_SSE=0 -DASTC_AVX=0 -DASTC_POPCNT=0
+CXXFLAGS += -msse2 -DASTCENC_SSE=0 -DASTCENC_AVX=0 -DASTCENC_POPCNT=0
else
ifeq ($(VEC),sse2)
-CXXFLAGS += -msse2 -DASTC_SSE=20 -DASTC_AVX=0 -DASTC_POPCNT=0
+CXXFLAGS += -msse2 -DASTCENC_SSE=20 -DASTCENC_AVX=0 -DASTCENC_POPCNT=0
else
ifeq ($(VEC),sse4.2)
-CXXFLAGS += -msse4.2 -mpopcnt -DASTC_SSE=42 -DASTC_AVX=0 -DASTC_POPCNT=1
+CXXFLAGS += -msse4.2 -mpopcnt -DASTCENC_SSE=42 -DASTCENC_AVX=0 -DASTCENC_POPCNT=1
else
ifeq ($(VEC),avx2)
-CXXFLAGS += -mavx2 -mpopcnt -DASTC_SSE=42 -DASTC_AVX=2 -DASTC_POPCNT=1
+CXXFLAGS += -mavx2 -mpopcnt -DASTCENC_SSE=42 -DASTCENC_AVX=2 -DASTCENC_POPCNT=1
else
$(error Unsupported VEC target, use VEC=nointrin/sse2/sse4.2/avx2)
endif
@@ -117,29 +121,39 @@ CXXFLAGS_EXTERNAL = \
-Wno-double-promotion \
-fno-strict-aliasing
+# ==================================================
+# Build rules for the command line wrapper
$(BINARY): $(EXTERNAL_OBJECTS) $(OBJECTS)
@$(CXX) -o $@ $^ $(CXXFLAGS) -lpthread
@echo "[Link] $@ (using $(VEC), debug=$(DBG))"
+# Note: ensure NDEBUG is undefined; all three libraries are weak at runtime
+# handling of corrupt files, relying on asserts to handle bd file input.
+# Compiling with NDEBUG is a potential security risk.
stb_image-$(VEC).o: stb_image.h
@$(CXX) -c -x c++ -o $@ $< $(CXXFLAGS_EXTERNAL) -DSTB_IMAGE_IMPLEMENTATION \
- -DSTBI_NO_PSD -DSTBI_NO_GIF -DSTBI_NO_PIC -DSTBI_NO_PNM
+ -DSTBI_NO_PSD -DSTBI_NO_GIF -DSTBI_NO_PIC -DSTBI_NO_PNM -UNDEBUG
@echo "[C++] $<"
stb_image_write-$(VEC).o: stb_image_write.h
- @$(CXX) -c -x c++ -o $@ $< $(CXXFLAGS_EXTERNAL) -DSTB_IMAGE_WRITE_IMPLEMENTATION
+ @$(CXX) -c -x c++ -o $@ $< $(CXXFLAGS_EXTERNAL) -DSTB_IMAGE_WRITE_IMPLEMENTATION \
+ -UNDEBUG
@echo "[C++] $<"
tinyexr-$(VEC).o: tinyexr.h
- @$(CXX) -c -x c++ -o $@ $< $(CXXFLAGS) -DTINYEXR_IMPLEMENTATION
+ @$(CXX) -c -x c++ -o $@ $< $(CXXFLAGS) -DTINYEXR_IMPLEMENTATION -UNDEBUG
@echo "[C++] $<"
$(OBJECTS): %-$(VEC).o: %.cpp $(HEADERS)
- @$(CXX) -c -o $@ $< $(CXXFLAGS)
+ @$(CXX) -c -o $@ $(abspath $<) $(CXXFLAGS)
@echo "[C++] $<"
+# ==================================================
+# Generic utility rules
+
clean:
@rm -f *-$(VEC).o
+ @rm -f *-$(VEC).so
@rm -f *-$(VEC).obj
@rm -f $(BINARY)
@rm -f $(BINARY).exe
diff --git a/Source/VS2019/astcenc-avx2.filters b/Source/VS2019/astcenc-avx2.filters
index 854e2f5..9bb7fd1 100644
--- a/Source/VS2019/astcenc-avx2.filters
+++ b/Source/VS2019/astcenc-avx2.filters
@@ -87,7 +87,7 @@
Source Files
-
+
Source Files
@@ -96,7 +96,7 @@
Source Files
-
+
Source Files
@@ -107,14 +107,14 @@
-
+
Header Files
Header Files
-
+
Header Files
-
\ No newline at end of file
+
diff --git a/Source/VS2019/astcenc-avx2.vcxproj b/Source/VS2019/astcenc-avx2.vcxproj
index 0aa2180..9459ce0 100644
--- a/Source/VS2019/astcenc-avx2.vcxproj
+++ b/Source/VS2019/astcenc-avx2.vcxproj
@@ -11,40 +11,46 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{BCA178CD-C714-484E-A02A-0489DC3C49B2}
@@ -92,7 +98,7 @@
Disabled
$(ProjectDir);%(AdditionalIncludeDirectories)
- WIN32;ASTC_SSE=42;ASTC_AVX=2;ASTC_POPCNT=1;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ WIN32;ASTCENC_SSE=42;ASTCENC_AVX=2;ASTCENC_POPCNT=1;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
EnableFastChecks
MultiThreadedDebugDLL
AdvancedVectorExtensions2
@@ -112,7 +118,7 @@
$(ProjectDir);%(AdditionalIncludeDirectories)
- WIN32;ASTC_SSE=42;ASTC_AVX=2;ASTC_POPCNT=1;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ WIN32;ASTCENC_SSE=42;ASTCENC_AVX=2;ASTCENC_POPCNT=1;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
MultiThreadedDLL
false
AdvancedVectorExtensions2
diff --git a/Source/VS2019/astcenc-sse2.filters b/Source/VS2019/astcenc-sse2.filters
index 854e2f5..9bb7fd1 100644
--- a/Source/VS2019/astcenc-sse2.filters
+++ b/Source/VS2019/astcenc-sse2.filters
@@ -87,7 +87,7 @@
Source Files
-
+
Source Files
@@ -96,7 +96,7 @@
Source Files
-
+
Source Files
@@ -107,14 +107,14 @@
-
+
Header Files
Header Files
-
+
Header Files
-
\ No newline at end of file
+
diff --git a/Source/VS2019/astcenc-sse2.vcxproj b/Source/VS2019/astcenc-sse2.vcxproj
index 3df7d8c..284c1f1 100644
--- a/Source/VS2019/astcenc-sse2.vcxproj
+++ b/Source/VS2019/astcenc-sse2.vcxproj
@@ -11,40 +11,46 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{D6D60D86-0502-446A-8498-888F78B869C2}
@@ -92,7 +98,7 @@
Disabled
$(ProjectDir);%(AdditionalIncludeDirectories)
- WIN32;ASTC_SSE=20;ASTC_AVX=0;ASTC_POPCNT=0;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ WIN32;ASTCENC_SSE=20;ASTCENC_AVX=0;ASTCENC_POPCNT=0;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
EnableFastChecks
MultiThreadedDebugDLL
NotSet
@@ -112,7 +118,7 @@
$(ProjectDir);%(AdditionalIncludeDirectories)
- WIN32;ASTC_SSE=20;ASTC_AVX=0;ASTC_POPCNT=0;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ WIN32;ASTCENC_SSE=20;ASTCENC_AVX=0;ASTCENC_POPCNT=0;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
MultiThreadedDLL
false
NotSet
diff --git a/Source/VS2019/astcenc-sse4.2.filters b/Source/VS2019/astcenc-sse4.2.filters
index 854e2f5..9bb7fd1 100644
--- a/Source/VS2019/astcenc-sse4.2.filters
+++ b/Source/VS2019/astcenc-sse4.2.filters
@@ -87,7 +87,7 @@
Source Files
-
+
Source Files
@@ -96,7 +96,7 @@
Source Files
-
+
Source Files
@@ -107,14 +107,14 @@
-
+
Header Files
Header Files
-
+
Header Files
-
\ No newline at end of file
+
diff --git a/Source/VS2019/astcenc-sse4.2.vcxproj b/Source/VS2019/astcenc-sse4.2.vcxproj
index d266714..9b4d936 100644
--- a/Source/VS2019/astcenc-sse4.2.vcxproj
+++ b/Source/VS2019/astcenc-sse4.2.vcxproj
@@ -11,40 +11,46 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{9FB06FB7-F57D-4B12-9AE9-91CD50FD4879}
@@ -92,7 +98,7 @@
Disabled
$(ProjectDir);%(AdditionalIncludeDirectories)
- WIN32;ASTC_SSE=42;ASTC_AVX=0;ASTC_POPCNT=1;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ WIN32;ASTCENC_SSE=42;ASTCENC_AVX=0;ASTCENC_POPCNT=1;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
EnableFastChecks
MultiThreadedDebugDLL
NotSet
@@ -112,7 +118,7 @@
$(ProjectDir);%(AdditionalIncludeDirectories)
- WIN32;ASTC_SSE=42;ASTC_AVX=0;ASTC_POPCNT=1;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ WIN32;ASTCENC_SSE=42;ASTCENC_AVX=0;ASTCENC_POPCNT=1;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
MultiThreadedDLL
false
NotSet
diff --git a/Source/astc_main.cpp b/Source/astc_main.cpp
deleted file mode 100644
index 96e3a7b..0000000
--- a/Source/astc_main.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// ----------------------------------------------------------------------------
-// Copyright 2011-2020 Arm Limited
-//
-// 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.
-// ----------------------------------------------------------------------------
-
-/**
- * @brief Application entry point.
- */
-
-#include "astc_codec_internals.h"
-
-int main(
- int argc,
- char **argv
-) {
- return astc_main(argc, argv);
-}
diff --git a/Source/astc_toplevel.cpp b/Source/astc_toplevel.cpp
deleted file mode 100644
index 8487261..0000000
--- a/Source/astc_toplevel.cpp
+++ /dev/null
@@ -1,1614 +0,0 @@
-// SPDX-License-Identifier: Apache-2.0
-// ----------------------------------------------------------------------------
-// Copyright 2011-2020 Arm Limited
-//
-// 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.
-// ----------------------------------------------------------------------------
-
-/**
- * @brief Functions for codec library front-end.
- */
-
-#include "astc_codec_internals.h"
-
-#include
-#include
-#include
-
-#ifdef DEBUG_CAPTURE_NAN
- #ifndef _GNU_SOURCE
- #define _GNU_SOURCE
- #endif
-
- #include
-#endif
-
-#ifdef DEBUG_PRINT_DIAGNOSTICS
- int print_diagnostics = 0;
- int diagnostics_tile = -1;
- int print_tile_errors = 0;
- int print_statistics = 0;
- extern int block_mode_histogram[2048];
-#endif
-
-static double start_time;
-static double end_time;
-static double start_coding_time;
-static double end_coding_time;
-
-NORETURN void astc_codec_internal_error(
- const char *filename,
- int line
-) {
- printf("Internal error: File=%s Line=%d\n", filename, line);
- exit(1);
-}
-
-#define MAGIC_FILE_CONSTANT 0x5CA1AB13
-
-struct astc_header
-{
- uint8_t magic[4];
- uint8_t blockdim_x;
- uint8_t blockdim_y;
- uint8_t blockdim_z;
- uint8_t xsize[3]; // x-size = xsize[0] + xsize[1] + xsize[2]
- uint8_t ysize[3]; // x-size, y-size and z-size are given in texels;
- uint8_t zsize[3]; // block count is inferred
-};
-
-astc_codec_image *load_astc_file(
- const char *filename,
- int bitness,
- astc_decode_mode decode_mode,
- swizzlepattern swz_decode,
- int linearize_srgb,
- int rgb_force_use_of_hdr,
- int alpha_force_use_of_hdr
-) {
- int x, y, z;
- FILE *f = fopen(filename, "rb");
- if (!f)
- {
- printf("Failed to open file %s\n", filename);
- exit(1);
- }
- astc_header hdr;
- size_t hdr_bytes_read = fread(&hdr, 1, sizeof(astc_header), f);
- if (hdr_bytes_read != sizeof(astc_header))
- {
- fclose(f);
- printf("Failed to read file %s\n", filename);
- exit(1);
- }
-
- uint32_t magicval = (uint32_t)(hdr.magic[0]) +
- (uint32_t)(hdr.magic[1]) * 256 +
- (uint32_t)(hdr.magic[2]) * 65536 +
- (uint32_t)(hdr.magic[3]) * 16777216;
-
- if (magicval != MAGIC_FILE_CONSTANT)
- {
- fclose(f);
- printf("File %s not recognized\n", filename);
- exit(1);
- }
-
- int xdim = hdr.blockdim_x;
- int ydim = hdr.blockdim_y;
- int zdim = hdr.blockdim_z;
-
- if ((xdim < 3 || xdim > 6 || ydim < 3 || ydim > 6 || zdim < 3 || zdim > 6) &&
- (xdim < 4 || xdim == 7 || xdim == 9 || xdim == 11 || xdim > 12 ||
- ydim < 4 || ydim == 7 || ydim == 9 || ydim == 11 || ydim > 12 || zdim != 1))
- {
- fclose(f);
- printf("File %s not recognized %d %d %d\n", filename, xdim, ydim, zdim);
- exit(1);
- }
-
- int xsize = hdr.xsize[0] + 256 * hdr.xsize[1] + 65536 * hdr.xsize[2];
- int ysize = hdr.ysize[0] + 256 * hdr.ysize[1] + 65536 * hdr.ysize[2];
- int zsize = hdr.zsize[0] + 256 * hdr.zsize[1] + 65536 * hdr.zsize[2];
-
- if (xsize == 0 || ysize == 0 || zsize == 0)
- {
- fclose(f);
- printf("File %s has zero dimension %d %d %d\n", filename, xsize, ysize, zsize);
- exit(1);
- }
-
- int xblocks = (xsize + xdim - 1) / xdim;
- int yblocks = (ysize + ydim - 1) / ydim;
- int zblocks = (zsize + zdim - 1) / zdim;
-
- uint8_t *buffer = (uint8_t *) malloc(xblocks * yblocks * zblocks * 16);
- if (!buffer)
- {
- fclose(f);
- printf("Ran out of memory\n");
- exit(1);
- }
- size_t bytes_to_read = xblocks * yblocks * zblocks * 16;
- size_t bytes_read = fread(buffer, 1, bytes_to_read, f);
- fclose(f);
- if (bytes_read != bytes_to_read)
- {
- printf("Failed to read file %s\n", filename);
- exit(1);
- }
-
- astc_codec_image *img = alloc_image(bitness, xsize, ysize, zsize, 0);
- img->linearize_srgb = linearize_srgb;
- img->rgb_force_use_of_hdr = rgb_force_use_of_hdr;
- img->alpha_force_use_of_hdr = alpha_force_use_of_hdr;
-
- block_size_descriptor bsd;
- init_block_size_descriptor(xdim, ydim, zdim, &bsd);
-
- imageblock pb;
- for (z = 0; z < zblocks; z++)
- {
- for (y = 0; y < yblocks; y++)
- {
- for (x = 0; x < xblocks; x++)
- {
- int offset = (((z * yblocks + y) * xblocks) + x) * 16;
- uint8_t *bp = buffer + offset;
- physical_compressed_block pcb = *(physical_compressed_block *) bp;
- symbolic_compressed_block scb;
- physical_to_symbolic(&bsd, pcb, &scb);
- decompress_symbolic_block(img, decode_mode, &bsd, x * xdim, y * ydim, z * zdim, &scb, &pb);
- write_imageblock(img, &pb, &bsd, x * xdim, y * ydim, z * zdim, swz_decode);
- }
- }
- }
-
- term_block_size_descriptor(&bsd);
- free(buffer);
- return img;
-}
-
-struct encode_astc_image_info
-{
- const block_size_descriptor* bsd;
- const error_weighting_params* ewp;
- uint8_t* buffer;
- int pack_and_unpack;
- int threadcount;
- astc_decode_mode decode_mode;
- swizzlepattern swz_encode;
- swizzlepattern swz_decode;
- const astc_codec_image* input_image;
- astc_codec_image* output_image;
-};
-
-static void encode_astc_image_threadfunc(
- int thread_count,
- int thread_id,
- void* vblk
-) {
- const encode_astc_image_info *blk = (const encode_astc_image_info *)vblk;
- const block_size_descriptor *bsd = blk->bsd;
- int xdim = bsd->xdim;
- int ydim = bsd->ydim;
- int zdim = bsd->zdim;
- uint8_t *buffer = blk->buffer;
- const error_weighting_params *ewp = blk->ewp;
- int pack_and_unpack = blk->pack_and_unpack;
- astc_decode_mode decode_mode = blk->decode_mode;
- swizzlepattern swz_encode = blk->swz_encode;
- swizzlepattern swz_decode = blk->swz_decode;
- const astc_codec_image *input_image = blk->input_image;
- astc_codec_image *output_image = blk->output_image;
-
- imageblock pb;
- int ctr = thread_id;
- int pctr = 0;
-
- int x, y, z;
- int xsize = input_image->xsize;
- int ysize = input_image->ysize;
- int zsize = input_image->zsize;
- int xblocks = (xsize + xdim - 1) / xdim;
- int yblocks = (ysize + ydim - 1) / ydim;
- int zblocks = (zsize + zdim - 1) / zdim;
-
- //allocate memory for temporary buffers
- compress_symbolic_block_buffers temp_buffers;
- temp_buffers.ewb = new error_weight_block;
- temp_buffers.ewbo = new error_weight_block_orig;
- temp_buffers.tempblocks = new symbolic_compressed_block[4];
- temp_buffers.temp = new imageblock;
- temp_buffers.planes2 = new compress_fixed_partition_buffers;
- temp_buffers.planes2->ei1 = new endpoints_and_weights;
- temp_buffers.planes2->ei2 = new endpoints_and_weights;
- temp_buffers.planes2->eix1 = new endpoints_and_weights[MAX_DECIMATION_MODES];
- temp_buffers.planes2->eix2 = new endpoints_and_weights[MAX_DECIMATION_MODES];
- temp_buffers.planes2->decimated_quantized_weights = new float[2 * MAX_DECIMATION_MODES * MAX_WEIGHTS_PER_BLOCK];
- temp_buffers.planes2->decimated_weights = new float[2 * MAX_DECIMATION_MODES * MAX_WEIGHTS_PER_BLOCK];
- temp_buffers.planes2->flt_quantized_decimated_quantized_weights = new float[2 * MAX_WEIGHT_MODES * MAX_WEIGHTS_PER_BLOCK];
- temp_buffers.planes2->u8_quantized_decimated_quantized_weights = new uint8_t[2 * MAX_WEIGHT_MODES * MAX_WEIGHTS_PER_BLOCK];
- temp_buffers.plane1 = temp_buffers.planes2;
-
- for (z = 0; z < zblocks; z++)
- {
- for (y = 0; y < yblocks; y++)
- {
- for (x = 0; x < xblocks; x++)
- {
- if (ctr == 0)
- {
- int offset = ((z * yblocks + y) * xblocks + x) * 16;
- uint8_t *bp = buffer + offset;
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (diagnostics_tile < 0 || diagnostics_tile == pctr)
- {
- print_diagnostics = (diagnostics_tile == pctr) ? 1 : 0;
- #endif
- fetch_imageblock(input_image, &pb, bsd, x * xdim, y * ydim, z * zdim, swz_encode);
- symbolic_compressed_block scb;
- compress_symbolic_block(input_image, decode_mode, bsd, ewp, &pb, &scb, &temp_buffers);
- if (pack_and_unpack)
- {
- decompress_symbolic_block(input_image, decode_mode, bsd, x * xdim, y * ydim, z * zdim, &scb, &pb);
- write_imageblock(output_image, &pb, bsd, x * xdim, y * ydim, z * zdim, swz_decode);
- }
- else
- {
- physical_compressed_block pcb;
- pcb = symbolic_to_physical(bsd, &scb);
- *(physical_compressed_block *) bp = pcb;
- }
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- }
- #endif
-
- ctr = thread_count - 1;
- pctr++;
- }
- else
- ctr--;
- }
- }
- }
-
- delete[] temp_buffers.planes2->decimated_quantized_weights;
- delete[] temp_buffers.planes2->decimated_weights;
- delete[] temp_buffers.planes2->flt_quantized_decimated_quantized_weights;
- delete[] temp_buffers.planes2->u8_quantized_decimated_quantized_weights;
- delete[] temp_buffers.planes2->eix1;
- delete[] temp_buffers.planes2->eix2;
- delete temp_buffers.planes2->ei1;
- delete temp_buffers.planes2->ei2;
- delete temp_buffers.planes2;
- delete[] temp_buffers.tempblocks;
- delete temp_buffers.temp;
- delete temp_buffers.ewbo;
- delete temp_buffers.ewb;
-}
-
-static void encode_astc_image(
- const astc_codec_image* input_image,
- astc_codec_image* output_image,
- int xdim,
- int ydim,
- int zdim,
- const error_weighting_params* ewp,
- astc_decode_mode decode_mode,
- swizzlepattern swz_encode,
- swizzlepattern swz_decode,
- uint8_t* buffer,
- int pack_and_unpack,
- int threadcount
-) {
- // before entering into the multi-threaded routine, ensure that the block size descriptors
- // and the partition table descriptors needed actually exist.
- block_size_descriptor* bsd = new block_size_descriptor;
- init_block_size_descriptor(xdim, ydim, zdim, bsd);
- get_partition_table(bsd, 0);
-
- encode_astc_image_info ai;
- ai.bsd = bsd;
- ai.buffer = buffer;
- ai.ewp = ewp;
- ai.pack_and_unpack = pack_and_unpack;
- ai.decode_mode = decode_mode;
- ai.swz_encode = swz_encode;
- ai.swz_decode = swz_decode;
- ai.input_image = input_image;
- ai.output_image = output_image;
-
- launch_threads(threadcount, encode_astc_image_threadfunc, &ai);
-
- term_block_size_descriptor(bsd);
- delete bsd;
-}
-
-static void store_astc_file(
- const astc_codec_image* input_image,
- const char* filename,
- int xdim,
- int ydim,
- int zdim,
- const error_weighting_params* ewp,
- astc_decode_mode decode_mode,
- swizzlepattern swz_encode,
- int threadcount
-) {
- int xsize = input_image->xsize;
- int ysize = input_image->ysize;
- int zsize = input_image->zsize;
-
- int xblocks = (xsize + xdim - 1) / xdim;
- int yblocks = (ysize + ydim - 1) / ydim;
- int zblocks = (zsize + zdim - 1) / zdim;
-
- uint8_t *buffer = (uint8_t *) malloc(xblocks * yblocks * zblocks * 16);
- if (!buffer)
- {
- printf("ERROR: Ran out of memory\n");
- exit(1);
- }
-
- encode_astc_image(input_image, nullptr, xdim, ydim, zdim, ewp, decode_mode, swz_encode, swz_encode, buffer, 0, threadcount);
-
- end_coding_time = get_time();
-
- astc_header hdr;
- hdr.magic[0] = MAGIC_FILE_CONSTANT & 0xFF;
- hdr.magic[1] = (MAGIC_FILE_CONSTANT >> 8) & 0xFF;
- hdr.magic[2] = (MAGIC_FILE_CONSTANT >> 16) & 0xFF;
- hdr.magic[3] = (MAGIC_FILE_CONSTANT >> 24) & 0xFF;
- hdr.blockdim_x = xdim;
- hdr.blockdim_y = ydim;
- hdr.blockdim_z = zdim;
- hdr.xsize[0] = xsize & 0xFF;
- hdr.xsize[1] = (xsize >> 8) & 0xFF;
- hdr.xsize[2] = (xsize >> 16) & 0xFF;
- hdr.ysize[0] = ysize & 0xFF;
- hdr.ysize[1] = (ysize >> 8) & 0xFF;
- hdr.ysize[2] = (ysize >> 16) & 0xFF;
- hdr.zsize[0] = zsize & 0xFF;
- hdr.zsize[1] = (zsize >> 8) & 0xFF;
- hdr.zsize[2] = (zsize >> 16) & 0xFF;
-
- FILE *wf = fopen(filename, "wb");
- if (!wf)
- {
- printf("ERROR: Failed to write output image %s\n", filename);
- exit(1);
- }
- fwrite(&hdr, 1, sizeof(astc_header), wf);
- fwrite(buffer, 1, xblocks * yblocks * zblocks * 16, wf);
- fclose(wf);
- free(buffer);
-}
-
-static astc_codec_image *pack_and_unpack_astc_image(
- const astc_codec_image* input_image,
- int xdim,
- int ydim,
- int zdim,
- const error_weighting_params* ewp,
- astc_decode_mode decode_mode,
- swizzlepattern swz_encode,
- swizzlepattern swz_decode,
- int bitness,
- int threadcount
-) {
- int xsize = input_image->xsize;
- int ysize = input_image->ysize;
- int zsize = input_image->zsize;
-
- astc_codec_image *img = alloc_image(bitness, xsize, ysize, zsize, 0);
-
- encode_astc_image(input_image, img, xdim, ydim, zdim, ewp, decode_mode,
- swz_encode, swz_decode, nullptr, 1, threadcount);
-
- return img;
-}
-
-static void compare_two_files(
- const char* filename1,
- const char* filename2,
- int low_fstop,
- int high_fstop,
- int linearize_srgb
-) {
- int load_result1;
- astc_codec_image *img1 = astc_codec_load_image(filename1, 0, 0, linearize_srgb, 0, 0, &load_result1);
- if (load_result1 < 0)
- {
- exit(1);
- }
-
- int load_result2;
- astc_codec_image *img2 = astc_codec_load_image(filename2, 0, 0, linearize_srgb, 0, 0, &load_result2);
- if (load_result2 < 0)
- {
- exit(1);
- }
-
- int file1_components = load_result1 & 0x7;
- int file2_components = load_result2 & 0x7;
- int comparison_components = MAX(file1_components, file2_components);
-
- int compare_hdr = 0;
- if ((load_result1 & 0x80) || (load_result2 & 0x80))
- compare_hdr = 1;
-
- compute_error_metrics(compare_hdr, comparison_components, img1, img2, low_fstop, high_fstop);
-}
-
-// The ASTC codec is written with the assumption that a float threaded through
-// the "if32" union will in fact be stored and reloaded as a 32-bit IEEE-754 single-precision
-// float, stored with round-to-nearest rounding. This is always the case in an
-// IEEE-754 compliant system, however not every system is actually IEEE-754 compliant
-// in the first place. As such, we run a quick test to check that this is actually the case
-// (e.g. gcc on 32-bit x86 will typically fail unless -msse2 -mfpmath=sse2 is specified).
-
-// TODO: Move to mathlib
-volatile float xprec_testval = 2.51f;
-static void test_inappropriate_extended_precision()
-{
- if32 p;
- p.f = xprec_testval + 12582912.0f;
- float q = p.f - 12582912.0f;
- if (q != 3.0f)
- {
- printf("CPU support error: float math is not IEEE-754 compliant.\n");
- printf(" Please recompile with IEEE-754 support.\n");
- exit(1);
- }
-}
-
-static void test_inappropriate_cpu_extensions()
-{
- #if ASTC_SSE >= 42
- if (!cpu_supports_sse42()) {
- printf("CPU support error: host lacks SSE 4.2 support.\n");
- printf(" Please recompile with VEC=sse2.\n");
- exit(1);
- }
- #endif
-
- #if ASTC_POPCNT >= 1
- if (!cpu_supports_popcnt()) {
- printf("CPU support error: host lacks POPCNT support.\n");
- printf(" Please recompile with VEC=sse2.\n");
- exit(1);
- }
- #endif
-
- #if ASTC_AVX >= 2
- if (!cpu_supports_avx2()) {
- printf("CPU support error: host lacks AVX2 support.\n");
- printf(" Please recompile with VEC=sse4.2 or VEC=sse2.\n");
- exit(1);
- }
- #endif
-}
-
-int astc_main(
- int argc,
- char **argv
-) {
- test_inappropriate_extended_precision();
-
- test_inappropriate_cpu_extensions();
-
- // initialization routines
- prepare_angular_tables();
- build_quantization_mode_table();
-
- start_time = get_time();
-
- #ifdef DEBUG_CAPTURE_NAN
- feenableexcept(FE_DIVBYZERO | FE_INVALID);
- #endif
-
- if (argc < 2)
- {
- astcenc_print_shorthelp();
- return 0;
- }
-
- enum astc_op_mode {
- ASTC_ENCODE,
- ASTC_DECODE,
- ASTC_ENCODE_AND_DECODE,
- ASTC_IMAGE_COMPARE,
- ASTC_PRINT_LONGHELP,
- ASTC_PRINT_VERSION,
- ASTC_UNRECOGNIZED
- };
-
- astc_decode_mode decode_mode = DECODE_LDR;
- astc_op_mode op_mode = ASTC_UNRECOGNIZED;
-
- struct {
- const char *opt;
- astc_op_mode op_mode;
- astc_decode_mode decode_mode;
- } modes[] = {
- {"-cl", ASTC_ENCODE, DECODE_LDR},
- {"-dl", ASTC_DECODE, DECODE_LDR},
- {"-tl", ASTC_ENCODE_AND_DECODE, DECODE_LDR},
- {"-cs", ASTC_ENCODE, DECODE_LDR_SRGB},
- {"-ds", ASTC_DECODE, DECODE_LDR_SRGB},
- {"-ts", ASTC_ENCODE_AND_DECODE, DECODE_LDR_SRGB},
- {"-ch", ASTC_ENCODE, DECODE_HDR},
- {"-cH", ASTC_ENCODE, DECODE_HDRA},
- {"-dh", ASTC_DECODE, DECODE_HDR},
- {"-dH", ASTC_DECODE, DECODE_HDRA},
- {"-th", ASTC_ENCODE_AND_DECODE, DECODE_HDR},
- {"-tH", ASTC_ENCODE_AND_DECODE, DECODE_HDRA},
- {"-compare", ASTC_IMAGE_COMPARE, DECODE_HDR},
- {"-h", ASTC_PRINT_LONGHELP, DECODE_HDR},
- {"-help", ASTC_PRINT_LONGHELP, DECODE_HDR},
- {"-v", ASTC_PRINT_VERSION, DECODE_HDR},
- {"-version", ASTC_PRINT_VERSION, DECODE_HDR}
- };
-
- int modes_count = sizeof(modes) / sizeof(modes[0]);
- for (int i = 0; i < modes_count; i++)
- {
- if (!strcmp(argv[1], modes[i].opt))
- {
- op_mode = modes[i].op_mode;
- decode_mode = modes[i].decode_mode;
- break;
- }
- }
-
- switch (op_mode)
- {
- case ASTC_UNRECOGNIZED:
- printf("Unrecognized operation mode \"%s\"\n", argv[1]);
- return 1;
- case ASTC_PRINT_LONGHELP:
- astcenc_print_longhelp();
- return 0;
- case ASTC_PRINT_VERSION:
- astcenc_print_header();
- return 0;
- default:
- break;
- }
-
- int array_size = 1;
-
- const char *input_filename = argc >= 3 ? argv[2] : nullptr;
- const char *output_filename = argc >= 4 ? argv[3] : nullptr;
-
- int silentmode = 0;
- int y_flip = 0;
- int linearize_srgb = 0;
- int rgb_force_use_of_hdr = 0;
- int alpha_force_use_of_hdr = 0;
-
- error_weighting_params ewp;
-
- ewp.rgb_power = 1.0f;
- ewp.alpha_power = 1.0f;
- ewp.rgb_base_weight = 1.0f;
- ewp.alpha_base_weight = 1.0f;
- ewp.rgb_mean_weight = 0.0f;
- ewp.rgb_stdev_weight = 0.0f;
- ewp.alpha_mean_weight = 0.0f;
- ewp.alpha_stdev_weight = 0.0f;
-
- ewp.rgb_mean_and_stdev_mixing = 0.0f;
- ewp.mean_stdev_radius = 0;
- ewp.enable_rgb_scale_with_alpha = 0;
- ewp.alpha_radius = 0;
-
- ewp.block_artifact_suppression = 0.0f;
- ewp.rgba_weights[0] = 1.0f;
- ewp.rgba_weights[1] = 1.0f;
- ewp.rgba_weights[2] = 1.0f;
- ewp.rgba_weights[3] = 1.0f;
- ewp.ra_normal_angular_scale = 0;
-
- swizzlepattern swz_encode = { 0, 1, 2, 3 };
- swizzlepattern swz_decode = { 0, 1, 2, 3 };
-
- int thread_count = 0; // default value
- int thread_count_autodetected = 0;
-
- int preset_has_been_set = 0;
-
- int plimit_autoset = -1;
- int plimit_user_specified = -1;
- int plimit_set_by_user = 0;
-
- float dblimit_autoset_2d = 0.0;
- float dblimit_autoset_3d = 0.0;
- float dblimit_user_specified = 0.0;
- int dblimit_set_by_user = 0;
-
- float oplimit_autoset = 0.0;
- float oplimit_user_specified = 0.0;
- int oplimit_set_by_user = 0;
-
- float mincorrel_autoset = 0.0;
- float mincorrel_user_specified = 0.0;
- int mincorrel_set_by_user = 0;
-
- float bmc_user_specified = 0.0;
- float bmc_autoset = 0.0;
- int bmc_set_by_user = 0;
-
- int maxiters_user_specified = 0;
- int maxiters_autoset = 0;
- int maxiters_set_by_user = 0;
-
- int xdim_2d = 0;
- int ydim_2d = 0;
- int xdim_3d = 0;
- int ydim_3d = 0;
- int zdim_3d = 0;
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- int print_block_mode_histogram = 0;
- #endif
-
- float log10_texels_2d = 0.0f;
- float log10_texels_3d = 0.0f;
-
- int low_fstop = -10;
- int high_fstop = 10;
-
- if (decode_mode == DECODE_HDRA)
- {
- ewp.rgb_power = 0.75f;
- ewp.rgb_base_weight = 0.0f;
- ewp.rgb_mean_weight = 1.0f;
-
- ewp.alpha_power = 0.75f;
- ewp.alpha_base_weight = 0.0f;
- ewp.alpha_mean_weight = 1.0f;
-
- rgb_force_use_of_hdr = 1;
- alpha_force_use_of_hdr = 1;
-
- dblimit_user_specified = 999.0f;
- dblimit_set_by_user = 1;
- }
- else if (decode_mode == DECODE_HDR)
- {
- ewp.rgb_power = 0.75f;
- ewp.rgb_base_weight = 0.0f;
- ewp.rgb_mean_weight = 1.0f;
-
- ewp.alpha_base_weight = 0.05f;
-
- rgb_force_use_of_hdr = 1;
- alpha_force_use_of_hdr = 0;
-
- dblimit_user_specified = 999.0f;
- dblimit_set_by_user = 1;
- }
-
- // parse the command line's encoding options.
- int argidx;
- if (op_mode == ASTC_ENCODE || op_mode == ASTC_ENCODE_AND_DECODE)
- {
- if (argc < 5)
- {
- printf("ERROR: Block size not specified\n");
- return 1;
- }
-
- int cnt2D, cnt3D;
- int dimensions = sscanf(argv[4], "%dx%d%nx%d%n", &xdim_3d, &ydim_3d, &cnt2D, &zdim_3d, &cnt3D);
- switch (dimensions)
- {
- case 0:
- case 1:
- printf("ERROR: Invalid block size %s specified\n", argv[4]);
- return 1;
- case 2:
- {
- // Character after the last match should be a NUL
- if (argv[4][cnt2D] || !is_legal_2d_block_size(xdim_3d, ydim_3d))
- {
- printf("ERROR: Invalid block size %s specified\n", argv[4]);
- return 1;
- }
-
- zdim_3d = 1;
- }
- break;
- default:
- {
- // Character after the last match should be a NUL
- if (argv[4][cnt3D]|| !is_legal_3d_block_size(xdim_3d, ydim_3d, zdim_3d))
- {
- printf("ERROR: Invalid block size %s specified\n", argv[4]);
- return 1;
- }
- }
- break;
- }
-
- xdim_2d = xdim_3d;
- ydim_2d = ydim_3d;
-
- log10_texels_2d = logf((float)(xdim_2d * ydim_2d)) / logf(10.0f);
- log10_texels_3d = logf((float)(xdim_3d * ydim_3d * zdim_3d)) / logf(10.0f);
- argidx = 5;
- }
- else
- {
- // for decode and comparison, block size is not needed.
- argidx = 4;
- }
-
- while (argidx < argc)
- {
- if (!strcmp(argv[argidx], "-silent"))
- {
- argidx++;
- silentmode = 1;
- }
- else if (!strcmp(argv[argidx], "-v"))
- {
- argidx += 7;
- if (argidx > argc)
- {
- printf("-v switch with less than 6 arguments, quitting\n");
- return 1;
- }
- ewp.mean_stdev_radius = atoi(argv[argidx - 6]);
- ewp.rgb_power = static_cast < float >(atof(argv[argidx - 5]));
- ewp.rgb_base_weight = static_cast < float >(atof(argv[argidx - 4]));
- ewp.rgb_mean_weight = static_cast < float >(atof(argv[argidx - 3]));
- ewp.rgb_stdev_weight = static_cast < float >(atof(argv[argidx - 2]));
- ewp.rgb_mean_and_stdev_mixing = static_cast < float >(atof(argv[argidx - 1]));
- }
- else if (!strcmp(argv[argidx], "-va"))
- {
- argidx += 5;
- if (argidx > argc)
- {
- printf("-va switch with less than 4 arguments, quitting\n");
- return 1;
- }
- ewp.alpha_power = static_cast < float >(atof(argv[argidx - 4]));
- ewp.alpha_base_weight = static_cast < float >(atof(argv[argidx - 3]));
- ewp.alpha_mean_weight = static_cast < float >(atof(argv[argidx - 2]));
- ewp.alpha_stdev_weight = static_cast < float >(atof(argv[argidx - 1]));
- }
- else if (!strcmp(argv[argidx], "-cw"))
- {
- argidx += 5;
- if (argidx > argc)
- {
- printf("-cw switch with less than 4 arguments\n");
- return 1;
- }
- ewp.rgba_weights[0] = static_cast < float >(atof(argv[argidx - 4]));
- ewp.rgba_weights[1] = static_cast < float >(atof(argv[argidx - 3]));
- ewp.rgba_weights[2] = static_cast < float >(atof(argv[argidx - 2]));
- ewp.rgba_weights[3] = static_cast < float >(atof(argv[argidx - 1]));
- }
- else if (!strcmp(argv[argidx], "-a"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-a switch with no argument\n");
- return 1;
- }
- ewp.enable_rgb_scale_with_alpha = 1;
- ewp.alpha_radius = atoi(argv[argidx - 1]);
- }
- else if (!strcmp(argv[argidx], "-b"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-b switch with no argument\n");
- return 1;
- }
- ewp.block_artifact_suppression = static_cast < float >(atof(argv[argidx - 1]));
- }
- else if (!strcmp(argv[argidx], "-esw"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-esw switch with no argument\n");
- return 1;
- }
-
- if (strlen(argv[argidx - 1]) != 4)
- {
- printf("Swizzle pattern for the -esw switch must have exactly 4 characters\n");
- return 1;
- }
-
- int swizzle_components[4];
- for (int i = 0; i < 4; i++)
- switch (argv[argidx - 1][i])
- {
- case 'r':
- swizzle_components[i] = 0;
- break;
- case 'g':
- swizzle_components[i] = 1;
- break;
- case 'b':
- swizzle_components[i] = 2;
- break;
- case 'a':
- swizzle_components[i] = 3;
- break;
- case '0':
- swizzle_components[i] = 4;
- break;
- case '1':
- swizzle_components[i] = 5;
- break;
- default:
- printf("Character '%c' is not a valid swizzle-character\n", argv[argidx - 1][i]);
- return 1;
- }
- swz_encode.r = swizzle_components[0];
- swz_encode.g = swizzle_components[1];
- swz_encode.b = swizzle_components[2];
- swz_encode.a = swizzle_components[3];
- }
- else if (!strcmp(argv[argidx], "-dsw"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-dsw switch with no argument\n");
- return 1;
- }
-
- if (strlen(argv[argidx - 1]) != 4)
- {
- printf("Swizzle pattern for the -dsw switch must have exactly 4 characters\n");
- return 1;
- }
-
- int swizzle_components[4];
- for (int i = 0; i < 4; i++)
- {
- switch (argv[argidx - 1][i])
- {
- case 'r':
- swizzle_components[i] = 0;
- break;
- case 'g':
- swizzle_components[i] = 1;
- break;
- case 'b':
- swizzle_components[i] = 2;
- break;
- case 'a':
- swizzle_components[i] = 3;
- break;
- case '0':
- swizzle_components[i] = 4;
- break;
- case '1':
- swizzle_components[i] = 5;
- break;
- case 'z':
- swizzle_components[i] = 6;
- break;
- default:
- printf("Character '%c' is not a valid swizzle-character\n", argv[argidx - 1][i]);
- return 1;
- }
- }
- swz_decode.r = swizzle_components[0];
- swz_decode.g = swizzle_components[1];
- swz_decode.b = swizzle_components[2];
- swz_decode.a = swizzle_components[3];
- }
- // presets begin here
- else if (!strcmp(argv[argidx], "-normal_psnr"))
- {
- argidx++;
- ewp.rgba_weights[0] = 1.0f;
- ewp.rgba_weights[1] = 0.0f;
- ewp.rgba_weights[2] = 0.0f;
- ewp.rgba_weights[3] = 1.0f;
- ewp.ra_normal_angular_scale = 1;
- swz_encode.r = 0; // r <- red
- swz_encode.g = 0; // g <- red
- swz_encode.b = 0; // b <- red
- swz_encode.a = 1; // a <- green
- swz_decode.r = 0; // r <- red
- swz_decode.g = 3; // g <- alpha
- swz_decode.b = 6; // b <- reconstruct
- swz_decode.a = 5; // 1.0
-
- oplimit_user_specified = 1000.0f;
- oplimit_set_by_user = 1;
- mincorrel_user_specified = 0.99f;
- mincorrel_set_by_user = 1;
- }
- else if (!strcmp(argv[argidx], "-normal_percep"))
- {
- argidx++;
- ewp.rgba_weights[0] = 1.0f;
- ewp.rgba_weights[1] = 0.0f;
- ewp.rgba_weights[2] = 0.0f;
- ewp.rgba_weights[3] = 1.0f;
- ewp.ra_normal_angular_scale = 1;
- swz_encode.r = 0; // r <- red
- swz_encode.g = 0; // g <- red
- swz_encode.b = 0; // b <- red
- swz_encode.a = 1; // a <- green
- swz_decode.r = 0; // r <- red
- swz_decode.g = 3; // g <- alpha
- swz_decode.b = 6; // b <- reconstruct
- swz_decode.a = 5; // 1.0
-
- oplimit_user_specified = 1000.0f;
- oplimit_set_by_user = 1;
- mincorrel_user_specified = 0.99f;
- mincorrel_set_by_user = 1;
-
- dblimit_user_specified = 999;
- dblimit_set_by_user = 1;
-
- ewp.block_artifact_suppression = 1.8f;
- ewp.mean_stdev_radius = 3;
- ewp.rgb_mean_weight = 0;
- ewp.rgb_stdev_weight = 50;
- ewp.rgb_mean_and_stdev_mixing = 0.0;
- ewp.alpha_mean_weight = 0;
- ewp.alpha_stdev_weight = 50;
- }
- else if (!strcmp(argv[argidx], "-mask"))
- {
- argidx++;
- ewp.mean_stdev_radius = 3;
- ewp.rgb_mean_weight = 0.0f;
- ewp.rgb_stdev_weight = 25.0f;
- ewp.rgb_mean_and_stdev_mixing = 0.03f;
- ewp.alpha_mean_weight = 0.0f;
- ewp.alpha_stdev_weight = 25.0f;
- }
-
- else if (!strcmp(argv[argidx], "-blockmodelimit"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-blockmodelimit switch with no argument\n");
- return 1;
- }
- float cutoff = (float)atof(argv[argidx - 1]);
- if (cutoff > 100 || !(cutoff >= 0))
- cutoff = 100;
- bmc_user_specified = cutoff;
- bmc_set_by_user = 1;
- }
- else if (!strcmp(argv[argidx], "-partitionlimit"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-partitionlimit switch with no argument\n");
- return 1;
- }
- plimit_user_specified = atoi(argv[argidx - 1]);
- plimit_set_by_user = 1;
- }
- else if (!strcmp(argv[argidx], "-dblimit"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-dblimit switch with no argument\n");
- return 1;
- }
- dblimit_user_specified = static_cast < float >(atof(argv[argidx - 1]));
- dblimit_set_by_user = 1;
- }
- else if (!strcmp(argv[argidx], "-partitionearlylimit"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-partitionearlylimit switch with no argument\n");
- return 1;
- }
- oplimit_user_specified = static_cast < float >(atof(argv[argidx - 1]));
- oplimit_set_by_user = 1;
- }
- else if (!strcmp(argv[argidx], "-planecorlimit"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-planecorlimit switch with no argument\n");
- return 1;
- }
- mincorrel_user_specified = static_cast < float >(atof(argv[argidx - 1]));
- mincorrel_set_by_user = 1;
- }
- else if (!strcmp(argv[argidx], "-refinementlimit"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-refinementlimit switch with no argument\n");
- return 1;
- }
- maxiters_user_specified = atoi(argv[argidx - 1]);
- maxiters_set_by_user = 1;
- }
- else if (!strcmp(argv[argidx], "-fast"))
- {
- argidx++;
- plimit_autoset = 4;
- oplimit_autoset = 1.0;
- mincorrel_autoset = 0.5;
- dblimit_autoset_2d = MAX(85 - 35 * log10_texels_2d, 63 - 19 * log10_texels_2d);
- dblimit_autoset_3d = MAX(85 - 35 * log10_texels_3d, 63 - 19 * log10_texels_3d);
- bmc_autoset = 50;
- maxiters_autoset = 1;
- preset_has_been_set++;
- }
- else if (!strcmp(argv[argidx], "-medium"))
- {
- argidx++;
- plimit_autoset = 25;
- oplimit_autoset = 1.2f;
- mincorrel_autoset = 0.75f;
- dblimit_autoset_2d = MAX(95 - 35 * log10_texels_2d, 70 - 19 * log10_texels_2d);
- dblimit_autoset_3d = MAX(95 - 35 * log10_texels_3d, 70 - 19 * log10_texels_3d);
- bmc_autoset = 75;
- maxiters_autoset = 2;
- preset_has_been_set++;
- }
- else if (!strcmp(argv[argidx], "-thorough"))
- {
- argidx++;
- plimit_autoset = 100;
- oplimit_autoset = 2.5f;
- mincorrel_autoset = 0.95f;
- dblimit_autoset_2d = MAX(105 - 35 * log10_texels_2d, 77 - 19 * log10_texels_2d);
- dblimit_autoset_3d = MAX(105 - 35 * log10_texels_3d, 77 - 19 * log10_texels_3d);
- bmc_autoset = 95;
- maxiters_autoset = 4;
- preset_has_been_set++;
- }
- else if (!strcmp(argv[argidx], "-exhaustive"))
- {
- argidx++;
- plimit_autoset = PARTITION_COUNT;
- oplimit_autoset = 1000.0f;
- mincorrel_autoset = 0.99f;
- dblimit_autoset_2d = 999.0f;
- dblimit_autoset_3d = 999.0f;
- bmc_autoset = 100;
- maxiters_autoset = 4;
- preset_has_been_set++;
- }
- else if (!strcmp(argv[argidx], "-j"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-j switch with no argument\n");
- return 1;
- }
- thread_count = atoi(argv[argidx - 1]);
- }
- else if (!strcmp(argv[argidx], "-linsrgb"))
- {
- argidx++;
- linearize_srgb = 1;
- dblimit_user_specified = 60;
- dblimit_set_by_user = 1;
- }
- else if (!strcmp(argv[argidx], "-yflip"))
- {
- argidx++;
- y_flip = 1;
- }
- else if (!strcmp(argv[argidx], "-mpsnr"))
- {
- argidx += 3;
- if (argidx > argc)
- {
- printf("-mpsnr switch with less than 2 arguments\n");
- return 1;
- }
- low_fstop = atoi(argv[argidx - 2]);
- high_fstop = atoi(argv[argidx - 1]);
- if (high_fstop < low_fstop)
- {
- printf("For -mpsnr switch, the argument cannot be greater than the\n" "high argument.\n");
- return 1;
- }
- }
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- else if (!strcmp(argv[argidx], "-diag"))
- {
- argidx += 2;
- if (argidx > argc)
- {
- printf("-diag switch with no argument\n");
- return 1;
- }
-
- diagnostics_tile = atoi(argv[argidx - 1]);
- }
- else if (!strcmp(argv[argidx], "-bmstat"))
- {
- argidx++;
- print_block_mode_histogram = 1;
- }
- else if (!strcmp(argv[argidx], "-pte"))
- {
- argidx++;
- print_tile_errors = 1;
- }
- else if (!strcmp(argv[argidx], "-stats"))
- {
- argidx++;
- print_statistics = 1;
- }
- #endif
- // Option: Encode a 3D image from an array of 2D images.
- else if (!strcmp(argv[argidx], "-array"))
- {
- // Only supports compressing (not decompressing or comparison).
- if (op_mode != ASTC_ENCODE)
- {
- printf("-array switch given when not compressing files - decompression and comparison of arrays not supported.\n");
- return 1;
- }
-
- // Image depth must be specified.
- if (argidx + 2 > argc)
- {
- printf("-array switch given, but no array size (image depth) given.\n");
- return 1;
- }
- argidx++;
-
- // Read array size (image depth).
- if (!sscanf(argv[argidx], "%d", &array_size) || array_size == 0)
- {
- printf("Invalid array size (image depth) given with -array option: \"%s\".\n", argv[argidx]);
- return 1;
- }
- argidx++;
- }
- else
- {
- printf("Commandline argument \"%s\" not recognized\n", argv[argidx]);
- return 1;
- }
- }
-
- if (!input_filename)
- {
- if (op_mode == ASTC_IMAGE_COMPARE)
- {
- printf("ERROR: Input file A not specified\n");
- }
- else
- {
- printf("ERROR: Input file not specified\n");
- }
- return 1;
- }
-
- if (!output_filename)
- {
- if (op_mode == ASTC_IMAGE_COMPARE)
- {
- printf("ERROR: Input file B not specified\n");
- }
- else
- {
- printf("ERROR: Output file not specified\n");
- }
- return 1;
- }
-
- if (op_mode == ASTC_IMAGE_COMPARE)
- {
- compare_two_files(input_filename, output_filename, low_fstop, high_fstop, linearize_srgb);
- return 0;
- }
-
- float texel_avg_error_limit_2d = 0.0f;
- float texel_avg_error_limit_3d = 0.0f;
-
- if (op_mode == ASTC_ENCODE || op_mode == ASTC_ENCODE_AND_DECODE)
- {
- // if encode, process the parsed command line values
- if (preset_has_been_set != 1)
- {
- printf("For encoding, need to specify exactly one performance-quality\n"
- "trade-off preset option. The available presets are:\n"
- " -fast\n" " -medium\n" " -thorough\n" " -exhaustive\n");
- return 1;
- }
-
- int partitions_to_test = plimit_set_by_user ? plimit_user_specified : plimit_autoset;
- float dblimit_2d = dblimit_set_by_user ? dblimit_user_specified : dblimit_autoset_2d;
- float dblimit_3d = dblimit_set_by_user ? dblimit_user_specified : dblimit_autoset_3d;
- float oplimit = oplimit_set_by_user ? oplimit_user_specified : oplimit_autoset;
- float mincorrel = mincorrel_set_by_user ? mincorrel_user_specified : mincorrel_autoset;
-
- int maxiters = maxiters_set_by_user ? maxiters_user_specified : maxiters_autoset;
- ewp.max_refinement_iters = maxiters;
-
- ewp.block_mode_cutoff = (bmc_set_by_user ? bmc_user_specified : bmc_autoset) / 100.0f;
-
- if (rgb_force_use_of_hdr == 0)
- {
- texel_avg_error_limit_2d = powf(0.1f, dblimit_2d * 0.1f) * 65535.0f * 65535.0f;
- texel_avg_error_limit_3d = powf(0.1f, dblimit_3d * 0.1f) * 65535.0f * 65535.0f;
- }
- else
- {
- texel_avg_error_limit_2d = 0.0f;
- texel_avg_error_limit_3d = 0.0f;
- }
-
- ewp.partition_1_to_2_limit = oplimit;
- ewp.lowest_correlation_cutoff = mincorrel;
- ewp.partition_search_limit = astc::clampi(partitions_to_test, 1, PARTITION_COUNT);
-
- // if diagnostics are run, force the thread count to 1.
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (diagnostics_tile >= 0 ||
- print_tile_errors > 0 ||
- print_statistics > 0)
- {
- thread_count = 1;
- thread_count_autodetected = 0;
- }
- #endif
-
- if (thread_count < 1)
- {
- thread_count = get_cpu_count();
- thread_count_autodetected = 1;
- }
-
-
- // Specifying the error weight of a color component as 0 is not allowed.
- // If weights are 0, then they are instead set to a small positive value.
-
- float max_color_component_weight = MAX(MAX(ewp.rgba_weights[0], ewp.rgba_weights[1]),
- MAX(ewp.rgba_weights[2], ewp.rgba_weights[3]));
- ewp.rgba_weights[0] = MAX(ewp.rgba_weights[0], max_color_component_weight / 1000.0f);
- ewp.rgba_weights[1] = MAX(ewp.rgba_weights[1], max_color_component_weight / 1000.0f);
- ewp.rgba_weights[2] = MAX(ewp.rgba_weights[2], max_color_component_weight / 1000.0f);
- ewp.rgba_weights[3] = MAX(ewp.rgba_weights[3], max_color_component_weight / 1000.0f);
-
-
- // print all encoding settings unless specifically told otherwise.
- if (!silentmode)
- {
- printf("Encoding settings:\n\n");
- if (zdim_3d == 1)
- {
- printf("2D Block size: %dx%d (%.2f bpp)\n", xdim_2d, ydim_2d, 128.0 / (xdim_2d * ydim_2d));
- }
- else
- {
- printf("3D Block size: %dx%dx%d (%.2f bpp)\n", xdim_3d, ydim_3d, zdim_3d, 128.0 / (xdim_3d * ydim_3d * zdim_3d));
- }
- printf("Radius for mean-and-stdev calculations: %d texels\n", ewp.mean_stdev_radius);
- printf("RGB power: %g\n", (double)ewp.rgb_power);
- printf("RGB base-weight: %g\n", (double)ewp.rgb_base_weight);
- printf("RGB local-mean weight: %g\n", (double)ewp.rgb_mean_weight);
- printf("RGB local-stdev weight: %g\n", (double)ewp.rgb_stdev_weight);
- printf("RGB mean-and-stdev mixing across color channels: %g\n", (double)ewp.rgb_mean_and_stdev_mixing);
- printf("Alpha power: %g\n", (double)ewp.alpha_power);
- printf("Alpha base-weight: %g\n", (double)ewp.alpha_base_weight);
- printf("Alpha local-mean weight: %g\n", (double)ewp.alpha_mean_weight);
- printf("Alpha local-stdev weight: %g\n", (double)ewp.alpha_stdev_weight);
- printf("RGB weights scale with alpha: ");
- if (ewp.enable_rgb_scale_with_alpha)
- printf("enabled (radius=%d)\n", ewp.alpha_radius);
- else
- printf("disabled\n");
- printf("Color channel relative weighting: R=%g G=%g B=%g A=%g\n", (double)ewp.rgba_weights[0], (double)ewp.rgba_weights[1], (double)ewp.rgba_weights[2], (double)ewp.rgba_weights[3]);
- printf("Block-artifact suppression parameter : %g\n", (double)ewp.block_artifact_suppression);
- printf("Number of distinct partitionings to test: %d (%s)\n", ewp.partition_search_limit, plimit_set_by_user ? "specified by user" : "preset");
- printf("PSNR decibel limit: 2D: %f 3D: %f (%s)\n", (double)dblimit_2d, (double)dblimit_3d, dblimit_set_by_user ? "specified by user" : "preset");
- printf("1->2 partition limit: %f\n", (double)oplimit);
- printf("Dual-plane color-correlation cutoff: %f (%s)\n", (double)mincorrel, mincorrel_set_by_user ? "specified by user" : "preset");
- printf("Block Mode Percentile Cutoff: %f (%s)\n", (double)(ewp.block_mode_cutoff * 100.0f), bmc_set_by_user ? "specified by user" : "preset");
- printf("Max refinement iterations: %d (%s)\n", ewp.max_refinement_iters, maxiters_set_by_user ? "specified by user" : "preset");
- printf("Thread count : %d (%s)\n", thread_count, thread_count_autodetected ? "autodetected" : "specified by user");
- printf("\n");
- }
- }
-
- int padding = MAX(ewp.mean_stdev_radius, ewp.alpha_radius);
-
- // determine encoding bitness as follows:
- // if enforced by the output format, follow the output format's result
- // else use decode_mode to pick bitness.
- int out_bitness = (op_mode == ASTC_DECODE || op_mode == ASTC_ENCODE_AND_DECODE) ? get_output_filename_enforced_bitness(output_filename) : -1;
- if (out_bitness == -1)
- {
- out_bitness = (decode_mode == DECODE_HDR) ? 16 : 8;
- }
-
- int xdim = -1;
- int ydim = -1;
- int zdim = -1;
-
- // Temporary image array (for merging multiple 2D images into one 3D image).
- int *load_results = nullptr;
- astc_codec_image **input_images = nullptr;
-
- int load_result = 0;
- astc_codec_image *input_image = nullptr;
- astc_codec_image *output_image = nullptr;
- int input_components = 0;
-
- int input_image_is_hdr = 0;
-
- // load image
- if (op_mode == ASTC_ENCODE || op_mode == ASTC_ENCODE_AND_DECODE)
- {
- // Allocate arrays for image data and load results.
- load_results = new int[array_size];
- input_images = new astc_codec_image *[array_size];
-
- // Iterate over all input images.
- for (int image_index = 0; image_index < array_size; image_index++)
- {
- // 2D input data.
- if (array_size == 1)
- {
- input_images[image_index] = astc_codec_load_image(
- input_filename, padding, y_flip, linearize_srgb,
- rgb_force_use_of_hdr, alpha_force_use_of_hdr,
- &load_results[image_index]);
- }
- // 3D input data - multiple 2D images.
- else
- {
- char new_input_filename[256];
-
- // Check for extension: .
- if (nullptr == strrchr(input_filename, '.'))
- {
- printf("Unable to determine file type from extension: %s\n", input_filename);
- return 1;
- }
-
- // Construct new file name and load: _N.
- strcpy(new_input_filename, input_filename);
- sprintf(strrchr(new_input_filename, '.'), "_%d%s", image_index, strrchr(input_filename, '.'));
- input_images[image_index] = astc_codec_load_image
- (new_input_filename, padding, y_flip, linearize_srgb,
- rgb_force_use_of_hdr, alpha_force_use_of_hdr,
- &load_results[image_index]);
-
- // If image loaded correctly, check image is not 3D.
- if ((load_results[image_index] >= 0) &&
- (input_images[image_index]->zsize != 1))
- {
- printf("3D source images not supported with -array option: %s\n", new_input_filename);
- return 1;
- }
- }
-
- // Check load result.
- if (load_results[image_index] < 0)
- {
- return 1;
- }
-
- // Check format matches other slices.
- if (load_results[image_index] != load_results[0])
- {
- printf("Mismatching image format - image 0 and %d are a different format\n", image_index);
- return 1;
- }
- }
-
- load_result = load_results[0];
-
- // Assign input image.
- if (array_size == 1)
- {
- input_image = input_images[0];
- }
- // Merge input image data.
- else
- {
- int z, xsize, ysize, zsize, bitness, slice_size;
-
- xsize = input_images[0]->xsize;
- ysize = input_images[0]->ysize;
- zsize = array_size;
- bitness = (load_result & 0x80) ? 16 : 8;
- slice_size = (xsize + (2 * padding)) * (ysize + (2 * padding));
-
- // Allocate image memory.
- input_image = alloc_image(bitness, xsize, ysize, zsize, padding);
-
- // Combine 2D source images into one 3D image (skip padding slices as these don't exist in 2D textures).
- for (z = padding; z < zsize + padding; z++)
- {
- if (bitness == 8)
- {
- memcpy(*input_image->data8[z], *input_images[z - padding]->data8[0], slice_size * 4 * sizeof(uint8_t));
- }
- else
- {
- memcpy(*input_image->data16[z], *input_images[z - padding]->data16[0], slice_size * 4 * sizeof(uint16_t));
- }
- }
-
- // Clean up temporary images.
- for (int i = 0; i < array_size; i++)
- {
- free_image(input_images[i]);
- }
-
- // Clamp texels outside the actual image area.
- fill_image_padding_area(input_image);
- }
-
- delete[] input_images;
- input_images = nullptr;
-
- delete[] load_results;
- load_results = nullptr;
-
- input_components = load_result & 7;
- input_image_is_hdr = (load_result & 0x80) ? 1 : 0;
-
- if ((input_image->zsize > 1) && (zdim_3d == 1))
- {
- printf("ERROR: 3D input data for a 2D ASTC block format\n");
- exit(1);
- }
-
- if (zdim_3d != 1)
- {
- xdim = xdim_3d;
- ydim = ydim_3d;
- zdim = zdim_3d;
- ewp.texel_avg_error_limit = texel_avg_error_limit_3d;
- }
- else
- {
- xdim = xdim_2d;
- ydim = ydim_2d;
- zdim = 1;
- ewp.texel_avg_error_limit = texel_avg_error_limit_2d;
- }
-
- expand_block_artifact_suppression(xdim, ydim, zdim, &ewp);
-
- if (!silentmode)
- {
- printf("%s: %dD %s image, %d x %d x %d, %d components\n\n",
- input_filename, input_image->zsize > 1 ? 3 : 2, input_image_is_hdr ? "HDR" : "LDR",
- input_image->xsize, input_image->ysize, input_image->zsize, load_result & 7);
- }
-
- if (padding > 0 ||
- ewp.rgb_mean_weight != 0.0f || ewp.rgb_stdev_weight != 0.0f ||
- ewp.alpha_mean_weight != 0.0f || ewp.alpha_stdev_weight != 0.0f)
- {
- if (!silentmode)
- {
- printf("Computing texel-neighborhood means and variances ... ");
- fflush(stdout);
- }
-
- compute_averages_and_variances(
- input_image,
- ewp.rgb_power,
- ewp.alpha_power,
- ewp.mean_stdev_radius,
- ewp.alpha_radius,
- linearize_srgb,
- swz_encode,
- thread_count);
-
- if (!silentmode)
- {
- printf("done\n");
- fflush(stdout);
- }
- }
- }
-
- start_coding_time = get_time();
-
- if (op_mode == ASTC_DECODE)
- {
- output_image = load_astc_file(input_filename, out_bitness, decode_mode, swz_decode,
- linearize_srgb, rgb_force_use_of_hdr, alpha_force_use_of_hdr);
- }
-
- // process image, if relevant
- if (op_mode == ASTC_ENCODE_AND_DECODE)
- {
- output_image = pack_and_unpack_astc_image(input_image, xdim, ydim, zdim, &ewp, decode_mode, swz_encode, swz_decode, out_bitness, thread_count);
- }
-
- end_coding_time = get_time();
-
- // print PSNR if encoding
- if (op_mode == ASTC_ENCODE_AND_DECODE)
- {
- compute_error_metrics(input_image_is_hdr, input_components, input_image, output_image, low_fstop, high_fstop);
- }
-
- // store image
- if (op_mode == ASTC_DECODE || op_mode == ASTC_ENCODE_AND_DECODE)
- {
- int store_result = -1;
- const char *format_string = "";
-
- store_result = astc_codec_store_image(output_image, output_filename, &format_string, y_flip);
- if (store_result < 0)
- {
- printf("ERROR: Failed to write output image %s\n", output_filename);
- return 1;
- }
- }
-
- if (op_mode == ASTC_ENCODE)
- {
- store_astc_file(input_image, output_filename, xdim, ydim, zdim, &ewp, decode_mode, swz_encode, thread_count);
- }
-
- free_image(input_image);
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_block_mode_histogram)
- {
- printf("%s ", argv[2]);
- printf("%d %d ", xdim_2d, ydim_2d);
- for (int i = 0; i < 2048; i++)
- {
- printf(" %d", block_mode_histogram[i]);
- }
- printf("\n");
- }
- #endif
-
- end_time = get_time();
-
- if (op_mode == ASTC_ENCODE_AND_DECODE || !silentmode)
- {
- printf("\nCoding time\n");
- printf("-----------\n");
- printf("Total time: %6.2f s\n", end_time - start_time);
- printf("Coding time: %6.2f s\n", end_coding_time - start_coding_time);
- }
-
- return 0;
-}
diff --git a/Source/astcenc.h b/Source/astcenc.h
new file mode 100644
index 0000000..5e919dc
--- /dev/null
+++ b/Source/astcenc.h
@@ -0,0 +1,347 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2020 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief The core astcenc codec library interface.
+ *
+ * This interface is the entry point to the core astcenc codec. It aims to be
+ * easy to use for non-experts, but also to allow experts to have fine control
+ * over the compressor heuristics. The core codec only handles compression and
+ * decompression, transferring all inputs and outputs via memory buffers.
+ *
+ * While the aim is that we keep this interface mostly stable, it should be
+ * viewed as a mutable interface tied to a specific source version. We are not
+ * trying to maintain backwards compatibility across codec versions.
+ *
+ * The API state management is based around an explicit context object. The
+ * context is the container for all allocated resources -- memory and threads
+ * -- needed to compress and decompress for a single image configuration. A
+ * context keeps the state needed to process one image at a time, but can be
+ * used to sequentially compress multiple images using the same configuration.
+ * This allows setup overheads to be amortized over multiple images, which is
+ * particularly important when images are small. An application can process
+ * multiple images concurrently by allocating multiple contexts.
+ *
+ * The API allows compression of a single image by using multiple threads
+ * within the scope of a single context. The API supports two mechanisms for
+ * this: automatic and manual. Automatic threading uses threads created and
+ * managed by the codec itself; no user setup needed - just configure the
+ * thread count and call compress from a single application thread.
+ * Manual threading uses user-created threads, which is a common pattern in
+ * some developer tools using persistent pools of worker threads. For this
+ * configure the codec with the maximum thread count you'll use and then invoke
+ * compress from each worker thread.
+ *
+ * To catch obvious input/output buffer sizing issues, which can cause security
+ * and stability problems, all transfer buffers are explicitly sized.
+ *
+ * Automatic threading
+ * ===================
+ *
+ * In pseudocode, the usage for automatic threading looks like this:
+ *
+ * // Configure the compressor run
+ * astcenc_config my_config;
+ * astcenc_init_config(..., &my_config);
+ *
+ * // Power users can modify the config after it is initialized and
+ * // before allocating the context with it.
+ *
+ * // Allocate working state given config and thread_count
+ * astcenc_context* my_context;
+ * astcenc_context_alloc(&my_config, thread_count, &my_context);
+ *
+ * // Compress the image with automatic multithreading
+ * foreach image:
+ * astc_image input;
+ * uint8_t* output;
+ * astcenc_compress_image(&my_context, &input, output, -1);
+ *
+ * // Clean up
+ * astcenc_context_free(my_context);
+ *
+ * Manual threading
+ * ================
+ *
+ * In pseudocode, the usage for manual user threading looks like this:
+ *
+ * // Configure the compressor run
+ * astcenc_config my_config;
+ * astcenc_flags my_flags = ASTCENC_USE_USER_THREADS | ...;
+ * astcenc_init_config(..., my_flags, &my_config);
+ *
+ * // Allocate working state given config and thread_count
+ * astcenc_context* my_context;
+ * astcenc_context_alloc(&my_config, thread_count, &my_context);
+ *
+ * // Compress the image with manually managed multithreading
+ * foreach image:
+ * astc_image input;
+ * uint8_t* output;
+ * for i in range(0, thread_count):
+ * astcenc_compress_image(&my_context, &input, output, i);
+ *
+ * // Wait for all threads to complete one image
+ * barrier();
+ *
+ * // Clean up
+ * astcenc_context_free(my_context);
+ */
+
+#ifndef ASTCENC_INCLUDED
+#define ASTCENC_INCLUDED
+
+#include
+#include
+
+/* ============================================================================
+ Data declarations
+============================================================================ */
+struct astcenc_context;
+
+// Return codes
+enum astcenc_error {
+ ASTCENC_SUCCESS = 0,
+ ASTCENC_ERR_OUT_OF_MEM,
+ ASTCENC_ERR_BAD_CPU_FLOAT,
+ ASTCENC_ERR_BAD_CPU_ISA,
+ ASTCENC_ERR_BAD_PARAM,
+ ASTCENC_ERR_BAD_BLOCK_SIZE,
+ ASTCENC_ERR_BAD_PROFILE,
+ ASTCENC_ERR_BAD_PRESET,
+ ASTCENC_ERR_BAD_SWIZZLE,
+ ASTCENC_ERR_BAD_FLAGS,
+ ASTCENC_ERR_NOT_IMPLEMENTED
+};
+
+// Compression color feature profile
+enum astcenc_profile {
+ ASTCENC_PRF_LDR_SRGB = 0,
+ ASTCENC_PRF_LDR,
+ ASTCENC_PRF_HDR_RGB_LDR_A,
+ ASTCENC_PRF_HDR
+};
+
+// Compression quality preset
+enum astcenc_preset {
+ ASTCENC_PRE_FAST = 0,
+ ASTCENC_PRE_MEDIUM,
+ ASTCENC_PRE_THOROUGH,
+ ASTCENC_PRE_EXHAUSTIVE
+};
+
+// Image channel data type
+enum astcenc_type {
+ ASTCENC_TYP_U8 = 0,
+ ASTCENC_TYP_F16
+};
+
+// Image channel swizzles
+enum astcenc_swz {
+ ASTCENC_SWZ_R = 0,
+ ASTCENC_SWZ_G = 1,
+ ASTCENC_SWZ_B = 2,
+ ASTCENC_SWZ_A = 3,
+ ASTCENC_SWZ_0 = 4,
+ ASTCENC_SWZ_1 = 5,
+ ASTCENC_SWZ_Z = 6
+};
+
+// Image channel swizzles
+struct astcenc_swizzle {
+ astcenc_swz r;
+ astcenc_swz g;
+ astcenc_swz b;
+ astcenc_swz a;
+};
+
+// Config mode flags
+static const unsigned int ASTCENC_FLG_MAP_NORMAL = 1 << 0;
+static const unsigned int ASTCENC_FLG_MAP_MASK = 1 << 1;
+static const unsigned int ASTCENC_FLG_USE_ALPHA_WEIGHT = 1 << 2;
+static const unsigned int ASTCENC_FLG_USE_PERCEPTUAL = 1 << 3;
+static const unsigned int ASTCENC_FLG_USE_USER_THREADS = 1 << 4;
+static const unsigned int ASTCENC_FLG_USE_LINEARIZED_SRGB = 1 << 5;
+
+static const unsigned int ASTCENC_ALL_FLAGS =
+ ASTCENC_FLG_MAP_NORMAL |
+ ASTCENC_FLG_MAP_MASK |
+ ASTCENC_FLG_USE_ALPHA_WEIGHT |
+ ASTCENC_FLG_USE_PERCEPTUAL |
+ ASTCENC_FLG_USE_USER_THREADS |
+ ASTCENC_FLG_USE_LINEARIZED_SRGB;
+
+// Config structure
+struct astcenc_config {
+ astcenc_profile profile;
+ unsigned int flags;
+ unsigned int block_x;
+ unsigned int block_y;
+ unsigned int block_z;
+ unsigned int v_rgba_radius;
+ float v_rgba_mean_stdev_mix;
+ float v_rgb_power;
+ float v_rgb_base;
+ float v_rgb_mean;
+ float v_rgb_stdev;
+ float v_a_power;
+ float v_a_base;
+ float v_a_mean;
+ float v_a_stdev;
+ float cw_r_weight;
+ float cw_g_weight;
+ float cw_b_weight;
+ float cw_a_weight;
+ unsigned int a_scale_radius;
+ float b_deblock_weight;
+ unsigned int tune_partition_limit;
+ unsigned int tune_block_mode_limit;
+ unsigned int tune_refinement_limit;
+ float tune_db_limit;
+ float tune_partition_early_out_limit;
+ float tune_two_plane_early_out_limit;
+};
+
+/**
+ * Structure to store an uncompressed 2D image, or a slice from a 3D image.
+ *
+ * @param dim_x The x dimension of the image, in texels.
+ * @param dim_y The y dimension of the image, in texels.
+ * @param dim_z The z dimension of the image, in texels.
+ * @param channels The number of color channels.
+ */
+struct astcenc_image {
+ unsigned int dim_x;
+ unsigned int dim_y;
+ unsigned int dim_z;
+ unsigned int dim_pad;
+ uint8_t ***data8;
+ uint16_t ***data16;
+};
+
+/**
+ * Populate a compressor config based on default settings.
+ *
+ * Power users can edit the returned config struct to apply manual fine tuning
+ * before creating the context.
+ *
+ * @param profile The color profile.
+ * @param block_x The ASTC block size X dimension.
+ * @param block_y The ASTC block size Y dimension.
+ * @param block_z The ASTC block size Z dimension.
+ * @param preset The search quality preset.
+ * @param flags Any ASTCENC_FLG_* flag bits.
+ * @param config The output config struct to populate.
+ *
+ * @return ASTCENC_SUCCESS on success, or an error if the inputs are invalid
+ * either individually, or in combination.
+ */
+astcenc_error astcenc_init_config(
+ astcenc_profile profile,
+ unsigned int block_x,
+ unsigned int block_y,
+ unsigned int block_z,
+ astcenc_preset preset,
+ unsigned int flags,
+ astcenc_config& config);
+
+/**
+ * Allocate a new compressor context based on the settings in the config.
+ *
+ * This function allocates all of the memory resources and threads needed by
+ * the compressor. This can be slow, so it is recommended that contexts are
+ * reused to serially compress multiple images in order to amortize setup cost.
+ *
+ * @param config The codec config.
+ * @param thread_count The thread count to configure for. This will allocate
+ * new threads unless config created with USE_USER_THREADS.
+ * If thread count is zero, the compressor will auto-set
+ * the thread count to the host CPU count.
+ * @param context Output location to store an opaque context pointer.
+ *
+ * @return ASTCENC_SUCCESS on success, or an error if context creation failed.
+ */
+astcenc_error astcenc_context_alloc(
+ const astcenc_config& config,
+ unsigned int thread_count,
+ astcenc_context** context);
+
+/**
+ * Compress an image.
+ *
+ * Note: User must allocate all output memory before calling this function.
+ *
+ * @param context The codec context.
+ * @param image The input image.
+ * @param data_out Pointer to byte array to store the output.
+ * @param data_len Length of the data array, in bytes.
+ * @param thread_index The thread index [0..N-1] of the calling thread. All
+ * N threads must call this function exactly once per
+ * decompression, and all threads must exit this function
+ * before a new image can be compressed or decompressed
+ *
+ * @return ASTCENC_SUCCESS on success, or an error if compression failed.
+ */
+astcenc_error astcenc_compress_image(
+ astcenc_context* context,
+ astcenc_image& image,
+ astcenc_swizzle swizzle,
+ uint8_t* data_out,
+ size_t data_len,
+ unsigned int thread_index);
+
+/**
+ * Decompress an image.
+ *
+ * Note: User must allocate all output memory before calling this function.
+ *
+ * @param context The codec context.
+ * @param data Pointer to compressed data.
+ * @param data_len Length of the compressed data, in bytes.
+ * @param image_out The output image.
+ * @param thread_index The thread index [0..N-1] of the calling thread. All
+ * N threads must call this function exactly once per
+ * decompression, and all threads must exit this function
+ * before a new image can be compressed or decompressed.
+ *
+ * @return ASTCENC_SUCCESS on success, or an error if decompression failed.
+ */
+astcenc_error astcenc_decompress_image(
+ astcenc_context* context,
+ uint8_t* data,
+ size_t data_len,
+ astcenc_image& image_out,
+ astcenc_swizzle swizzle,
+ unsigned int thread_index);
+
+/**
+ * Free the compressor context.
+ */
+void astcenc_context_free(
+ astcenc_context* context);
+
+/**
+ * Utility to get a string for specific status code.
+ *
+ * @param status The status value.
+ *
+ * @return A human readable nul-terminated string.
+ */
+const char* astcenc_get_error_string(
+ astcenc_error status);
+
+#endif
diff --git a/Source/astc_averages_and_directions.cpp b/Source/astcenc_averages_and_directions.cpp
similarity index 99%
rename from Source/astc_averages_and_directions.cpp
rename to Source/astcenc_averages_and_directions.cpp
index 2afdda5..b48c76b 100644
--- a/Source/astc_averages_and_directions.cpp
+++ b/Source/astcenc_averages_and_directions.cpp
@@ -19,7 +19,7 @@
* @brief Functions for finding dominant direction of a set of colors.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
#ifdef DEBUG_CAPTURE_NAN
#ifndef _GNU_SOURCE
@@ -99,20 +99,22 @@ void compute_averages_and_directions_rgba(
float4 best_vector = sum_xp;
float best_sum = prod_xp;
+
if (prod_yp > best_sum)
{
best_vector = sum_yp;
best_sum = prod_yp;
}
+
if (prod_zp > best_sum)
{
best_vector = sum_zp;
best_sum = prod_zp;
}
+
if (prod_wp > best_sum)
{
best_vector = sum_wp;
- best_sum = prod_wp;
}
directions_rgba[partition] = best_vector;
@@ -184,15 +186,16 @@ void compute_averages_and_directions_rgb(
float3 best_vector = sum_xp;
float best_sum = prod_xp;
+
if (prod_yp > best_sum)
{
best_vector = sum_yp;
best_sum = prod_yp;
}
+
if (prod_zp > best_sum)
{
best_vector = sum_zp;
- best_sum = prod_zp;
}
directions_rgb[partition] = best_vector;
@@ -298,19 +301,23 @@ void compute_averages_and_directions_3_components(
float3 best_vector = sum_xp;
float best_sum = prod_xp;
+
if (prod_yp > best_sum)
{
best_vector = sum_yp;
best_sum = prod_yp;
}
+
if (prod_zp > best_sum)
{
best_vector = sum_zp;
- best_sum = prod_zp;
}
if (dot(best_vector, best_vector) < 1e-18f)
+ {
best_vector = float3(1.0f, 1.0f, 1.0f);
+ }
+
directions[partition] = best_vector;
}
@@ -345,16 +352,12 @@ void compute_averages_and_directions_2_components(
data_vr = blk->data_r;
data_vg = blk->data_b;
}
- else if (component1 == 1 && component2 == 2)
+ else // (component1 == 1 && component2 == 2)
{
texel_weights = ewb->texel_weight_gb;
data_vr = blk->data_g;
data_vg = blk->data_b;
}
- else
- {
- ASTC_CODEC_INTERNAL_ERROR();
- }
for (partition = 0; partition < partition_count; partition++)
{
@@ -400,10 +403,10 @@ void compute_averages_and_directions_2_components(
float2 best_vector = sum_xp;
float best_sum = prod_xp;
+
if (prod_yp > best_sum)
{
best_vector = sum_yp;
- best_sum = prod_yp;
}
directions[partition] = best_vector;
diff --git a/Source/astc_block_sizes2.cpp b/Source/astcenc_block_sizes2.cpp
similarity index 99%
rename from Source/astc_block_sizes2.cpp
rename to Source/astcenc_block_sizes2.cpp
index 597571e..4ba9c1f 100644
--- a/Source/astc_block_sizes2.cpp
+++ b/Source/astcenc_block_sizes2.cpp
@@ -19,7 +19,7 @@
* @brief Functions to generate block size descriptor and decimation tables.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
// return 0 on invalid mode, 1 on valid mode.
static int decode_block_mode_2d(
diff --git a/Source/astc_color_quantize.cpp b/Source/astcenc_color_quantize.cpp
similarity index 98%
rename from Source/astc_color_quantize.cpp
rename to Source/astcenc_color_quantize.cpp
index 9afd728..c7bdb8a 100644
--- a/Source/astc_color_quantize.cpp
+++ b/Source/astcenc_color_quantize.cpp
@@ -21,11 +21,7 @@
#include
-#include "astc_codec_internals.h"
-
-#ifdef DEBUG_PRINT_DIAGNOSTICS
- #include
-#endif
+#include "astcenc_internal.h"
/*
quantize an LDR RGB color. Since this is a fall-back encoding, we cannot actually
@@ -1109,14 +1105,10 @@ static void quantize_hdr_rgbo3(
int s_uquantval;
quantize_and_unquantize_retain_top_four_bits(quantization_level, s_lowbits, &s_quantval, &s_uquantval);
-
- s_intval = (s_intval & ~0x1f) | (s_uquantval & 0x1f);
- s_fval = s_intval * mode_rscale;
output[0] = r_quantval;
output[1] = g_quantval;
output[2] = b_quantval;
output[3] = s_quantval;
-
return;
}
@@ -1866,16 +1858,6 @@ int pack_color_endpoints(
int* output,
int quantization_level
) {
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("%s : format=%d quantization_level=%d\n", __func__, format, quantization_level);
- printf("Color 0: <%g %g %g %g>\n", color0.x, color0.y, color0.z, color0.w);
- printf("Color 1: <%g %g %g %g>\n", color1.x, color1.y, color1.z, color1.w);
-
- }
- #endif
-
// we do not support negative colors.
color0.x = MAX(color0.x, 0.0f);
color0.y = MAX(color0.y, 0.0f);
@@ -1886,8 +1868,9 @@ int pack_color_endpoints(
color1.z = MAX(color1.z, 0.0f);
color1.w = MAX(color1.w, 0.0f);
- int retval;
+ int retval = 0;
+ // TODO: Make format an endpoint_fmt enum type
switch (format)
{
case FMT_RGB:
@@ -1994,23 +1977,7 @@ int pack_color_endpoints(
quantize_hdr_rgb_alpha3(color0, color1, output, quantization_level);
retval = FMT_HDR_RGBA;
break;
-
- default:
- ASTC_CODEC_INTERNAL_ERROR();
}
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- int i;
- printf("Quantized to format %d\n", retval);
- printf("Quantized color:");
-
- for (i = 0; i < 8; i++)
- printf(" %X", output[i]);
- printf("\n\n");
- }
- #endif
-
return retval;
}
diff --git a/Source/astc_color_unquantize.cpp b/Source/astcenc_color_unquantize.cpp
similarity index 98%
rename from Source/astc_color_unquantize.cpp
rename to Source/astcenc_color_unquantize.cpp
index 76e4d36..b23f7a1 100644
--- a/Source/astc_color_unquantize.cpp
+++ b/Source/astcenc_color_unquantize.cpp
@@ -19,7 +19,7 @@
* @brief Functions for color unquantization.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
static int rgb_delta_unpack(
const int input[6],
@@ -795,8 +795,7 @@ static void hdr_rgb_hdr_alpha_unpack3(
}
void unpack_color_endpoints(
- const astc_codec_image* image,
- astc_decode_mode decode_mode,
+ astcenc_profile decode_mode,
int format,
int quantization_level,
const int* input,
@@ -808,6 +807,7 @@ void unpack_color_endpoints(
) {
*nan_endpoint = 0;
+ // TODO: Make format the correct enum type
switch (format)
{
case FMT_LUMINANCE:
@@ -905,14 +905,11 @@ void unpack_color_endpoints(
*alpha_hdr = 1;
hdr_rgb_hdr_alpha_unpack3(input, quantization_level, output0, output1);
break;
-
- default:
- ASTC_CODEC_INTERNAL_ERROR();
}
if (*alpha_hdr == -1)
{
- if (image->alpha_force_use_of_hdr)
+ if (decode_mode == ASTCENC_PRF_HDR)
{
output0->w = 0x7800;
output1->w = 0x7800;
@@ -928,7 +925,7 @@ void unpack_color_endpoints(
switch (decode_mode)
{
- case DECODE_LDR_SRGB:
+ case ASTCENC_PRF_LDR_SRGB:
if (*rgb_hdr == 1)
{
output0->x = 0xFF00;
@@ -955,7 +952,7 @@ void unpack_color_endpoints(
*alpha_hdr = 0;
break;
- case DECODE_LDR:
+ case ASTCENC_PRF_LDR:
if (*rgb_hdr == 1)
{
output0->x = 0xFFFF;
@@ -983,8 +980,8 @@ void unpack_color_endpoints(
*alpha_hdr = 0;
break;
- case DECODE_HDR:
- case DECODE_HDRA:
+ case ASTCENC_PRF_HDR_RGB_LDR_A:
+ case ASTCENC_PRF_HDR:
if (*rgb_hdr == 0)
{
output0->x *= 257;
diff --git a/Source/astc_compress_symbolic.cpp b/Source/astcenc_compress_symbolic.cpp
similarity index 87%
rename from Source/astc_compress_symbolic.cpp
rename to Source/astcenc_compress_symbolic.cpp
index 7deff6d..c15b953 100644
--- a/Source/astc_compress_symbolic.cpp
+++ b/Source/astcenc_compress_symbolic.cpp
@@ -19,10 +19,11 @@
* @brief Functions to compress a symbolic block.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
-#include
-#include
+#include
+#include
+#include
#ifdef DEBUG_CAPTURE_NAN
#ifndef _GNU_SOURCE
@@ -40,8 +41,7 @@
* quality by moving each weight up by one or down by one quantization step.
*/
static int realign_weights(
- const astc_codec_image* image,
- astc_decode_mode decode_mode,
+ astcenc_profile decode_mode,
const block_size_descriptor* bsd,
const imageblock* blk,
const error_weight_block* ewb,
@@ -78,8 +78,7 @@ static int realign_weights(
for (int pa_idx = 0; pa_idx < partition_count; pa_idx++)
{
- unpack_color_endpoints(image,
- decode_mode,
+ unpack_color_endpoints(decode_mode,
scb->color_formats[pa_idx],
scb->color_quantization_level,
scb->color_values[pa_idx],
@@ -207,8 +206,7 @@ static int realign_weights(
function for compressing a block symbolically, given that we have already decided on a partition
*/
static void compress_symbolic_block_fixed_partition_1_plane(
- const astc_codec_image* image,
- astc_decode_mode decode_mode,
+ astcenc_profile decode_mode,
float mode_cutoff,
int max_refinement_iters,
const block_size_descriptor* bsd,
@@ -306,8 +304,6 @@ static void compress_symbolic_block_fixed_partition_1_plane(
weight_high_value[i] = 1.0f;
int decimation_mode = bsd->block_modes[i].decimation_mode;
- if (bsd->decimation_mode_percentile[decimation_mode] > mode_cutoff)
- ASTC_CODEC_INTERNAL_ERROR();
// compute weight bitcount for the mode
int bits_used_by_weights = compute_ise_bitcount(ixtab2[decimation_mode]->num_weights,
@@ -330,11 +326,6 @@ static void compress_symbolic_block_fixed_partition_1_plane(
// then, compute weight-errors for the weight mode.
qwt_errors[i] = compute_error_of_weight_set(&(eix[decimation_mode]), ixtab2[decimation_mode], flt_quantized_decimated_quantized_weights + MAX_WEIGHTS_PER_BLOCK * i);
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Block mode %d -> weight error = %f\n", i, qwt_errors[i]);
- #endif
}
// for each weighting mode, determine the optimal combination of color endpoint encodings
@@ -364,16 +355,6 @@ static void compress_symbolic_block_fixed_partition_1_plane(
int decimation_mode = bsd->block_modes[quantized_weight[i]].decimation_mode;
int weight_quantization_mode = bsd->block_modes[quantized_weight[i]].quantization_mode;
const decimation_table *it = ixtab2[decimation_mode];
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("Selected mode = %d\n", quantized_weight[i]);
- printf("Selected decimation mode = %d\n", decimation_mode);
- printf("Selected weight-quantization mode = %d\n", weight_quantization_mode);
- }
- #endif
-
u8_weight_src = u8_quantized_decimated_quantized_weights + MAX_WEIGHTS_PER_BLOCK * quantized_weight[i];
weights_to_copy = it->num_weights;
@@ -441,7 +422,7 @@ static void compress_symbolic_block_fixed_partition_1_plane(
// perform a final pass over the weights to try to improve them.
int adjustments = realign_weights(
- image, decode_mode, bsd, blk, ewb, scb, u8_weight_src, nullptr);
+ decode_mode, bsd, blk, ewb, scb, u8_weight_src, nullptr);
if (adjustments == 0)
break;
@@ -455,8 +436,7 @@ static void compress_symbolic_block_fixed_partition_1_plane(
}
static void compress_symbolic_block_fixed_partition_2_planes(
- const astc_codec_image* image,
- astc_decode_mode decode_mode,
+ astcenc_profile decode_mode,
float mode_cutoff,
int max_refinement_iters,
const block_size_descriptor* bsd,
@@ -730,7 +710,7 @@ static void compress_symbolic_block_fixed_partition_2_planes(
}
int adjustments = realign_weights(
- image, decode_mode, bsd, blk, ewb, scb, u8_weight1_src, u8_weight2_src);
+ decode_mode, bsd, blk, ewb, scb, u8_weight1_src, u8_weight2_src);
if (adjustments == 0)
break;
@@ -747,22 +727,21 @@ static void compress_symbolic_block_fixed_partition_2_planes(
}
void expand_block_artifact_suppression(
- int xdim,
- int ydim,
- int zdim,
+ unsigned int xdim,
+ unsigned int ydim,
+ unsigned int zdim,
error_weighting_params* ewp
) {
- int x, y, z;
float centerpos_x = (xdim - 1) * 0.5f;
float centerpos_y = (ydim - 1) * 0.5f;
float centerpos_z = (zdim - 1) * 0.5f;
float *bef = ewp->block_artifact_suppression_expanded;
- for (z = 0; z < zdim; z++)
+ for (unsigned int z = 0; z < zdim; z++)
{
- for (y = 0; y < ydim; y++)
+ for (unsigned int y = 0; y < ydim; y++)
{
- for (x = 0; x < xdim; x++)
+ for (unsigned int x = 0; x < xdim; x++)
{
float xdif = (x - centerpos_x) / xdim;
float ydif = (y - centerpos_y) / ydim;
@@ -1018,8 +997,7 @@ static void prepare_block_statistics(
for (i = 0; i < texels_per_block; i++)
{
float weight = ewb->texel_weight[i];
- if (weight < 0.0f)
- ASTC_CODEC_INTERNAL_ERROR();
+ assert(weight >= 0.0f);
weight_sum += weight;
float r = blk->data_r[i];
@@ -1106,13 +1084,9 @@ static void prepare_block_statistics(
*is_normal_map = nf_sum < (0.2f * (float)texels_per_block);
}
-#ifdef DEBUG_PRINT_DIAGNOSTICS
- int block_mode_histogram[2048];
-#endif
-
float compress_symbolic_block(
const astc_codec_image* input_image,
- astc_decode_mode decode_mode,
+ astcenc_profile decode_mode,
const block_size_descriptor* bsd,
const error_weighting_params* ewp,
const imageblock* blk,
@@ -1124,39 +1098,13 @@ float compress_symbolic_block(
int ypos = blk->ypos;
int zpos = blk->zpos;
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("Diagnostics of block of dimension %d x %d x %d\n\n", xdim, ydim, zdim);
-
- printf("XPos: %d YPos: %d ZPos: %d\n", xpos, ypos, zpos);
-
- printf("Red-min: %f Red-max: %f\n", blk->red_min, blk->red_max);
- printf("Green-min: %f Green-max: %f\n", blk->green_min, blk->green_max);
- printf("Blue-min: %f Blue-max: %f\n", blk->blue_min, blk->blue_max);
- printf("Alpha-min: %f Alpha-max: %f\n", blk->alpha_min, blk->alpha_max);
- printf("Grayscale: %d\n", blk->grayscale);
-
- for (int z = 0; z < zdim; z++)
- for (int y = 0; y < ydim; y++)
- for (int x = 0; x < xdim; x++)
- {
- int idx = ((z * ydim + y) * xdim + x) * 4;
- printf("Texel (%d %d %d) : orig=< %g, %g, %g, %g >, work=< %g, %g, %g, %g >\n",
- x, y, z,
- blk->orig_data[idx], blk->orig_data[idx + 1], blk->orig_data[idx + 2], blk->orig_data[idx + 3],
- blk->data_r[idx], blk->data_g[idx], blk->data_b[idx], blk->data_a[idx]);
- }
- printf("\n");
- }
- #endif
-
if (blk->red_min == blk->red_max && blk->green_min == blk->green_max && blk->blue_min == blk->blue_max && blk->alpha_min == blk->alpha_max)
{
// detected a constant-color block. Encode as FP16 if using HDR
scb->error_block = 0;
- if (input_image->rgb_force_use_of_hdr)
+ if ((decode_mode == ASTCENC_PRF_HDR) ||
+ (decode_mode == ASTCENC_PRF_HDR_RGB_LDR_A))
{
scb->block_mode = -1;
scb->partition_count = 0;
@@ -1201,16 +1149,6 @@ float compress_symbolic_block(
scb->constant_color[3] = astc::flt2int_rtn(alpha * 65535.0f);
}
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("Block is single-color <%4.4X %4.4X %4.4X %4.4X>\n", scb->constant_color[0], scb->constant_color[1], scb->constant_color[2], scb->constant_color[3]);
- }
-
- if (print_tile_errors)
- printf("0\n");
- #endif
-
physical_compressed_block psb = symbolic_to_physical(bsd, scb);
physical_to_symbolic(bsd, psb, scb);
@@ -1222,21 +1160,6 @@ float compress_symbolic_block(
float error_weight_sum = prepare_error_weight_block(input_image, bsd, ewp, blk, ewb, ewbo);
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("\n");
- for (int z = 0; z < zdim; z++)
- for (int y = 0; y < ydim; y++)
- for (int x = 0; x < xdim; x++)
- {
- int idx = (z * ydim + y) * xdim + x;
- printf("ErrorWeight (%d %d %d) : < %g, %g, %g, %g >\n", x, y, z, ewb->error_weights[idx].x, ewb->error_weights[idx].y, ewb->error_weights[idx].z, ewb->error_weights[idx].w);
- }
- printf("\n");
- }
- #endif
-
symbolic_compressed_block *tempblocks = tmpbuf->tempblocks;
float error_of_best_block = 1e20f;
@@ -1263,7 +1186,7 @@ float compress_symbolic_block(
float best_errorval_in_mode;
for (i = 0; i < 2; i++)
{
- compress_symbolic_block_fixed_partition_1_plane(input_image, decode_mode, modecutoffs[i], ewp->max_refinement_iters, bsd, 1, // partition count
+ compress_symbolic_block_fixed_partition_1_plane(decode_mode, modecutoffs[i], ewp->max_refinement_iters, bsd, 1, // partition count
0, // partition index
blk, ewb, tempblocks, tmpbuf->plane1);
@@ -1272,38 +1195,17 @@ float compress_symbolic_block(
{
if (tempblocks[j].error_block)
continue;
- decompress_symbolic_block(input_image, decode_mode, bsd, xpos, ypos, zpos, tempblocks + j, temp);
+ decompress_symbolic_block(decode_mode, bsd, xpos, ypos, zpos, tempblocks + j, temp);
float errorval = compute_imageblock_difference(bsd, blk, temp, ewb) * errorval_mult[i];
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("\n-----------------------------------\n");
- printf("Single-weight partition test 0 (1 partition) completed\n");
- printf("Resulting error value: %g\n", errorval);
- }
- #endif
-
if (errorval < best_errorval_in_mode)
best_errorval_in_mode = errorval;
if (errorval < error_of_best_block)
{
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Accepted as better than previous-best-error, which was %g\n", error_of_best_block);
- #endif
-
error_of_best_block = errorval;
*scb = tempblocks[j];
}
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("-----------------------------------\n");
- }
- #endif
}
best_errorvals_in_modes[0] = best_errorval_in_mode;
@@ -1331,7 +1233,7 @@ float compress_symbolic_block(
if (!uses_alpha && i == 3)
continue;
- compress_symbolic_block_fixed_partition_2_planes(input_image, decode_mode, mode_cutoff, ewp->max_refinement_iters,
+ compress_symbolic_block_fixed_partition_2_planes(decode_mode, mode_cutoff, ewp->max_refinement_iters,
bsd, 1, // partition count
0, // partition index
i, // the color component to test a separate plane of weights for.
@@ -1342,39 +1244,18 @@ float compress_symbolic_block(
{
if (tempblocks[j].error_block)
continue;
- decompress_symbolic_block(input_image, decode_mode, bsd, xpos, ypos, zpos, tempblocks + j, temp);
+ decompress_symbolic_block(decode_mode, bsd, xpos, ypos, zpos, tempblocks + j, temp);
float errorval = compute_imageblock_difference(bsd, blk, temp, ewb);
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("\n-----------------------------------\n");
- printf("Dual-weight partition test %d (1 partition) completed\n", i);
- printf("Resulting error value: %g\n", errorval);
- }
- #endif
-
if (errorval < best_errorval_in_mode)
best_errorval_in_mode = errorval;
if (errorval < error_of_best_block)
{
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Accepted as better than previous-best-error, which was %g\n", error_of_best_block);
- #endif
-
error_of_best_block = errorval;
*scb = tempblocks[j];
}
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("-----------------------------------\n");
- }
- #endif
-
best_errorvals_in_modes[i + 1] = best_errorval_in_mode;
}
@@ -1395,7 +1276,7 @@ float compress_symbolic_block(
for (i = 0; i < 2; i++)
{
- compress_symbolic_block_fixed_partition_1_plane(input_image, decode_mode, mode_cutoff, ewp->max_refinement_iters,
+ compress_symbolic_block_fixed_partition_1_plane(decode_mode, mode_cutoff, ewp->max_refinement_iters,
bsd, partition_count, partition_indices_1plane[i], blk, ewb, tempblocks, tmpbuf->plane1);
best_errorval_in_mode = 1e30f;
@@ -1403,28 +1284,14 @@ float compress_symbolic_block(
{
if (tempblocks[j].error_block)
continue;
- decompress_symbolic_block(input_image, decode_mode, bsd, xpos, ypos, zpos, tempblocks + j, temp);
+ decompress_symbolic_block(decode_mode, bsd, xpos, ypos, zpos, tempblocks + j, temp);
float errorval = compute_imageblock_difference(bsd, blk, temp, ewb);
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("\n-----------------------------------\n");
- printf("Single-weight partition test %d (%d partitions) completed\n", i, partition_count);
- printf("Resulting error value: %g\n", errorval);
- }
- #endif
-
if (errorval < best_errorval_in_mode)
best_errorval_in_mode = errorval;
if (errorval < error_of_best_block)
{
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Accepted as better than previous-best-error, which was %g\n", error_of_best_block);
- #endif
-
error_of_best_block = errorval;
*scb = tempblocks[j];
}
@@ -1432,18 +1299,10 @@ float compress_symbolic_block(
best_errorvals_in_modes[4 * (partition_count - 2) + 5 + i] = best_errorval_in_mode;
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("-----------------------------------\n");
- }
- #endif
-
if ((error_of_best_block / error_weight_sum) < ewp->texel_avg_error_limit)
goto END_OF_TESTS;
}
-
if (partition_count == 2 && !is_normal_map && MIN(best_errorvals_in_modes[5], best_errorvals_in_modes[6]) > (best_errorvals_in_modes[0] * ewp->partition_1_to_2_limit))
goto END_OF_TESTS;
@@ -1455,7 +1314,7 @@ float compress_symbolic_block(
{
if (lowest_correl > ewp->lowest_correlation_cutoff)
continue;
- compress_symbolic_block_fixed_partition_2_planes(input_image, decode_mode,
+ compress_symbolic_block_fixed_partition_2_planes(decode_mode,
mode_cutoff,
ewp->max_refinement_iters,
bsd,
@@ -1468,29 +1327,16 @@ float compress_symbolic_block(
{
if (tempblocks[j].error_block)
continue;
- decompress_symbolic_block(input_image, decode_mode, bsd, xpos, ypos, zpos, tempblocks + j, temp);
+
+ decompress_symbolic_block(decode_mode, bsd, xpos, ypos, zpos, tempblocks + j, temp);
float errorval = compute_imageblock_difference(bsd, blk, temp, ewb);
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("\n-----------------------------------\n");
- printf("Dual-weight partition test %d (%d partitions) completed\n", i, partition_count);
- printf("Resulting error value: %g\n", errorval);
- }
- #endif
-
if (errorval < best_errorval_in_mode)
best_errorval_in_mode = errorval;
if (errorval < error_of_best_block)
{
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Accepted as better than previous-best-error, which was %g\n", error_of_best_block);
- #endif
-
error_of_best_block = errorval;
*scb = tempblocks[j];
}
@@ -1498,28 +1344,12 @@ float compress_symbolic_block(
best_errorvals_in_modes[4 * (partition_count - 2) + 5 + 2 + i] = best_errorval_in_mode;
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("-----------------------------------\n");
- }
- #endif
-
if ((error_of_best_block / error_weight_sum) < ewp->texel_avg_error_limit)
goto END_OF_TESTS;
}
}
END_OF_TESTS:
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (scb->block_mode >= 0)
- block_mode_histogram[scb->block_mode & 0x7ff]++;
-
- if (print_tile_errors)
- printf("%g\n", (double)error_of_best_block);
- #endif
-
// compress/decompress to a physical block
physical_compressed_block psb = symbolic_to_physical(bsd, scb);
physical_to_symbolic(bsd, psb, scb);
diff --git a/Source/astc_compute_variance.cpp b/Source/astcenc_compute_variance.cpp
similarity index 98%
rename from Source/astc_compute_variance.cpp
rename to Source/astcenc_compute_variance.cpp
index e40e1e9..1f80531 100644
--- a/Source/astc_compute_variance.cpp
+++ b/Source/astcenc_compute_variance.cpp
@@ -28,7 +28,7 @@
* stability allowing us to use floats rather than doubles.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
#include
/**
@@ -48,7 +48,7 @@ struct pixel_region_variance_args
/** The RGB data should be treated as sRGB. */
int need_srgb_transform;
/** The channel swizzle pattern. */
- swizzlepattern swz;
+ astcenc_swizzle swz;
/** Should the algorithm bother with Z axis processing? */
int have_z;
/** The kernel radius for average and variance. */
@@ -162,7 +162,7 @@ static void compute_pixel_region_variance(
float rgb_power = arg->rgb_power;
float alpha_power = arg->alpha_power;
int need_srgb_transform = arg->need_srgb_transform;
- swizzlepattern swz = arg->swz;
+ astcenc_swizzle swz = arg->swz;
int have_z = arg->have_z;
int size_x = arg->size.x;
@@ -219,8 +219,8 @@ static void compute_pixel_region_variance(
{
// Swizzle data structure 4 = ZERO, 5 = ONE
uint8_t data[6];
- data[4] = 0;
- data[5] = 255;
+ data[ASTCENC_SWZ_0] = 0;
+ data[ASTCENC_SWZ_1] = 255;
for (int z = zd_start; z < padsize_z; z++)
{
@@ -271,8 +271,8 @@ static void compute_pixel_region_variance(
{
// Swizzle data structure 4 = ZERO, 5 = ONE (in FP16)
uint16_t data[6];
- data[4] = 0;
- data[5] = 0x3C00;
+ data[ASTCENC_SWZ_0] = 0;
+ data[ASTCENC_SWZ_1] = 0x3C00;
for (int z = zd_start; z < padsize_z; z++)
{
@@ -603,7 +603,7 @@ void compute_averages_and_variances(
int avg_var_kernel_radius,
int alpha_kernel_radius,
int need_srgb_transform,
- swizzlepattern swz,
+ astcenc_swizzle swz,
int thread_count
) {
int size_x = img->xsize;
@@ -612,9 +612,9 @@ void compute_averages_and_variances(
int pixel_count = size_x * size_y * size_z;
// Perform memory allocations for the destination buffers
- if (img->input_averages) delete[] img->input_averages;
- if (img->input_variances) delete[] img->input_variances;
- if (img->input_alpha_averages) delete[] img->input_alpha_averages;
+ delete[] img->input_averages;
+ delete[] img->input_variances;
+ delete[] img->input_alpha_averages;
img->input_averages = new float4[pixel_count];
img->input_variances = new float4[pixel_count];
diff --git a/Source/astc_decompress_symbolic.cpp b/Source/astcenc_decompress_symbolic.cpp
similarity index 95%
rename from Source/astc_decompress_symbolic.cpp
rename to Source/astcenc_decompress_symbolic.cpp
index 6e6481c..62e4005 100644
--- a/Source/astc_decompress_symbolic.cpp
+++ b/Source/astcenc_decompress_symbolic.cpp
@@ -19,7 +19,7 @@
* @brief Functions to decompress a symbolic block.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
#include
@@ -39,7 +39,7 @@ static int compute_value_of_texel_int(
}
static uint4 lerp_color_int(
- astc_decode_mode decode_mode,
+ astcenc_profile decode_mode,
uint4 color0,
uint4 color1,
int weight,
@@ -54,7 +54,7 @@ static uint4 lerp_color_int(
uint4 weight0 = uint4(64, 64, 64, 64) - weight1;
- if (decode_mode == DECODE_LDR_SRGB)
+ if (decode_mode == ASTCENC_PRF_LDR_SRGB)
{
color0 = uint4(color0.x >> 8, color0.y >> 8, color0.z >> 8, color0.w >> 8);
color1 = uint4(color1.x >> 8, color1.y >> 8, color1.z >> 8, color1.w >> 8);
@@ -63,7 +63,7 @@ static uint4 lerp_color_int(
uint4 color = (color0 * weight0) + (color1 * weight1) + uint4(32, 32, 32, 32);
color = uint4(color.x >> 6, color.y >> 6, color.z >> 6, color.w >> 6);
- if (decode_mode == DECODE_LDR_SRGB)
+ if (decode_mode == ASTCENC_PRF_LDR_SRGB)
{
color = color * 257;
}
@@ -72,8 +72,7 @@ static uint4 lerp_color_int(
}
void decompress_symbolic_block(
- const astc_codec_image* image,
- astc_decode_mode decode_mode,
+ astcenc_profile decode_mode,
const block_size_descriptor* bsd,
int xpos,
int ypos,
@@ -90,7 +89,7 @@ void decompress_symbolic_block(
// if we detected an error-block, blow up immediately.
if (scb->error_block)
{
- if (decode_mode == DECODE_LDR_SRGB)
+ if (decode_mode == ASTCENC_PRF_LDR_SRGB)
{
for (i = 0; i < bsd->texel_count; i++)
{
@@ -138,7 +137,7 @@ void decompress_symbolic_block(
// For sRGB decoding a real decoder would just use the top 8 bits
// for color conversion. We don't color convert, so linearly scale
// the top 8 bits into the full 16 bit dynamic range
- if (decode_mode == DECODE_LDR_SRGB)
+ if (decode_mode == ASTCENC_PRF_LDR_SRGB)
{
ired = (ired >> 8) * 257;
igreen = (igreen >> 8) * 257;
@@ -157,7 +156,7 @@ void decompress_symbolic_block(
{
switch (decode_mode)
{
- case DECODE_LDR_SRGB:
+ case ASTCENC_PRF_LDR_SRGB:
red = 1.0f;
green = 0.0f;
blue = 1.0f;
@@ -165,7 +164,7 @@ void decompress_symbolic_block(
use_lns = 0;
use_nan = 0;
break;
- case DECODE_LDR:
+ case ASTCENC_PRF_LDR:
red = 0.0f;
green = 0.0f;
blue = 0.0f;
@@ -173,8 +172,8 @@ void decompress_symbolic_block(
use_lns = 0;
use_nan = 1;
break;
- case DECODE_HDR:
- case DECODE_HDRA:
+ case ASTCENC_PRF_HDR_RGB_LDR_A:
+ case ASTCENC_PRF_HDR:
// constant-color block; unpack from FP16 to FP32.
red = sf16_to_float(scb->constant_color[0]);
green = sf16_to_float(scb->constant_color[1]);
@@ -225,8 +224,7 @@ void decompress_symbolic_block(
for (i = 0; i < partition_count; i++)
{
- unpack_color_endpoints(image,
- decode_mode,
+ unpack_color_endpoints(decode_mode,
scb->color_formats[i],
scb->color_quantization_level,
scb->color_values[i],
diff --git a/Source/astc_encoding_choice_error.cpp b/Source/astcenc_encoding_choice_error.cpp
similarity index 89%
rename from Source/astc_encoding_choice_error.cpp
rename to Source/astcenc_encoding_choice_error.cpp
index ef603c6..f634cff 100644
--- a/Source/astc_encoding_choice_error.cpp
+++ b/Source/astcenc_encoding_choice_error.cpp
@@ -37,11 +37,7 @@
* the quantization step.
*/
-#include "astc_codec_internals.h"
-
-#ifdef DEBUG_PRINT_DIAGNOSTICS
- #include
-#endif
+#include "astcenc_internal.h"
// helper function to merge two endpoint-colors
void merge_endpoints(
@@ -115,13 +111,6 @@ void compute_encoding_choice_errors(
int texels_per_block = bsd->texel_count;
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("%s : texels-per-block=%dx%dx%d, separate_component=%d, partition-count=%d\n", __func__, bsd->xdim, bsd->ydim, bsd->zdim, separate_component, partition_count);
- }
- #endif
-
float3 averages[4];
float3 directions_rgb[4];
float4 error_weightings[4];
@@ -169,17 +158,6 @@ void compute_encoding_choice_errors(
luminance_lines[i].a = float3(0.0f, 0.0f, 0.0f);
luminance_lines[i].b = normalize(csf);
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("Partition %d\n", i);
- printf("Average = <%g %g %g>\n", averages[i].x, averages[i].y, averages[i].z);
- printf("Uncorr-rgb-line = <%g %g %g> + t<%g %g %g>\n",
- uncorr_rgb_lines[i].a.x, uncorr_rgb_lines[i].a.y, uncorr_rgb_lines[i].a.z, uncorr_rgb_lines[i].b.x, uncorr_rgb_lines[i].b.y, uncorr_rgb_lines[i].b.z);
- printf("Samechroma-line = t<%g %g %g>\n", samechroma_rgb_lines[i].b.x, samechroma_rgb_lines[i].b.y, samechroma_rgb_lines[i].b.z);
- }
- #endif
-
proc_uncorr_rgb_lines[i].amod = (uncorr_rgb_lines[i].a - uncorr_rgb_lines[i].b * dot(uncorr_rgb_lines[i].a, uncorr_rgb_lines[i].b)) * icsf;
proc_uncorr_rgb_lines[i].bs = uncorr_rgb_lines[i].b * csf;
proc_uncorr_rgb_lines[i].bis = uncorr_rgb_lines[i].b * icsf;
@@ -211,14 +189,6 @@ void compute_encoding_choice_errors(
rgb_luma_error[i] = compute_error_squared_rgb_single_partition(i, bsd, pi, pb, ewb, &(proc_rgb_luma_lines[i]));
luminance_rgb_error[i] = compute_error_squared_rgb_single_partition(i, bsd, pi, pb, ewb, &(proc_luminance_lines[i]));
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("Partition %d : uncorr-error=%g samechroma-error=%g rgb-luma-error=%g lum-error=%g\n",
- i, uncorr_rgb_error[i], samechroma_rgb_error[i], rgb_luma_error[i], luminance_rgb_error[i]);
- }
- #endif
}
// compute the error that arises from just ditching alpha and RGB
diff --git a/Source/astcenc_entry.cpp b/Source/astcenc_entry.cpp
new file mode 100644
index 0000000..ba2d0c8
--- /dev/null
+++ b/Source/astcenc_entry.cpp
@@ -0,0 +1,823 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2020 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions for the library entrypoint.
+ */
+
+#include
+#include
+
+#include "astcenc.h"
+#include "astcenc_internal.h"
+
+// The ASTC codec is written with the assumption that a float threaded through
+// the "if32" union will in fact be stored and reloaded as a 32-bit IEEE-754 single-precision
+// float, stored with round-to-nearest rounding. This is always the case in an
+// IEEE-754 compliant system, however not every system is actually IEEE-754 compliant
+// in the first place. As such, we run a quick test to check that this is actually the case
+// (e.g. gcc on 32-bit x86 will typically fail unless -msse2 -mfpmath=sse2 is specified).
+static astcenc_error validate_cpu_float()
+{
+ if32 p;
+ volatile float xprec_testval = 2.51f;
+ p.f = xprec_testval + 12582912.0f;
+ float q = p.f - 12582912.0f;
+
+ if (q != 3.0f)
+ {
+ return ASTCENC_ERR_BAD_CPU_FLOAT;
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+static astcenc_error validate_cpu_isa()
+{
+ #if ASTCENC_SSE >= 42
+ if (!cpu_supports_sse42())
+ {
+ return ASTCENC_ERR_BAD_CPU_ISA;
+ }
+ #endif
+
+ #if ASTCENC_POPCNT >= 1
+ if (!cpu_supports_popcnt())
+ {
+ return ASTCENC_ERR_BAD_CPU_ISA;
+ }
+ #endif
+
+ #if ASTCENC_AVX >= 2
+ if (!cpu_supports_avx2())
+ {
+ return ASTCENC_ERR_BAD_CPU_ISA;
+ }
+ #endif
+
+ return ASTCENC_SUCCESS;
+}
+
+static astcenc_error validate_profile(
+ astcenc_profile profile
+) {
+ switch(profile)
+ {
+ case ASTCENC_PRF_LDR_SRGB:
+ case ASTCENC_PRF_LDR:
+ case ASTCENC_PRF_HDR_RGB_LDR_A:
+ case ASTCENC_PRF_HDR:
+ return ASTCENC_SUCCESS;
+ default:
+ return ASTCENC_ERR_BAD_PROFILE;
+ }
+}
+
+static astcenc_error validate_block_size(
+ unsigned int block_x,
+ unsigned int block_y,
+ unsigned int block_z
+) {
+ if (((block_z <= 1) && is_legal_2d_block_size(block_x, block_y)) ||
+ ((block_z >= 2) && is_legal_3d_block_size(block_x, block_y, block_z)))
+ {
+ return ASTCENC_SUCCESS;
+ }
+
+ return ASTCENC_ERR_BAD_BLOCK_SIZE;
+}
+
+static astcenc_error validate_flags(
+ unsigned int flags
+) {
+ // Flags field must not contain any unknown flag bits
+ unsigned int exMask = ~ASTCENC_ALL_FLAGS;
+ if (astc::popcount(flags & exMask) != 0)
+ {
+ return ASTCENC_ERR_BAD_FLAGS;
+ }
+
+ // Flags field must only contain at most a single map type
+ exMask = ASTCENC_FLG_MAP_MASK | ASTCENC_FLG_MAP_NORMAL;
+ if (astc::popcount(flags & exMask) > 1)
+ {
+ return ASTCENC_ERR_BAD_FLAGS;
+ }
+
+ // TODO: We don't support user threads yet
+ if (flags & ASTCENC_FLG_USE_USER_THREADS)
+ {
+ return ASTCENC_ERR_NOT_IMPLEMENTED;
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+static astcenc_error validate_compression_swz(
+ astcenc_swz swizzle
+) {
+ switch(swizzle)
+ {
+ case ASTCENC_SWZ_R:
+ case ASTCENC_SWZ_G:
+ case ASTCENC_SWZ_B:
+ case ASTCENC_SWZ_A:
+ case ASTCENC_SWZ_0:
+ case ASTCENC_SWZ_1:
+ return ASTCENC_SUCCESS;
+ default:
+ return ASTCENC_ERR_BAD_SWIZZLE;
+ }
+}
+
+static astcenc_error validate_compression_swizzle(
+ astcenc_swizzle swizzle
+) {
+ if (validate_compression_swz(swizzle.r) ||
+ validate_compression_swz(swizzle.g) ||
+ validate_compression_swz(swizzle.b) ||
+ validate_compression_swz(swizzle.a))
+ {
+ return ASTCENC_ERR_BAD_SWIZZLE;
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+static astcenc_error validate_decompression_swz(
+ astcenc_swz swizzle
+) {
+ switch(swizzle)
+ {
+ case ASTCENC_SWZ_R:
+ case ASTCENC_SWZ_G:
+ case ASTCENC_SWZ_B:
+ case ASTCENC_SWZ_A:
+ case ASTCENC_SWZ_0:
+ case ASTCENC_SWZ_1:
+ case ASTCENC_SWZ_Z:
+ return ASTCENC_SUCCESS;
+ default:
+ return ASTCENC_ERR_BAD_SWIZZLE;
+ }
+}
+
+static astcenc_error validate_decompression_swizzle(
+ astcenc_swizzle swizzle
+) {
+ if (validate_decompression_swz(swizzle.r) ||
+ validate_decompression_swz(swizzle.g) ||
+ validate_decompression_swz(swizzle.b) ||
+ validate_decompression_swz(swizzle.a))
+ {
+ return ASTCENC_ERR_BAD_SWIZZLE;
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+/**
+ * Validate that an incoming configuration is in-spec.
+ *
+ * This function can respond in two ways:
+ *
+ * * Numerical inputs that have valid ranges are clamped to those valid
+ * ranges. No error is thrown for out-of-range inputs in this case.
+ * * Numerical inputs and logic inputs are are logically invalid and which
+ * make no sense algorithmically will return an error.
+ */
+static astcenc_error validate_config(
+ astcenc_config &config
+) {
+ astcenc_error status;
+
+ status = validate_profile(config.profile);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ status = validate_flags(config.flags);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ status = validate_block_size(config.block_x, config.block_y, config.block_z);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ config.v_rgba_mean_stdev_mix = MAX(config.v_rgba_mean_stdev_mix, 0.0f);
+ config.v_rgb_power = MAX(config.v_rgb_power, 0.0f);
+ config.v_rgb_base = MAX(config.v_rgb_base, 0.0f);
+ config.v_rgb_mean = MAX(config.v_rgb_mean, 0.0f);
+ config.v_rgb_stdev = MAX(config.v_rgb_stdev, 0.0f);
+ config.v_a_power = MAX(config.v_a_power, 0.0f);
+ config.v_a_base = MAX(config.v_a_base, 0.0f);
+ config.v_a_mean = MAX(config.v_a_mean, 0.0f);
+ config.v_a_stdev = MAX(config.v_a_stdev, 0.0f);
+
+ config.b_deblock_weight = MAX(config.b_deblock_weight, 0.0f);
+
+ config.tune_partition_limit = astc::clampi(config.tune_partition_limit, 1, PARTITION_COUNT);
+ config.tune_block_mode_limit = astc::clampi(config.tune_block_mode_limit, 1, 100);
+ config.tune_refinement_limit = MAX(config.tune_refinement_limit, 1);
+ config.tune_db_limit = MAX(config.tune_db_limit, 0.0f);
+ config.tune_partition_early_out_limit = MAX(config.tune_partition_early_out_limit, 0.0f);
+ config.tune_two_plane_early_out_limit = MAX(config.tune_two_plane_early_out_limit, 0.0f);
+
+ // Specifying a zero weight color component is not allowed; force to small value
+ float max_weight = MAX(MAX(config.cw_r_weight, config.cw_g_weight),
+ MAX(config.cw_b_weight, config.cw_a_weight));
+ if (max_weight > 0.0f)
+ {
+ max_weight /= 1000.0f;
+ config.cw_r_weight = MAX(config.cw_r_weight, max_weight);
+ config.cw_g_weight = MAX(config.cw_g_weight, max_weight);
+ config.cw_b_weight = MAX(config.cw_b_weight, max_weight);
+ config.cw_a_weight = MAX(config.cw_a_weight, max_weight);
+ }
+ // If all color components error weights are zero then return an error
+ else
+ {
+ return ASTCENC_ERR_BAD_PARAM;
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+astcenc_error astcenc_init_config(
+ astcenc_profile profile,
+ unsigned int block_x,
+ unsigned int block_y,
+ unsigned int block_z,
+ astcenc_preset preset,
+ unsigned int flags,
+ astcenc_config& config
+) {
+ astcenc_error status;
+
+ // Zero init all config fields; although most of will be over written
+ std::memset(&config, 0, sizeof(config));
+
+ // Process the block size
+ block_z = MAX(block_z, 1); // For 2D blocks Z==0 is accepted, but convert to 1
+ status = validate_block_size(block_x, block_y, block_z);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ config.block_x = block_x;
+ config.block_y = block_y;
+ config.block_z = block_z;
+
+ float texels = static_cast(block_x * block_y * block_z);
+ float ltexels = logf(texels) / logf(10.0f);
+
+ // Process the performance preset; note that this must be done before we
+ // process any additional settings, such as color profile and flags, which
+ // may replace some of these settings with more use case tuned values
+ switch(preset)
+ {
+ case ASTCENC_PRE_FAST:
+ config.tune_partition_limit = 4;
+ config.tune_block_mode_limit = 50;
+ config.tune_refinement_limit = 1;
+ config.tune_db_limit = MAX(85 - 35 * ltexels, 63 - 19 * ltexels);
+ config.tune_partition_early_out_limit = 1.0f;
+ config.tune_two_plane_early_out_limit = 0.5f;
+ break;
+ case ASTCENC_PRE_MEDIUM:
+ config.tune_partition_limit = 25;
+ config.tune_block_mode_limit = 75;
+ config.tune_refinement_limit = 2;
+ config.tune_db_limit = MAX(95 - 35 * ltexels, 70 - 19 * ltexels);
+ config.tune_partition_early_out_limit = 1.2f;
+ config.tune_two_plane_early_out_limit = 0.75f;
+ break;
+ case ASTCENC_PRE_THOROUGH:
+ config.tune_partition_limit = 100;
+ config.tune_block_mode_limit = 95;
+ config.tune_refinement_limit = 4;
+ config.tune_db_limit = MAX(105 - 35 * ltexels, 77 - 19 * ltexels);
+ config.tune_partition_early_out_limit = 2.5f;
+ config.tune_two_plane_early_out_limit = 0.95f;
+ break;
+ case ASTCENC_PRE_EXHAUSTIVE:
+ config.tune_partition_limit = 1024;
+ config.tune_block_mode_limit = 100;
+ config.tune_refinement_limit = 4;
+ config.tune_db_limit = 999.0f;
+ config.tune_partition_early_out_limit = 1000.0f;
+ config.tune_two_plane_early_out_limit = 0.99f;
+ break;
+ default:
+ return ASTCENC_ERR_BAD_PRESET;
+ }
+
+ // Set heuristics to the defaults for each color profile
+ config.v_rgba_radius = 0;
+ config.v_rgba_mean_stdev_mix = 0.0f;
+
+ config.cw_r_weight = 1.0f;
+ config.cw_g_weight = 1.0f;
+ config.cw_b_weight = 1.0f;
+ config.cw_a_weight = 1.0f;
+
+ config.a_scale_radius = 0;
+
+ config.b_deblock_weight = 0.0f;
+
+ config.profile = profile;
+ switch(profile)
+ {
+ case ASTCENC_PRF_LDR:
+ case ASTCENC_PRF_LDR_SRGB:
+ config.v_rgb_power = 1.0f;
+ config.v_rgb_base = 1.0f;
+ config.v_rgb_mean = 0.0f;
+ config.v_rgb_stdev = 0.0f;
+
+ config.v_a_power = 1.0f;
+ config.v_a_base = 1.0f;
+ config.v_a_mean = 0.0f;
+ config.v_a_stdev = 0.0f;
+ break;
+ case ASTCENC_PRF_HDR_RGB_LDR_A:
+ config.v_rgb_power = 0.75f;
+ config.v_rgb_base = 0.0f;
+ config.v_rgb_mean = 1.0f;
+ config.v_rgb_stdev = 0.0f;
+
+ config.v_a_power = 1.0f;
+ config.v_a_base = 0.05f;
+ config.v_a_mean = 0.0f;
+ config.v_a_stdev = 0.0f;
+
+ config.tune_db_limit = 999.0f;
+ break;
+ case ASTCENC_PRF_HDR:
+ config.v_rgb_power = 0.75f;
+ config.v_rgb_base = 0.0f;
+ config.v_rgb_mean = 1.0f;
+ config.v_rgb_stdev = 0.0f;
+
+ config.v_a_power = 0.75f;
+ config.v_a_base = 0.0f;
+ config.v_a_mean = 1.0f;
+ config.v_a_stdev = 0.0f;
+
+ config.tune_db_limit = 999.0f;
+ break;
+ default:
+ return ASTCENC_ERR_BAD_PROFILE;
+ }
+
+ // Flags field must not contain any unknown flag bits
+ status = validate_flags(flags);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ if (flags & ASTCENC_FLG_MAP_NORMAL)
+ {
+ config.cw_r_weight = 1.0f;
+ config.cw_g_weight = 0.0f;
+ config.cw_b_weight = 0.0f;
+ config.cw_a_weight = 1.0f;
+ config.tune_partition_early_out_limit = 1000.0f;
+ config.tune_two_plane_early_out_limit = 0.99f;
+
+ if (flags & ASTCENC_FLG_USE_PERCEPTUAL)
+ {
+ config.b_deblock_weight = 1.8f;
+ config.v_rgba_radius = 3;
+ config.v_rgba_mean_stdev_mix = 0.0f;
+ config.v_rgb_mean = 0.0f;
+ config.v_rgb_stdev = 50.0f;
+ config.v_a_mean = 0.0f;
+ config.v_a_stdev = 50.0f;
+ }
+ }
+
+ if (flags & ASTCENC_FLG_MAP_MASK)
+ {
+ config.v_rgba_radius = 3;
+ config.v_rgba_mean_stdev_mix = 0.03f;
+ config.v_rgb_mean = 0.0f;
+ config.v_rgb_stdev = 25.0f;
+ config.v_a_mean = 0.0f;
+ config.v_a_stdev = 25.0f;
+ }
+
+ // TODO: We don't support user threads yet
+ if (flags & ASTCENC_FLG_USE_USER_THREADS)
+ {
+ return ASTCENC_ERR_NOT_IMPLEMENTED;
+ }
+
+ config.flags = flags;
+
+ return ASTCENC_SUCCESS;
+}
+
+astcenc_error astcenc_context_alloc(
+ astcenc_config const& config,
+ unsigned int thread_count,
+ astcenc_context** context
+) {
+ astcenc_error status;
+ astcenc_context* ctx = nullptr;
+ block_size_descriptor* bsd = nullptr;
+
+ status = validate_cpu_float();
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ status = validate_cpu_isa();
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ if (thread_count == 0)
+ {
+ thread_count = get_cpu_count();
+ }
+
+ try
+ {
+ ctx = new astcenc_context;
+ ctx->thread_count = thread_count;
+ ctx->config = config;
+
+ // Copy the config first and validate the copy (may modify it)
+ status = validate_config(ctx->config);
+ if (status != ASTCENC_SUCCESS)
+ {
+ delete ctx;
+ return status;
+ }
+
+ bsd = new block_size_descriptor;
+ init_block_size_descriptor(config.block_x, config.block_y, config.block_z, bsd);
+ ctx->bsd = bsd;
+ }
+ catch(const std::bad_alloc&)
+ {
+ term_block_size_descriptor(bsd);
+ delete bsd;
+ delete ctx;
+ *context = nullptr;
+ return ASTCENC_ERR_OUT_OF_MEM;
+ }
+
+ *context = ctx;
+
+ // TODO: Currently static memory; should move to context memory
+ prepare_angular_tables();
+ build_quantization_mode_table();
+
+ return ASTCENC_SUCCESS;
+}
+
+void astcenc_context_free(
+ astcenc_context* context
+) {
+ if (context)
+ {
+ term_block_size_descriptor(context->bsd);
+ delete context->bsd;
+ delete context;
+ }
+}
+
+struct compress_astc_image_info
+{
+ const block_size_descriptor* bsd;
+ const error_weighting_params* ewp;
+ uint8_t* buffer;
+ int threadcount;
+ astcenc_profile decode_mode;
+ astcenc_swizzle swz_encode;
+ const astc_codec_image* input_image;
+};
+
+static void encode_astc_image_threadfunc(
+ int thread_count,
+ int thread_id,
+ void* vblk
+) {
+ const compress_astc_image_info *blk = (const compress_astc_image_info *)vblk;
+ const block_size_descriptor *bsd = blk->bsd;
+ int xdim = bsd->xdim;
+ int ydim = bsd->ydim;
+ int zdim = bsd->zdim;
+ uint8_t *buffer = blk->buffer;
+ const error_weighting_params *ewp = blk->ewp;
+ astcenc_profile decode_mode = blk->decode_mode;
+ astcenc_swizzle swz_encode = blk->swz_encode;
+ const astc_codec_image *input_image = blk->input_image;
+
+ imageblock pb;
+ int ctr = thread_id;
+
+ int x, y, z;
+ int xsize = input_image->xsize;
+ int ysize = input_image->ysize;
+ int zsize = input_image->zsize;
+ int xblocks = (xsize + xdim - 1) / xdim;
+ int yblocks = (ysize + ydim - 1) / ydim;
+ int zblocks = (zsize + zdim - 1) / zdim;
+
+ //allocate memory for temporary buffers
+ compress_symbolic_block_buffers temp_buffers;
+ temp_buffers.ewb = new error_weight_block;
+ temp_buffers.ewbo = new error_weight_block_orig;
+ temp_buffers.tempblocks = new symbolic_compressed_block[4];
+ temp_buffers.temp = new imageblock;
+ temp_buffers.planes2 = new compress_fixed_partition_buffers;
+ temp_buffers.planes2->ei1 = new endpoints_and_weights;
+ temp_buffers.planes2->ei2 = new endpoints_and_weights;
+ temp_buffers.planes2->eix1 = new endpoints_and_weights[MAX_DECIMATION_MODES];
+ temp_buffers.planes2->eix2 = new endpoints_and_weights[MAX_DECIMATION_MODES];
+ temp_buffers.planes2->decimated_quantized_weights = new float[2 * MAX_DECIMATION_MODES * MAX_WEIGHTS_PER_BLOCK];
+ temp_buffers.planes2->decimated_weights = new float[2 * MAX_DECIMATION_MODES * MAX_WEIGHTS_PER_BLOCK];
+ temp_buffers.planes2->flt_quantized_decimated_quantized_weights = new float[2 * MAX_WEIGHT_MODES * MAX_WEIGHTS_PER_BLOCK];
+ temp_buffers.planes2->u8_quantized_decimated_quantized_weights = new uint8_t[2 * MAX_WEIGHT_MODES * MAX_WEIGHTS_PER_BLOCK];
+ temp_buffers.plane1 = temp_buffers.planes2;
+
+ for (z = 0; z < zblocks; z++)
+ {
+ for (y = 0; y < yblocks; y++)
+ {
+ for (x = 0; x < xblocks; x++)
+ {
+ if (ctr == 0)
+ {
+ int offset = ((z * yblocks + y) * xblocks + x) * 16;
+ uint8_t *bp = buffer + offset;
+ fetch_imageblock(decode_mode, input_image, &pb, bsd, x * xdim, y * ydim, z * zdim, swz_encode);
+ symbolic_compressed_block scb;
+ compress_symbolic_block(input_image, decode_mode, bsd, ewp, &pb, &scb, &temp_buffers);
+ *(physical_compressed_block*) bp = symbolic_to_physical(bsd, &scb);
+ ctr = thread_count - 1;
+ }
+ else
+ ctr--;
+ }
+ }
+ }
+
+ delete[] temp_buffers.planes2->decimated_quantized_weights;
+ delete[] temp_buffers.planes2->decimated_weights;
+ delete[] temp_buffers.planes2->flt_quantized_decimated_quantized_weights;
+ delete[] temp_buffers.planes2->u8_quantized_decimated_quantized_weights;
+ delete[] temp_buffers.planes2->eix1;
+ delete[] temp_buffers.planes2->eix2;
+ delete temp_buffers.planes2->ei1;
+ delete temp_buffers.planes2->ei2;
+ delete temp_buffers.planes2;
+ delete[] temp_buffers.tempblocks;
+ delete temp_buffers.temp;
+ delete temp_buffers.ewbo;
+ delete temp_buffers.ewb;
+}
+
+astcenc_error astcenc_compress_image(
+ astcenc_context* context,
+ astcenc_image& image,
+ astcenc_swizzle swizzle,
+ uint8_t* data_out,
+ size_t data_len,
+ unsigned int thread_index
+) {
+ astcenc_error status;
+
+ status = validate_compression_swizzle(swizzle);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ if (context->config.flags & ASTCENC_FLG_USE_USER_THREADS)
+ {
+ if (thread_index >= context->thread_count)
+ {
+ return ASTCENC_ERR_BAD_PARAM;
+ }
+ }
+
+ // TODO: Replace error_weighting_params in the core codec with the config / context structs
+ error_weighting_params ewp;
+ ewp.rgb_power = context->config.v_rgb_power;
+ ewp.rgb_base_weight = context->config.v_rgb_base;
+ ewp.rgb_mean_weight = context->config.v_rgb_mean;
+ ewp.rgb_stdev_weight = context->config.v_rgb_stdev;
+ ewp.alpha_power = context->config.v_a_power;
+ ewp.alpha_base_weight = context->config.v_a_base;
+ ewp.alpha_mean_weight = context->config.v_a_mean;
+ ewp.alpha_stdev_weight = context->config.v_a_stdev;
+ ewp.rgb_mean_and_stdev_mixing = context->config.v_rgba_mean_stdev_mix;
+ ewp.mean_stdev_radius = context->config.v_rgba_radius;
+ ewp.enable_rgb_scale_with_alpha = context->config.flags & ASTCENC_FLG_USE_ALPHA_WEIGHT ? 1 : 0;
+ ewp.alpha_radius = context->config.a_scale_radius;
+ ewp.ra_normal_angular_scale = context->config.flags & ASTCENC_FLG_MAP_NORMAL ? 1 : 0;
+ ewp.block_artifact_suppression = context->config.b_deblock_weight;
+ ewp.rgba_weights[0] = context->config.cw_r_weight;
+ ewp.rgba_weights[1] = context->config.cw_g_weight;
+ ewp.rgba_weights[2] = context->config.cw_b_weight;
+ ewp.rgba_weights[3] = context->config.cw_a_weight;
+ ewp.partition_search_limit = context->config.tune_partition_limit;
+ ewp.block_mode_cutoff = context->config.tune_block_mode_limit / 100.0f;
+ ewp.partition_1_to_2_limit = context->config.tune_partition_early_out_limit;
+ ewp.lowest_correlation_cutoff = context->config.tune_two_plane_early_out_limit;
+ ewp.max_refinement_iters = context->config.tune_refinement_limit;
+
+ if ((context->config.profile == ASTCENC_PRF_LDR) || (context->config.profile == ASTCENC_PRF_LDR_SRGB))
+ {
+ ewp.texel_avg_error_limit = powf(0.1f, context->config.tune_db_limit * 0.1f) * 65535.0f * 65535.0f;
+ }
+ else
+ {
+ ewp.texel_avg_error_limit = 0.0f;
+ }
+
+ // TODO: Replace astc_codec_image in the core codec with the astcenc_image struct
+ astc_codec_image input_image;
+ input_image.data8 = image.data8;
+ input_image.data16 = image.data16;
+ input_image.xsize = image.dim_x;
+ input_image.ysize = image.dim_y;
+ input_image.zsize = image.dim_z;
+ input_image.padding = image.dim_pad;
+
+ // Need to agree what we do with linearize sRGB
+ input_image.linearize_srgb = context->config.flags & ASTCENC_FLG_USE_LINEARIZED_SRGB ? 1 : 0;
+
+ input_image.input_averages = nullptr;
+ input_image.input_variances = nullptr;
+ input_image.input_alpha_averages = nullptr;
+
+ if (image.dim_pad > 0 ||
+ ewp.rgb_mean_weight != 0.0f || ewp.rgb_stdev_weight != 0.0f ||
+ ewp.alpha_mean_weight != 0.0f || ewp.alpha_stdev_weight != 0.0f)
+ {
+ compute_averages_and_variances(&input_image, ewp.rgb_power, ewp.alpha_power,
+ ewp.mean_stdev_radius, ewp.alpha_radius,
+ input_image.linearize_srgb, swizzle, context->thread_count);
+ }
+
+ // TODO: This could be done once when the context is created
+ expand_block_artifact_suppression(
+ context->config.block_x, context->config.block_y, context->config.block_z, &ewp);
+
+ compress_astc_image_info ai;
+ ai.bsd = context->bsd;
+ ai.buffer = data_out;
+ ai.ewp = &ewp;
+ ai.decode_mode = context->config.profile;
+ ai.swz_encode = swizzle;
+ ai.input_image = &input_image;
+
+ // TODO: Add bounds checking
+ (void)data_len;
+
+ // TODO: Implement user-thread pools
+ launch_threads(context->thread_count, encode_astc_image_threadfunc, &ai);
+
+ // Clean up any memory allocated by compute_averages_and_variances
+ delete[] input_image.input_averages;
+ delete[] input_image.input_variances;
+ delete[] input_image.input_alpha_averages;
+
+ return ASTCENC_SUCCESS;
+}
+
+astcenc_error astcenc_decompress_image(
+ astcenc_context* context,
+ uint8_t* data,
+ size_t data_len,
+ astcenc_image& image_out,
+ astcenc_swizzle swizzle,
+ unsigned int thread_index
+) {
+ astcenc_error status;
+
+ status = validate_decompression_swizzle(swizzle);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ if (context->config.flags & ASTCENC_FLG_USE_USER_THREADS)
+ {
+ if (thread_index >= context->thread_count)
+ {
+ return ASTCENC_ERR_BAD_PARAM;
+ }
+ }
+
+ unsigned int block_x = context->config.block_x;
+ unsigned int block_y = context->config.block_y;
+ unsigned int block_z = context->config.block_z;
+
+ unsigned int xblocks = (image_out.dim_x + block_x - 1) / block_x;
+ unsigned int yblocks = (image_out.dim_y + block_y - 1) / block_y;
+ unsigned int zblocks = (image_out.dim_z + block_z - 1) / block_z;
+
+ // TODO: Check output bounds
+ (void)data_len;
+
+ // TODO: Handle custom threading
+ (void)thread_index;
+
+ // TODO: Replace astc_codec_image in the core codec with the astcenc_image struct
+ astc_codec_image image;
+ image.data8 = image_out.data8;
+ image.data16 = image_out.data16;
+ image.xsize = image_out.dim_x;
+ image.ysize = image_out.dim_y;
+ image.zsize = image_out.dim_z;
+ image.padding = image_out.dim_pad;
+
+ // Need to agree what we do with linearize sRGB
+ image.linearize_srgb = (context->config.flags & ASTCENC_FLG_USE_LINEARIZED_SRGB) == 0 ? 0 : 1;
+
+ image.input_averages = nullptr;
+ image.input_variances = nullptr;
+ image.input_alpha_averages = nullptr;
+
+ imageblock pb;
+ for (unsigned int z = 0; z < zblocks; z++)
+ {
+ for (unsigned int y = 0; y < yblocks; y++)
+ {
+ for (unsigned int x = 0; x < xblocks; x++)
+ {
+ unsigned int offset = (((z * yblocks + y) * xblocks) + x) * 16;
+ uint8_t* bp = data + offset;
+ physical_compressed_block pcb = *(physical_compressed_block *) bp;
+ symbolic_compressed_block scb;
+ physical_to_symbolic(context->bsd, pcb, &scb);
+ decompress_symbolic_block(context->config.profile, context->bsd,
+ x * block_x, y * block_y, z * block_z,
+ &scb, &pb);
+ write_imageblock(&image, &pb, context->bsd,
+ x * block_x, y * block_y, z * block_z, swizzle);
+ }
+ }
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+const char* astcenc_get_error_string(
+ astcenc_error status
+) {
+ switch(status)
+ {
+ case ASTCENC_ERR_OUT_OF_MEM:
+ return "ASTCENC_ERR_OUT_OF_MEM";
+ case ASTCENC_ERR_BAD_CPU_FLOAT:
+ return "ASTCENC_ERR_BAD_CPU_FLOAT";
+ case ASTCENC_ERR_BAD_CPU_ISA:
+ return "ASTCENC_ERR_BAD_CPU_ISA";
+ case ASTCENC_ERR_BAD_PARAM:
+ return "ASTCENC_ERR_BAD_PARAM";
+ case ASTCENC_ERR_BAD_BLOCK_SIZE:
+ return "ASTCENC_ERR_BAD_BLOCK_SIZE";
+ case ASTCENC_ERR_BAD_PROFILE:
+ return "ASTCENC_ERR_BAD_PROFILE";
+ case ASTCENC_ERR_BAD_PRESET:
+ return "ASTCENC_ERR_BAD_PRESET";
+ case ASTCENC_ERR_BAD_FLAGS:
+ return "ASTCENC_ERR_BAD_FLAGS";
+ case ASTCENC_ERR_BAD_SWIZZLE:
+ return "ASTCENC_ERR_BAD_SWIZZLE";
+ case ASTCENC_ERR_NOT_IMPLEMENTED:
+ return "ASTCENC_ERR_NOT_IMPLEMENTED";
+ default:
+ return nullptr;
+ }
+}
diff --git a/Source/astc_find_best_partitioning.cpp b/Source/astcenc_find_best_partitioning.cpp
similarity index 93%
rename from Source/astc_find_best_partitioning.cpp
rename to Source/astcenc_find_best_partitioning.cpp
index 2ed39bf..9de177d 100644
--- a/Source/astc_find_best_partitioning.cpp
+++ b/Source/astcenc_find_best_partitioning.cpp
@@ -49,11 +49,7 @@
* each element in the table is an uint8_t indicating partition index (0, 1, 2 or 3)
*/
-#include "astc_codec_internals.h"
-
-#ifdef DEBUG_PRINT_DIAGNOSTICS
- #include
-#endif
+#include "astcenc_internal.h"
static void compute_alpha_minmax(
int texels_per_block,
@@ -234,10 +230,6 @@ void find_best_partitionings(
float weight_imprecision_estim_squared = weight_imprecision_estim * weight_imprecision_estim;
-#ifdef DEBUG_PRINT_DIAGNOSTICS
- printf("weight_imprecision_estim = %g\n", (double)weight_imprecision_estim);
-#endif
-
int uses_alpha = imageblock_uses_alpha(pb);
const partition_info* ptab = get_partition_table(bsd, partition_count);
@@ -255,10 +247,6 @@ void find_best_partitionings(
if (uses_alpha)
{
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Partition testing with alpha, %d partitions\n\n", partition_count);
- #endif
for (i = 0; i < PARTITION_COUNT; i++)
{
@@ -267,11 +255,6 @@ void find_best_partitionings(
if (bk_partition_count < partition_count)
{
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Partitioning %d-%d: invalid\n", partition_count, partition);
- #endif
-
uncorr_errors[i] = 1e35f;
samechroma_errors[i] = 1e35f;
separate_errors[i] = float4(1e35f, 1e35f, 1e35f, 1e35f);
@@ -282,13 +265,7 @@ void find_best_partitionings(
// than the sentinel value for invalid partitions
if (i >= partition_search_limit)
{
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Partitioning %d-%d: excluded from testing\n", partition_count, partition);
- #endif
-
defacto_search_limit = i;
-
uncorr_errors[i] = 1e34f;
samechroma_errors[i] = 1e34f;
separate_errors[i] = float4(1e34f, 1e34f, 1e34f, 1e34f);
@@ -489,22 +466,10 @@ void find_best_partitionings(
uncorr_errors[i] = uncorr_error;
samechroma_errors[i] = samechroma_error;
separate_errors[i] = separate_error;
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Partitioning %d-%d errors: uncorr=%g, samechroma=%g, sep-alpha=%g\n",
- partition_count, i, (double)uncorr_error, (double)samechroma_error, (double)separate_error.w);
- #endif
}
}
else
{
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Partition testing without alpha, %d partitions\n", partition_count);
- #endif
-
for (i = 0; i < PARTITION_COUNT; i++)
{
int partition = partition_sequence[i];
@@ -512,11 +477,6 @@ void find_best_partitionings(
int bk_partition_count = ptab[partition].partition_count;
if (bk_partition_count < partition_count)
{
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Partitioning %d-%d: invalid\n", partition_count, i);
- #endif
-
uncorr_errors[i] = 1e35f;
samechroma_errors[i] = 1e35f;
separate_errors[i] = float4(1e35f, 1e35f, 1e35f, 1e35f);
@@ -527,11 +487,6 @@ void find_best_partitionings(
// than the sentinel value for invalid partitions
if (i >= partition_search_limit)
{
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf(" Partitioning %d-%d: excluded from testing\n", partition_count, partition);
- #endif
-
defacto_search_limit = i;
uncorr_errors[i] = 1e34f;
samechroma_errors[i] = 1e34f;
@@ -712,13 +667,6 @@ void find_best_partitionings(
uncorr_errors[i] = uncorr_error;
samechroma_errors[i] = samechroma_error;
separate_errors[i] = float4(separate_error.x, separate_error.y, separate_error.z, 0.0f);
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Partitioning %d-%d errors: uncorr=%f, samechroma=%f, sep-red=%f, sep-green=%f, sep-blue=%f\n",
- partition_count, partition, (double)uncorr_error, (double)samechroma_error,
- (double)separate_error.x, (double)separate_error.y, (double)separate_error.z);
- #endif
}
}
@@ -798,10 +746,18 @@ void find_best_partitionings(
switch(best_component)
{
- case 0: separate_errors[best_partition].x = 1e30f; break;
- case 1: separate_errors[best_partition].y = 1e30f; break;
- case 2: separate_errors[best_partition].z = 1e30f; break;
- case 3: separate_errors[best_partition].w = 1e30f; break;
+ case 0:
+ separate_errors[best_partition].x = 1e30f;
+ break;
+ case 1:
+ separate_errors[best_partition].y = 1e30f;
+ break;
+ case 2:
+ separate_errors[best_partition].z = 1e30f;
+ break;
+ case 3:
+ separate_errors[best_partition].w = 1e30f;
+ break;
}
best_partition = (best_component << PARTITION_BITS) | partition_sequence[best_partition & (PARTITION_COUNT - 1)];
diff --git a/Source/astc_ideal_endpoints_and_weights.cpp b/Source/astcenc_ideal_endpoints_and_weights.cpp
similarity index 85%
rename from Source/astc_ideal_endpoints_and_weights.cpp
rename to Source/astcenc_ideal_endpoints_and_weights.cpp
index 7f7da58..53e716f 100644
--- a/Source/astc_ideal_endpoints_and_weights.cpp
+++ b/Source/astcenc_ideal_endpoints_and_weights.cpp
@@ -19,11 +19,9 @@
* @brief Functions for computing color endpoints and texel weights.
*/
-#include "astc_codec_internals.h"
+#include
-#ifdef DEBUG_PRINT_DIAGNOSTICS
- #include
-#endif
+#include "astcenc_internal.h"
#ifdef DEBUG_CAPTURE_NAN
#ifndef _GNU_SOURCE
@@ -39,7 +37,7 @@ static void compute_endpoints_and_ideal_weights_1_component(
const imageblock* blk,
const error_weight_block* ewb,
endpoints_and_weights* ei,
- int component
+ unsigned int component
) {
int i;
@@ -54,6 +52,7 @@ static void compute_endpoints_and_ideal_weights_1_component(
const float *error_weights;
const float* data_vr = nullptr;
+ assert(component <= 3);
switch (component)
{
case 0:
@@ -72,8 +71,6 @@ static void compute_endpoints_and_ideal_weights_1_component(
error_weights = ewb->texel_weight_a;
data_vr = blk->data_a;
break;
- default:
- ASTC_CODEC_INTERNAL_ERROR();
}
for (i = 0; i < partition_count; i++)
@@ -122,10 +119,7 @@ static void compute_endpoints_and_ideal_weights_1_component(
ei->weights[i] = value;
ei->weight_error_scale[i] = partition_error_scale[partition] * error_weights[i];
- if (astc::isnan(ei->weight_error_scale[i]))
- {
- ASTC_CODEC_INTERNAL_ERROR();
- }
+ assert(!astc::isnan(ei->weight_error_scale[i]));
}
for (i = 0; i < partition_count; i++)
@@ -152,27 +146,6 @@ static void compute_endpoints_and_ideal_weights_1_component(
break;
}
}
-
- // print all the data that this function computes.
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("%s: %dx%dx%d texels, %d partitions, component=%d\n", __func__, xdim, ydim, zdim, partition_count, component);
- printf("Endpoints:\n");
- for (i = 0; i < partition_count; i++)
- {
- printf("%d Low: <%g> => <%g %g %g %g>\n", i, lowvalues[i], ei->ep.endpt0[i].x, ei->ep.endpt0[i].y, ei->ep.endpt0[i].z, ei->ep.endpt0[i].w);
- printf("%d High: <%g> => <%g %g %g %g>\n", i, highvalues[i], ei->ep.endpt1[i].x, ei->ep.endpt1[i].y, ei->ep.endpt1[i].z, ei->ep.endpt1[i].w);
- }
- printf("Ideal-weights:\n");
-
- for (i = 0; i < texels_per_block; i++)
- {
- printf("%3d <%2d %2d %2d>=> %g (weight=%g)\n", i, i % xdim, (i / xdim) % ydim, i / (xdim * ydim), ei->weights[i], ei->weight_error_scale[i]);
- }
- printf("\n");
- }
- #endif
}
static void compute_endpoints_and_ideal_weights_2_components(
@@ -209,16 +182,12 @@ static void compute_endpoints_and_ideal_weights_2_components(
data_vr = blk->data_r;
data_vg = blk->data_b;
}
- else if (component1 == 1 && component2 == 2)
+ else // (component1 == 1 && component2 == 2)
{
error_weights = ewb->texel_weight_gb;
data_vr = blk->data_g;
data_vg = blk->data_b;
}
- else
- {
- ASTC_CODEC_INTERNAL_ERROR();
- }
int texels_per_block = bsd->texel_count;
@@ -408,32 +377,8 @@ static void compute_endpoints_and_ideal_weights_2_components(
ei->weights[i] = idx;
ei->weight_error_scale[i] = length_squared[partition] * error_weights[i];
- if (astc::isnan(ei->weight_error_scale[i]))
- {
- ASTC_CODEC_INTERNAL_ERROR();
- }
+ assert(!astc::isnan(ei->weight_error_scale[i]));
}
-
- // print all the data that this function computes.
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("%s: %dx%dx%d texels, %d partitions, component1=%d, component2=%d\n", __func__, xdim, ydim, zdim, partition_count, component1, component2);
- printf("Endpoints:\n");
- for (i = 0; i < partition_count; i++)
- {
- printf("%d Low: <%g %g> => <%g %g %g %g>\n", i, lowvalues[i].x, lowvalues[i].y, ei->ep.endpt0[i].x, ei->ep.endpt0[i].y, ei->ep.endpt0[i].z, ei->ep.endpt0[i].w);
- printf("%d High: <%g %g> => <%g %g %g %g>\n", i, highvalues[i].x, highvalues[i].y, ei->ep.endpt1[i].x, ei->ep.endpt1[i].y, ei->ep.endpt1[i].z, ei->ep.endpt1[i].w);
- }
- printf("Ideal-weights:\n");
-
- for (i = 0; i < texels_per_block; i++)
- {
- printf("%3d <%2d %2d %2d>=> %g (weight=%g)\n", i, i % xdim, (i / xdim) % ydim, i / (xdim * ydim), ei->weights[i], ei->weight_error_scale[i]);
- }
- printf("\n");
- }
- #endif
}
static void compute_endpoints_and_ideal_weights_3_components(
@@ -666,32 +611,8 @@ static void compute_endpoints_and_ideal_weights_3_components(
ei->weights[i] = idx;
ei->weight_error_scale[i] = length_squared[partition] * error_weights[i];
- if (astc::isnan(ei->weight_error_scale[i]))
- {
- ASTC_CODEC_INTERNAL_ERROR();
- }
+ assert(!astc::isnan(ei->weight_error_scale[i]));
}
-
- // print all the data that this function computes.
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("%s: %dx%dx%d texels, %d partitions, component1=%d, component2=%d, component3=%d\n", __func__, xdim, ydim, zdim, partition_count, component1, component2, component3);
- printf("Endpoints:\n");
- for (i = 0; i < partition_count; i++)
- {
- printf("%d Low: <%g %g %f> => <%g %g %g %g>\n", i, lowvalues[i].x, lowvalues[i].y, lowvalues[i].z, ei->ep.endpt0[i].x, ei->ep.endpt0[i].y, ei->ep.endpt0[i].z, ei->ep.endpt0[i].w);
- printf("%d High: <%g %g %g> => <%g %g %g %g>\n", i, highvalues[i].x, highvalues[i].y, highvalues[i].z, ei->ep.endpt1[i].x, ei->ep.endpt1[i].y, ei->ep.endpt1[i].z, ei->ep.endpt1[i].w);
- }
- printf("Ideal-weights:\n");
-
- for (i = 0; i < texels_per_block; i++)
- {
- printf("%3d <%2d %2d %2d>=> %g (weight=%g)\n", i, (i % xdim), (i / xdim) % ydim, i / (xdim * ydim), ei->weights[i], ei->weight_error_scale[i]);
- }
- printf("\n");
- }
- #endif
}
static void compute_endpoints_and_ideal_weights_rgba(
@@ -752,19 +673,6 @@ static void compute_endpoints_and_ideal_weights_rgba(
lines[i].b = normalize(directions_rgba[i]);
}
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- for (i = 0; i < partition_count; i++)
- {
- printf("Direction-vector %d: <%f %f %f %f>\n", i, directions_rgba[i].x, directions_rgba[i].y, directions_rgba[i].z, directions_rgba[i].w);
- printf("Line %d A: <%f %f %f %f>\n", i, lines[i].a.x, lines[i].a.y, lines[i].a.z, lines[i].a.w);
- printf("Line %d B: <%f %f %f %f>\n", i, lines[i].b.x, lines[i].b.y, lines[i].b.z, lines[i].b.w);
- printf("Scalefactors %d: <%f %f %f %f>\n", i, scalefactors[i].x, scalefactors[i].y, scalefactors[i].z, scalefactors[i].w);
- }
- }
- #endif
-
for (i = 0; i < texels_per_block; i++)
{
if (error_weights[i] > 1e-10f)
@@ -787,14 +695,6 @@ static void compute_endpoints_and_ideal_weights_rgba(
}
}
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- for (i = 0; i < partition_count; i++)
- printf("Partition %d: Lowparam=%f Highparam=%f\n", i, lowparam[i], highparam[i]);
- }
- #endif
-
for (i = 0; i < partition_count; i++)
{
float length = highparam[i] - lowparam[i];
@@ -840,33 +740,8 @@ static void compute_endpoints_and_ideal_weights_rgba(
idx = 0.0f;
ei->weights[i] = idx;
ei->weight_error_scale[i] = error_weights[i] * length_squared[partition];
- if (astc::isnan(ei->weight_error_scale[i]))
- {
- ASTC_CODEC_INTERNAL_ERROR();
- }
+ assert(!astc::isnan(ei->weight_error_scale[i]));
}
-
- // print all the data that this function computes.
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("%s: %dx%dx%d texels, %d partitions\n", __func__, xdim, ydim, zdim, partition_count);
- printf("Endpoints:\n");
- for (i = 0; i < partition_count; i++)
- {
- printf("%d Low: <%g %g %g %g>\n", i, ei->ep.endpt0[i].x, ei->ep.endpt0[i].y, ei->ep.endpt0[i].z, ei->ep.endpt0[i].w);
- printf("%d High: <%g %g %g %g>\n", i, ei->ep.endpt1[i].x, ei->ep.endpt1[i].y, ei->ep.endpt1[i].z, ei->ep.endpt1[i].w);
- }
- printf("\nIdeal-weights:\n");
-
- for (i = 0; i < texels_per_block; i++)
- {
- printf("%3d <%2d %2d %2d>=> %g (weight=%g)\n", i, i % xdim, (i / xdim) % ydim, i / (xdim * ydim), ei->weights[i], ei->weight_error_scale[i]);
- }
- printf("\n\n");
- }
- #endif
-
}
/*
@@ -883,11 +758,6 @@ void compute_endpoints_and_ideal_weights_1_plane(
const error_weight_block* ewb,
endpoints_and_weights* ei
) {
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("%s: texels_per_block=%dx%dx%d\n\n", __func__, xdim, ydim, zdim);
- #endif
-
int uses_alpha = imageblock_uses_alpha(blk);
if (uses_alpha)
{
@@ -908,11 +778,6 @@ void compute_endpoints_and_ideal_weights_2_planes(
endpoints_and_weights* ei1,
endpoints_and_weights* ei2
) {
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("%s: texels_per_block=%dx%dx%d, separate_component=%d\n\n", __func__, xdim, ydim, zdim, separate_component);
- #endif
-
int uses_alpha = imageblock_uses_alpha(blk);
switch (separate_component)
{
@@ -941,12 +806,8 @@ void compute_endpoints_and_ideal_weights_2_planes(
break;
case 3: // separate weights for alpha
- if (uses_alpha == 0)
- {
- ASTC_CODEC_INTERNAL_ERROR();
- }
+ assert(uses_alpha != 0);
compute_endpoints_and_ideal_weights_3_components(bsd, pt, blk, ewb, ei1, 3);
-
compute_endpoints_and_ideal_weights_1_component(bsd, pt, blk, ewb, ei2, 3);
break;
}
@@ -1150,19 +1011,6 @@ void compute_ideal_quantized_weights_for_decimation_table(
int weight_count = it->num_weights;
const quantization_and_transfer_table *qat = &(quant_and_xfer_tables[quantization_level]);
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("%s : texels-per-block=%d, weights=%d, quantization-level=%d\n\n", __func__, texels_per_block, weight_count, quantization_level);
-
- printf("Weight values before quantization:\n");
- for (i = 0; i < weight_count; i++)
- printf("%3d : %g\n", i, weight_set_in[i]);
-
- printf("Low-bound: %f High-bound: %f\n", low_bound, high_bound);
- }
- #endif
-
static const int quant_levels[12] = { 2,3,4,5,6,8,10,12,16,20,24,32 };
float quant_level_m1 = (float)(quant_levels[quantization_level] - 1);
@@ -1186,7 +1034,7 @@ void compute_ideal_quantized_weights_for_decimation_table(
int i = 0;
-#if ASTC_AVX >= 2
+#if ASTCENC_AVX >= 2
// TODO: This is currently 4-wide. Could try 8?
int clipped_weight_count = weight_count & ~3;
__m128i shuf = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1,
@@ -1352,20 +1200,6 @@ void recompute_ideal_colors(
int partition_count = pi->partition_count;
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("%s : %dx%dx%d texels_per_block, %d partitions, plane2-color-component=%d\n\n", __func__, xdim, ydim, zdim, partition_count, plane2_color_component);
-
- printf("Pre-adjustment endpoint-colors: \n");
- for (int i = 0; i < partition_count; i++)
- {
- printf("%d Low <%g %g %g %g>\n", i, ep->endpt0[i].x, ep->endpt0[i].y, ep->endpt0[i].z, ep->endpt0[i].w);
- printf("%d High <%g %g %g %g>\n", i, ep->endpt1[i].x, ep->endpt1[i].y, ep->endpt1[i].z, ep->endpt1[i].w);
- }
- }
- #endif
-
for (int i = 0; i < partition_count; i++)
{
float4 rgba_sum = float4(1e-17f, 1e-17f, 1e-17f, 1e-17f);
@@ -1603,14 +1437,6 @@ void recompute_ideal_colors(
+ (2.0f * lmrs_sum.y * lmrs_sum.y)
+ (lmrs_sum.z * lmrs_sum.z);
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Plane-1 partition %d determinants: R=%g G=%g B=%g A=%g L=%g S=%g\n", i,
- (double)color_det1.x, (double)color_det1.y,
- (double)color_det1.z, (double)color_det1.w,
- (double)ls_det1, (double)ls_det1);
- #endif
-
float4 ep0 = (right_sum * color_vec_x - middle_sum * color_vec_y) * color_rdet1;
float4 ep1 = (left_sum * color_vec_y - middle_sum * color_vec_x) * color_rdet1;
@@ -1695,12 +1521,6 @@ void recompute_ideal_colors(
+ (2.0f * middle2_sum * middle2_sum)
+ (right2_sum * right2_sum);
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("Plane-2 partition %d determinants: R=%g G=%g B=%g A=%g\n",
- i, (double)color_det2.x, (double)color_det2.y, (double)color_det2.z, (double)color_det2.w);
- #endif
-
float4 ep0 = (right2_sum * color_vec_x - middle2_sum * color_vec_y) * color_rdet2;
float4 ep1 = (left2_sum * color_vec_y - middle2_sum * color_vec_x) * color_rdet2;
@@ -1751,26 +1571,4 @@ void recompute_ideal_colors(
rgbo_vectors[i] = float4(ep0.x, ep0.y, ep0.z, avgdif);
}
}
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("Post-adjustment endpoint-colors: \n");
- for (int i = 0; i < partition_count; i++)
- {
- printf("%d Low <%g %g %g %g>\n", i,
- (double)ep->endpt0[i].x, (double)ep->endpt0[i].y,
- (double)ep->endpt0[i].z, (double)ep->endpt0[i].w);
- printf("%d High <%g %g %g %g>\n", i,
- (double)ep->endpt1[i].x, (double)ep->endpt1[i].y,
- (double)ep->endpt1[i].z, (double)ep->endpt1[i].w);
- printf("%d RGBS: <%g %g %g %g>\n", i,
- (double)rgbs_vectors[i].x, (double)rgbs_vectors[i].y,
- (double)rgbs_vectors[i].z, (double)rgbs_vectors[i].w);
- printf("%d RGBO <%g %g %g %g>\n", i,
- (double)rgbo_vectors[i].x, (double)rgbo_vectors[i].y,
- (double)rgbo_vectors[i].z, (double)rgbo_vectors[i].w);
- }
- }
- #endif
}
diff --git a/Source/astc_image.cpp b/Source/astcenc_image.cpp
similarity index 60%
rename from Source/astc_image.cpp
rename to Source/astcenc_image.cpp
index b6d7efb..b454d05 100644
--- a/Source/astc_image.cpp
+++ b/Source/astcenc_image.cpp
@@ -19,256 +19,10 @@
* @brief Functions for creating in-memory ASTC image structures.
*/
+#include
#include
-#include "astc_codec_internals.h"
-astc_codec_image *alloc_image(
- int bitness,
- int xsize,
- int ysize,
- int zsize,
- int padding
-) {
- int i, j;
- astc_codec_image *img = new astc_codec_image;
- img->xsize = xsize;
- img->ysize = ysize;
- img->zsize = zsize;
- img->padding = padding;
-
- img->input_averages = nullptr;
- img->input_variances = nullptr;
- img->input_alpha_averages = nullptr;
-
- img->linearize_srgb = 0;
- img->rgb_force_use_of_hdr = 0;
- img->alpha_force_use_of_hdr = 0;
-
- int exsize = xsize + 2 * padding;
- int eysize = ysize + 2 * padding;
- int ezsize = (zsize == 1) ? 1 : zsize + 2 * padding;
-
- if (bitness == 8)
- {
- img->data8 = new uint8_t **[ezsize];
- img->data8[0] = new uint8_t *[ezsize * eysize];
- img->data8[0][0] = new uint8_t[4 * ezsize * eysize * exsize];
- memset(img->data8[0][0], 0, 4 * ezsize * eysize * exsize);
-
- for (i = 1; i < ezsize; i++)
- {
- img->data8[i] = img->data8[0] + i * eysize;
- img->data8[i][0] = img->data8[0][0] + 4 * i * exsize * eysize;
- }
-
- for (i = 0; i < ezsize; i++)
- {
- for (j = 1; j < eysize; j++)
- {
- img->data8[i][j] = img->data8[i][0] + 4 * j * exsize;
- }
- }
-
- img->data16 = nullptr;
- }
- else if (bitness == 16)
- {
- img->data16 = new uint16_t **[ezsize];
- img->data16[0] = new uint16_t *[ezsize * eysize];
- img->data16[0][0] = new uint16_t[4 * ezsize * eysize * exsize];
- memset(img->data16[0][0], 0, 8 * ezsize * eysize * exsize);
-
- for (i = 1; i < ezsize; i++)
- {
- img->data16[i] = img->data16[0] + i * eysize;
- img->data16[i][0] = img->data16[0][0] + 4 * i * exsize * eysize;
- }
-
- for (i = 0; i < ezsize; i++)
- {
- for (j = 1; j < eysize; j++)
- {
- img->data16[i][j] = img->data16[i][0] + 4 * j * exsize;
- }
- }
-
- img->data8 = nullptr;
- }
- else
- {
- ASTC_CODEC_INTERNAL_ERROR();
- }
-
- return img;
-}
-
-void free_image(astc_codec_image * img)
-{
- if (img == nullptr)
- {
- return;
- }
-
- if (img->data8)
- {
- delete[] img->data8[0][0];
- delete[] img->data8[0];
- delete[] img->data8;
- }
-
- if (img->data16)
- {
- delete[] img->data16[0][0];
- delete[] img->data16[0];
- delete[] img->data16;
- }
-
- if (img->input_averages)
- {
- delete[] img->input_averages;
- }
-
- if (img->input_variances)
- {
- delete[] img->input_variances;
- }
-
- if (img->input_alpha_averages)
- {
- delete[] img->input_alpha_averages;
- }
-
- delete img;
-}
-
-
-// fill the padding area of the input-file buffer with clamp-to-edge data
-// Done inefficiently, in that it will overwrite all the interior data at least once;
-// this is not considered a problem, since this makes up a very small part of total
-// running time.
-void fill_image_padding_area(astc_codec_image * img)
-{
- if (img->padding == 0)
- {
- return;
- }
-
- int x, y, z, i;
- int exsize = img->xsize + 2 * img->padding;
- int eysize = img->ysize + 2 * img->padding;
- int ezsize = (img->zsize == 1) ? 1 : (img->zsize + 2 * img->padding);
-
- int xmin = img->padding;
- int ymin = img->padding;
- int zmin = (img->zsize == 1) ? 0 : img->padding;
- int xmax = img->xsize + img->padding - 1;
- int ymax = img->ysize + img->padding - 1;
- int zmax = (img->zsize == 1) ? 0 : img->zsize + img->padding - 1;
-
- // This is a very simple implementation. Possible optimizations include:
- // * Testing if texel is outside the edge.
- // * Looping over texels that we know are outside the edge.
- if (img->data8)
- {
- for (z = 0; z < ezsize; z++)
- {
- int zc = MIN(MAX(z, zmin), zmax);
- for (y = 0; y < eysize; y++)
- {
- int yc = MIN(MAX(y, ymin), ymax);
- for (x = 0; x < exsize; x++)
- {
- int xc = MIN(MAX(x, xmin), xmax);
- for (i = 0; i < 4; i++)
- {
- img->data8[z][y][4 * x + i] = img->data8[zc][yc][4 * xc + i];
- }
- }
- }
- }
- }
- else if (img->data16)
- {
- for (z = 0; z < ezsize; z++)
- {
- int zc = MIN(MAX(z, zmin), zmax);
- for (y = 0; y < eysize; y++)
- {
- int yc = MIN(MAX(y, ymin), ymax);
- for (x = 0; x < exsize; x++)
- {
- int xc = MIN(MAX(x, xmin), xmax);
- for (i = 0; i < 4; i++)
- {
- img->data16[z][y][4 * x + i] = img->data16[zc][yc][4 * xc + i];
- }
- }
- }
- }
- }
-}
-
-
-int determine_image_channels(const astc_codec_image * img)
-{
- int x, y, z;
-
- int xsize = img->xsize;
- int ysize = img->ysize;
- int zsize = img->zsize;
- // scan through the image data
- // to determine how many color channels the image has.
-
- int lum_mask;
- int alpha_mask;
- int alpha_mask_ref;
- if (img->data8)
- {
- alpha_mask_ref = 0xFF;
- alpha_mask = 0xFF;
- lum_mask = 0;
- for (z = 0; z < zsize; z++)
- {
- for (y = 0; y < ysize; y++)
- {
- for (x = 0; x < xsize; x++)
- {
- int r = img->data8[z][y][4 * x];
- int g = img->data8[z][y][4 * x + 1];
- int b = img->data8[z][y][4 * x + 2];
- int a = img->data8[z][y][4 * x + 3];
- lum_mask |= (r ^ g) | (r ^ b);
- alpha_mask &= a;
- }
- }
- }
- }
- else // (bitness == 16)
- {
- alpha_mask_ref = 0xFFFF;
- alpha_mask = 0xFFFF;
- lum_mask = 0;
- for (z = 0; z < zsize; z++)
- {
- for (y = 0; y < ysize; y++)
- {
- for (x = 0; x < xsize; x++)
- {
- int r = img->data16[z][y][4 * x];
- int g = img->data16[z][y][4 * x + 1];
- int b = img->data16[z][y][4 * x + 2];
- int a = img->data16[z][y][4 * x + 3];
- lum_mask |= (r ^ g) | (r ^ b);
- alpha_mask &= (a ^ 0xC3FF); // a ^ 0xC3FF returns FFFF if and only if the input is 1.0
- }
- }
- }
- }
-
- int image_channels = 1 + (lum_mask == 0 ? 0 : 2) + (alpha_mask == alpha_mask_ref ? 0 : 1);
-
- return image_channels;
-}
+#include "astcenc_internal.h"
// conversion functions between the LNS representation and the FP16 representation.
float float_to_lns(float p)
@@ -493,6 +247,7 @@ void imageblock_initialize_orig_from_work(
// fetch an imageblock from the input file.
void fetch_imageblock(
+ astcenc_profile decode_mode,
const astc_codec_image* img,
imageblock* pb, // picture-block to initialize with image data
const block_size_descriptor* bsd,
@@ -500,7 +255,7 @@ void fetch_imageblock(
int xpos,
int ypos,
int zpos,
- swizzlepattern swz
+ astcenc_swizzle swz
) {
float *fptr = pb->orig_data;
int xsize = img->xsize + 2 * img->padding;
@@ -626,6 +381,7 @@ void fetch_imageblock(
// perform sRGB-to-linear transform on input data, if requested.
int pixelcount = bsd->texel_count;
+ // sRGB to Linear
if (img->linearize_srgb)
{
fptr = pb->orig_data;
@@ -686,18 +442,8 @@ void fetch_imageblock(
fptr += 4;
}
- float max_rgb = MAX(max_red, MAX(max_green, max_blue));
-
- // use LNS if:
- // * RGB-maximum is less than 0.15
- // * RGB-maximum is greater than 1
- // * Alpha-maximum is greater than 1
- int rgb_lns = (max_rgb < 0.15f || max_rgb > 1.0f || max_alpha > 1.0f) ? 1 : 0;
- int alpha_lns = rgb_lns ? (max_alpha > 1.0f || max_alpha < 0.15f) : 0;
-
- // not yet though; for the time being, just obey the command line.
- rgb_lns = img->rgb_force_use_of_hdr;
- alpha_lns = img->alpha_force_use_of_hdr;
+ int rgb_lns = (decode_mode == ASTCENC_PRF_HDR) || (decode_mode == ASTCENC_PRF_HDR_RGB_LDR_A);
+ int alpha_lns = decode_mode == ASTCENC_PRF_HDR;
// impose the choice on every pixel when encoding.
for (i = 0; i < pixelcount; i++)
@@ -719,7 +465,7 @@ void write_imageblock(
int xpos,
int ypos,
int zpos,
- swizzlepattern swz
+ astcenc_swizzle swz
) {
const float *fptr = pb->orig_data;
const uint8_t *nptr = pb->nan_texel;
@@ -756,7 +502,7 @@ void write_imageblock(
}
else
{
- // apply swizzle
+ // Linear to sRGB
if (img->linearize_srgb)
{
float r = fptr[0];
@@ -853,7 +599,7 @@ void write_imageblock(
else
{
- // apply swizzle
+ // Linear to sRGB
if (img->linearize_srgb)
{
float r = fptr[0];
@@ -967,157 +713,3 @@ void update_imageblock_flags(
pb->alpha_max = alpha_max;
pb->grayscale = grayscale;
}
-
-// initialize an astc_codec_image data structure from a 2D array of RGBA float*4
-astc_codec_image* astc_img_from_floatx4_array(
- const float* image,
- int xsize,
- int ysize,
- int padding,
- int y_flip
-) {
- astc_codec_image* astc_img = alloc_image(16, xsize, ysize, 1, padding);
-
- for (int y = 0; y < ysize; y++)
- {
- int y_dst = y + padding;
- int y_src = y_flip ? (ysize - y - 1) : y;
- const float* src = image + 4 * xsize * y_src;
-
- for (int x = 0; x < xsize; x++)
- {
- int x_dst = x + padding;
- astc_img->data16[0][y_dst][4 * x_dst] = float_to_sf16(src[4 * x], SF_NEARESTEVEN);
- astc_img->data16[0][y_dst][4 * x_dst + 1] = float_to_sf16(src[4 * x + 1], SF_NEARESTEVEN);
- astc_img->data16[0][y_dst][4 * x_dst + 2] = float_to_sf16(src[4 * x + 2], SF_NEARESTEVEN);
- astc_img->data16[0][y_dst][4 * x_dst + 3] = float_to_sf16(src[4 * x + 3], SF_NEARESTEVEN);
- }
- }
-
- fill_image_padding_area(astc_img);
- return astc_img;
-}
-
-// initialize an astc_codec_image data structure from a 2D array of UNORM8
-astc_codec_image* astc_img_from_unorm8x4_array(
- const uint8_t* imageptr,
- int xsize,
- int ysize,
- int padding,
- int y_flip
-) {
- astc_codec_image *astc_img = alloc_image(8, xsize, ysize, 1, padding);
-
- for (int y = 0; y < ysize; y++)
- {
- int y_dst = y + padding;
- int y_src = y_flip ? (ysize - y - 1) : y;
- const uint8_t* src = imageptr + 4 * xsize * y_src;
-
- for (int x = 0; x < xsize; x++)
- {
- int x_dst = x + padding;
- astc_img->data8[0][y_dst][4 * x_dst] = src[4 * x];
- astc_img->data8[0][y_dst][4 * x_dst + 1] = src[4 * x + 1];
- astc_img->data8[0][y_dst][4 * x_dst + 2] = src[4 * x + 2];
- astc_img->data8[0][y_dst][4 * x_dst + 3] = src[4 * x + 3];
- }
- }
-
- fill_image_padding_area(astc_img);
- return astc_img;
-}
-
-// initialize a flattened array of float4 values from an ASTC codec image
-// The returned array is allocated with malloc() and needs to be freed with free().
-float* floatx4_array_from_astc_img(
- const astc_codec_image* img,
- int y_flip
-) {
- int xsize = img->xsize;
- int ysize = img->ysize;
-
- float *buf = (float *)malloc(4 * sizeof(float) * xsize * ysize);
-
- if (img->data8)
- {
- for (int y = 0; y < ysize; y++)
- {
- int ymod = y_flip ? ysize - y - 1 : y;
- const uint8_t* src = img->data8[0][ymod + img->padding] + (4 * img->padding);
- float* dst = buf + y * xsize * 4;
- for (int x = 0; x < xsize; x++)
- {
- dst[4 * x] = src[4 * x] * (1.0f / 255.0f);
- dst[4 * x + 1] = src[4 * x + 1] * (1.0f / 255.0f);
- dst[4 * x + 2] = src[4 * x + 2] * (1.0f / 255.0f);
- dst[4 * x + 3] = src[4 * x + 3] * (1.0f / 255.0f);
- }
- }
- }
- else
- {
- for (int y = 0; y < ysize; y++)
- {
- int ymod = y_flip ? ysize - y - 1 : y;
- const uint16_t *src = img->data16[0][ymod + img->padding] + (4 * img->padding);
- float *dst = buf + y * xsize * 4;
- for (int x = 0; x < xsize; x++)
- {
- dst[4 * x] = sf16_to_float(src[4 * x]);
- dst[4 * x + 1] = sf16_to_float(src[4 * x + 1]);
- dst[4 * x + 2] = sf16_to_float(src[4 * x + 2]);
- dst[4 * x + 3] = sf16_to_float(src[4 * x + 3]);
- }
- }
- }
-
- return buf;
-}
-
-// initialize a flattened array of unorm8x4 values from an ASTC codec image
-// The returned array is allocated with malloc() and needs to be freed with free().
-uint8_t* unorm8x4_array_from_astc_img(
- const astc_codec_image* img,
- int y_flip
-) {
- int xsize = img->xsize;
- int ysize = img->ysize;
-
- uint8_t* buf = (uint8_t*)malloc(4 * sizeof(uint8_t) * xsize * ysize);
-
- if (img->data8)
- {
- for (int y = 0; y < ysize; y++)
- {
- int ymod = y_flip ? ysize-y-1 : y;
- const uint8_t* src = img->data8[0][ymod + img->padding] + (4 * img->padding);
- uint8_t* dst = buf + y * xsize * 4;
- for (int x = 0; x < xsize; x++)
- {
- dst[4 * x] = src[4 * x];
- dst[4 * x + 1] = src[4 * x + 1];
- dst[4 * x + 2] = src[4 * x + 2];
- dst[4 * x + 3] = src[4 * x + 3];
- }
- }
- }
- else
- {
- for (int y = 0; y < ysize; y++)
- {
- int ymod = y_flip ? ysize-y-1 : y;
- const uint16_t* src = img->data16[0][ymod + img->padding] + (4 * img->padding);
- uint8_t* dst = buf + y * xsize * 4;
- for (int x = 0; x < xsize; x++)
- {
- dst[4 * x] = (uint8_t)astc::flt2int_rtn(astc::clamp1f(sf16_to_float(src[4*x])) * 255.0f);
- dst[4 * x + 1] = (uint8_t)astc::flt2int_rtn(astc::clamp1f(sf16_to_float(src[4*x+1])) * 255.0f);
- dst[4 * x + 2] = (uint8_t)astc::flt2int_rtn(astc::clamp1f(sf16_to_float(src[4*x+2])) * 255.0f);
- dst[4 * x + 3] = (uint8_t)astc::flt2int_rtn(astc::clamp1f(sf16_to_float(src[4*x+3])) * 255.0f);
- }
- }
- }
-
- return buf;
-}
diff --git a/Source/astc_integer_sequence.cpp b/Source/astcenc_integer_sequence.cpp
similarity index 91%
rename from Source/astc_integer_sequence.cpp
rename to Source/astcenc_integer_sequence.cpp
index bdabe4c..f38426f 100644
--- a/Source/astc_integer_sequence.cpp
+++ b/Source/astcenc_integer_sequence.cpp
@@ -19,42 +19,42 @@
* @brief Functions for encoding/decoding Bounded Integer Sequence Encoding.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
// unpacked quint triplets for each packed-quint value
static const uint8_t quints_of_integer[128][3] = {
- {0, 0, 0}, {1, 0, 0}, {2, 0, 0}, {3, 0, 0},
- {4, 0, 0}, {0, 4, 0}, {4, 4, 0}, {4, 4, 4},
- {0, 1, 0}, {1, 1, 0}, {2, 1, 0}, {3, 1, 0},
- {4, 1, 0}, {1, 4, 0}, {4, 4, 1}, {4, 4, 4},
- {0, 2, 0}, {1, 2, 0}, {2, 2, 0}, {3, 2, 0},
- {4, 2, 0}, {2, 4, 0}, {4, 4, 2}, {4, 4, 4},
- {0, 3, 0}, {1, 3, 0}, {2, 3, 0}, {3, 3, 0},
- {4, 3, 0}, {3, 4, 0}, {4, 4, 3}, {4, 4, 4},
- {0, 0, 1}, {1, 0, 1}, {2, 0, 1}, {3, 0, 1},
- {4, 0, 1}, {0, 4, 1}, {4, 0, 4}, {0, 4, 4},
- {0, 1, 1}, {1, 1, 1}, {2, 1, 1}, {3, 1, 1},
- {4, 1, 1}, {1, 4, 1}, {4, 1, 4}, {1, 4, 4},
- {0, 2, 1}, {1, 2, 1}, {2, 2, 1}, {3, 2, 1},
- {4, 2, 1}, {2, 4, 1}, {4, 2, 4}, {2, 4, 4},
- {0, 3, 1}, {1, 3, 1}, {2, 3, 1}, {3, 3, 1},
- {4, 3, 1}, {3, 4, 1}, {4, 3, 4}, {3, 4, 4},
- {0, 0, 2}, {1, 0, 2}, {2, 0, 2}, {3, 0, 2},
- {4, 0, 2}, {0, 4, 2}, {2, 0, 4}, {3, 0, 4},
- {0, 1, 2}, {1, 1, 2}, {2, 1, 2}, {3, 1, 2},
- {4, 1, 2}, {1, 4, 2}, {2, 1, 4}, {3, 1, 4},
- {0, 2, 2}, {1, 2, 2}, {2, 2, 2}, {3, 2, 2},
- {4, 2, 2}, {2, 4, 2}, {2, 2, 4}, {3, 2, 4},
- {0, 3, 2}, {1, 3, 2}, {2, 3, 2}, {3, 3, 2},
- {4, 3, 2}, {3, 4, 2}, {2, 3, 4}, {3, 3, 4},
- {0, 0, 3}, {1, 0, 3}, {2, 0, 3}, {3, 0, 3},
- {4, 0, 3}, {0, 4, 3}, {0, 0, 4}, {1, 0, 4},
- {0, 1, 3}, {1, 1, 3}, {2, 1, 3}, {3, 1, 3},
- {4, 1, 3}, {1, 4, 3}, {0, 1, 4}, {1, 1, 4},
- {0, 2, 3}, {1, 2, 3}, {2, 2, 3}, {3, 2, 3},
- {4, 2, 3}, {2, 4, 3}, {0, 2, 4}, {1, 2, 4},
- {0, 3, 3}, {1, 3, 3}, {2, 3, 3}, {3, 3, 3},
- {4, 3, 3}, {3, 4, 3}, {0, 3, 4}, {1, 3, 4}
+ {0, 0, 0}, {1, 0, 0}, {2, 0, 0}, {3, 0, 0},
+ {4, 0, 0}, {0, 4, 0}, {4, 4, 0}, {4, 4, 4},
+ {0, 1, 0}, {1, 1, 0}, {2, 1, 0}, {3, 1, 0},
+ {4, 1, 0}, {1, 4, 0}, {4, 4, 1}, {4, 4, 4},
+ {0, 2, 0}, {1, 2, 0}, {2, 2, 0}, {3, 2, 0},
+ {4, 2, 0}, {2, 4, 0}, {4, 4, 2}, {4, 4, 4},
+ {0, 3, 0}, {1, 3, 0}, {2, 3, 0}, {3, 3, 0},
+ {4, 3, 0}, {3, 4, 0}, {4, 4, 3}, {4, 4, 4},
+ {0, 0, 1}, {1, 0, 1}, {2, 0, 1}, {3, 0, 1},
+ {4, 0, 1}, {0, 4, 1}, {4, 0, 4}, {0, 4, 4},
+ {0, 1, 1}, {1, 1, 1}, {2, 1, 1}, {3, 1, 1},
+ {4, 1, 1}, {1, 4, 1}, {4, 1, 4}, {1, 4, 4},
+ {0, 2, 1}, {1, 2, 1}, {2, 2, 1}, {3, 2, 1},
+ {4, 2, 1}, {2, 4, 1}, {4, 2, 4}, {2, 4, 4},
+ {0, 3, 1}, {1, 3, 1}, {2, 3, 1}, {3, 3, 1},
+ {4, 3, 1}, {3, 4, 1}, {4, 3, 4}, {3, 4, 4},
+ {0, 0, 2}, {1, 0, 2}, {2, 0, 2}, {3, 0, 2},
+ {4, 0, 2}, {0, 4, 2}, {2, 0, 4}, {3, 0, 4},
+ {0, 1, 2}, {1, 1, 2}, {2, 1, 2}, {3, 1, 2},
+ {4, 1, 2}, {1, 4, 2}, {2, 1, 4}, {3, 1, 4},
+ {0, 2, 2}, {1, 2, 2}, {2, 2, 2}, {3, 2, 2},
+ {4, 2, 2}, {2, 4, 2}, {2, 2, 4}, {3, 2, 4},
+ {0, 3, 2}, {1, 3, 2}, {2, 3, 2}, {3, 3, 2},
+ {4, 3, 2}, {3, 4, 2}, {2, 3, 4}, {3, 3, 4},
+ {0, 0, 3}, {1, 0, 3}, {2, 0, 3}, {3, 0, 3},
+ {4, 0, 3}, {0, 4, 3}, {0, 0, 4}, {1, 0, 4},
+ {0, 1, 3}, {1, 1, 3}, {2, 1, 3}, {3, 1, 3},
+ {4, 1, 3}, {1, 4, 3}, {0, 1, 4}, {1, 1, 4},
+ {0, 2, 3}, {1, 2, 3}, {2, 2, 3}, {3, 2, 3},
+ {4, 2, 3}, {2, 4, 3}, {0, 2, 4}, {1, 2, 4},
+ {0, 3, 3}, {1, 3, 3}, {2, 3, 3}, {3, 3, 3},
+ {4, 3, 3}, {3, 4, 3}, {0, 3, 4}, {1, 3, 4}
};
// packed quint-value for every unpacked quint-triplet
diff --git a/Source/astc_codec_internals.h b/Source/astcenc_internal.h
similarity index 86%
rename from Source/astc_codec_internals.h
rename to Source/astcenc_internal.h
index 5f77cf2..2a18489 100644
--- a/Source/astc_codec_internals.h
+++ b/Source/astcenc_internal.h
@@ -19,25 +19,29 @@
* @brief Functions and data declarations.
*/
-#ifndef ASTC_CODEC_INTERNALS_INCLUDED
-#define ASTC_CODEC_INTERNALS_INCLUDED
+#ifndef ASTCENC_INTERNAL_INCLUDED
+#define ASTCENC_INTERNAL_INCLUDED
#include
#include
#include
#include
-#include "astc_mathlib.h"
-
-// Temporary workaround to build machine still running VS2013
-// Version 1910 is Visual Studio 2017
-#if !defined(_MSC_VER) || (_MSC_VER >= 1910)
- #define NORETURN [[noreturn]]
-#else
- #define NORETURN
- #define __func__ __FUNCTION__
+#ifndef ASTCENC_SSE
+#error ERROR: ASTCENC_SSE not defined
#endif
+#ifndef ASTCENC_POPCNT
+#error ERROR: ASTCENC_POPCNT not defined
+#endif
+
+#ifndef ASTCENC_AVX
+#error ERROR: ASTCENC_AVX not defined
+#endif
+
+#include "astcenc.h"
+#include "astcenc_mathlib.h"
+
// ASTC parameters
#define MAX_TEXELS_PER_BLOCK 216
#define MAX_WEIGHTS_PER_BLOCK 64
@@ -51,32 +55,10 @@
#define MAX_DECIMATION_MODES 87
#define MAX_WEIGHT_MODES 2048
-// error reporting for codec internal errors.
-#define ASTC_CODEC_INTERNAL_ERROR() astc_codec_internal_error(__FILE__, __LINE__)
-NORETURN void astc_codec_internal_error(const char *filename, int linenumber);
-
// uncomment this macro to enable checking for inappropriate NaNs;
// works on Linux only, and slows down encoding significantly.
// #define DEBUG_CAPTURE_NAN
-// uncomment this macro to enable the ability to log diagnostics using the
-// -diag command line switch, which is useful for bug hunting in the encoder
-// #define DEBUG_PRINT_DIAGNOSTICS
-
-#ifdef DEBUG_PRINT_DIAGNOSTICS
- extern int print_diagnostics;
- extern int print_tile_errors;
- extern int print_statistics;
-#endif
-
-enum astc_decode_mode
-{
- DECODE_LDR_SRGB,
- DECODE_LDR,
- DECODE_HDR,
- DECODE_HDRA
-};
-
/*
Partition table representation:
For each block size, we have 3 tables, each with 1024 partitionings;
@@ -367,7 +349,7 @@ enum endpoint_formats
FMT_RGBA = 12,
FMT_RGBA_DELTA = 13,
FMT_HDR_RGB_LDR_ALPHA = 14,
- FMT_HDR_RGBA = 15,
+ FMT_HDR_RGBA = 15
};
struct symbolic_compressed_block
@@ -391,15 +373,6 @@ struct physical_compressed_block
uint8_t data[16];
};
-/* ============================================================================
- Functions for printing build info and help messages
-============================================================================ */
-void astcenc_print_header();
-
-void astcenc_print_shorthelp();
-
-void astcenc_print_longhelp();
-
/* ============================================================================
Functions and data pertaining to quantization and encoding
============================================================================ */
@@ -643,62 +616,15 @@ struct astc_codec_image
float4 *input_averages;
float4 *input_variances;
float *input_alpha_averages;
-
int linearize_srgb;
- int rgb_force_use_of_hdr;
- int alpha_force_use_of_hdr;
};
-astc_codec_image* alloc_image(
- int bitness,
- int xsize,
- int ysize,
- int zsize,
- int padding);
-void free_image(
- astc_codec_image* img);
-
-void fill_image_padding_area(
- astc_codec_image* img);
-
-int determine_image_channels(
- const astc_codec_image* img);
-
-// helper functions to prepare an ASTC image object from a flat array
-// Used by the image loaders in "astc_file_load_store.cpp"
-astc_codec_image* astc_img_from_floatx4_array(
- const float* image,
- int xsize,
- int ysize,
- int padding,
- int y_flip);
-
-astc_codec_image*astc_img_from_unorm8x4_array(
- const uint8_t*imageptr,
- int xsize,
- int ysize,
- int padding,
- int y_flip);
-
-// helper functions to prepare a flat array from an ASTC image object.
-// the array is allocated with malloc(); caller needs to use free()
-// to free it.
-float* floatx4_array_from_astc_img(
- const astc_codec_image* img,
- int y_flip);
-
-uint8_t* unorm8x4_array_from_astc_img(
- const astc_codec_image* img,
- int y_flip);
-
-// the entries here : 0=red, 1=green, 2=blue, 3=alpha, 4=0.0, 5=1.0
-struct swizzlepattern
+struct astcenc_context
{
- uint8_t r;
- uint8_t g;
- uint8_t b;
- uint8_t a;
+ astcenc_config config;
+ block_size_descriptor* bsd;
+ unsigned int thread_count;
};
/**
@@ -723,60 +649,12 @@ void compute_averages_and_variances(
int avg_var_kernel_radius,
int alpha_kernel_radius,
int need_srgb_transform,
- swizzlepattern swz,
+ astcenc_swizzle swz,
int thread_count);
-/*
- Functions to load image from file.
- If successful, return an astc_codec_image object.
- If unsuccessful, returns nullptr.
-
- *result is used to return a result. In case of a successfully loaded image, bits[2:0]
- of *result indicate how many components are present, and bit[7] indicate whether
- the input image was LDR or HDR (0=LDR, 1=HDR).
-
- In case of failure, *result is given a negative value.
-*/
-
-astc_codec_image* astc_codec_load_image(
- const char* filename,
- int padding,
- int y_flip,
- int linearize_srgb,
- int rgb_force_use_of_hdr,
- int alpha_force_use_of_hdr,
- int* result);
-
-int astc_codec_store_image(
- const astc_codec_image* output_image,
- const char* output_filename,
- const char** file_format_name,
- int y_flip);
-
-int get_output_filename_enforced_bitness(
- const char* filename);
-
-/**
- * @brief Compute error metrics comparing two images.
- *
- * @param compute_hdr_metrics Non-zero if HDR metrics should be computed.
- * @param input_components The number of input color components.
- * @param img1 The original iamge.
- * @param img2 The compressed image.
- * @param fstop_lo The low exposure fstop (HDR only).
- * @param fstop_hi The high exposure fstop (HDR only).
- * @param show_psnr Non-zero if metrics should be logged to stdout.
- */
-void compute_error_metrics(
- int compute_hdr_metrics,
- int input_components,
- const astc_codec_image* img1,
- const astc_codec_image* img2,
- int fstop_lo,
- int fstop_hi);
-
// fetch an image-block from the input file
void fetch_imageblock(
+ astcenc_profile decode_mode,
const astc_codec_image* img,
imageblock* pb, // picture-block to initialize with image data
const block_size_descriptor* bsd,
@@ -784,7 +662,7 @@ void fetch_imageblock(
int xpos,
int ypos,
int zpos,
- swizzlepattern swz);
+ astcenc_swizzle swz);
// write an image block to the output file buffer.
// the data written are taken from orig_data.
@@ -796,7 +674,7 @@ void write_imageblock(
int xpos,
int ypos,
int zpos,
- swizzlepattern swz);
+ astcenc_swizzle swz);
// helper function to check whether a given picture-block has alpha that is not
// just uniformly 1.
@@ -883,8 +761,7 @@ int pack_color_endpoints(
// unpack a pair of color endpoints from a series of integers.
void unpack_color_endpoints(
- const astc_codec_image* image,
- astc_decode_mode decode_mode,
+ astcenc_profile decode_mode,
int format,
int quantization_level,
const int* input,
@@ -966,9 +843,9 @@ void recompute_ideal_colors(
const error_weight_block* ewb);
void expand_block_artifact_suppression(
- int xdim,
- int ydim,
- int zdim,
+ unsigned int xdim,
+ unsigned int ydim,
+ unsigned int zdim,
error_weighting_params* ewp);
// functions pertaining to weight alignment
@@ -1001,7 +878,7 @@ void compute_angular_endpoints_2planes(
float compress_symbolic_block(
const astc_codec_image* input_image,
- astc_decode_mode decode_mode,
+ astcenc_profile decode_mode,
const block_size_descriptor* bsd,
const error_weighting_params* ewp,
const imageblock* blk,
@@ -1009,8 +886,7 @@ float compress_symbolic_block(
compress_symbolic_block_buffers* tmpbuf);
void decompress_symbolic_block(
- const astc_codec_image* image,
- astc_decode_mode decode_mode,
+ astcenc_profile decode_mode,
const block_size_descriptor* bsd,
int xpos,
int ypos,
@@ -1036,47 +912,6 @@ uint16_t lns_to_sf16(
/* ============================================================================
Platform-specific functions
============================================================================ */
-
-/**
- * @brief Get the current time.
- *
- * @returns The current time in seconds since arbitrary epoch.
- */
-double get_time();
-
-/**
- * @brief Get the number of CPU cores.
- *
- * @returns The number of online or onlineable CPU cores in the system.
- */
-int get_cpu_count();
-
-/**
- * @brief Delete (unlink) a file on the filesystem.
- *
-|* @param filename The file to delete.
- *
- * @returns Zero on success, non-zero otherwise.
- */
-int unlink_file(const char *filename);
-
-/**
- * @brief Launch N worker threads and wait for them to complete.
- *
- * All threads run the same thread function, and have the same thread payload,
- * but are given a unique thread ID (0 .. N-1) as a parameter to the run
- * function to allow thread-specific behavior.
- *
-|* @param thread_count The number of threads to spawn.
- * @param func The function to execute. Must have the signature:
- * void (int thread_count, int thread_id, void* payload)
- * @param payload Pointer to an opaque thread payload object.
- */
-void launch_threads(
- int thread_count,
- void (*func)(int, int, void*),
- void *payload);
-
/**
* @brief Run-time detection if the host CPU supports SSE 4.2.
* @returns Zero if not supported, positive value if it is.
@@ -1096,15 +931,27 @@ int cpu_supports_popcnt();
int cpu_supports_avx2();
/**
- * @brief The main entry point.
+ * @brief Get the number of CPU cores.
*
- * @param argc The number of arguments.
- * @param argb The array of command line arguments.
- *
- * @returns Zero on success, non-zero otherwise.
+ * @returns The number of online or onlineable CPU cores in the system.
*/
-int astc_main(
- int argc,
- char** argv);
+int get_cpu_count();
+
+/**
+ * @brief Launch N worker threads and wait for them to complete.
+ *
+ * All threads run the same thread function, and have the same thread payload,
+ * but are given a unique thread ID (0 .. N-1) as a parameter to the run
+ * function to allow thread-specific behavior.
+ *
+|* @param thread_count The number of threads to spawn.
+ * @param func The function to execute. Must have the signature:
+ * void (int thread_count, int thread_id, void* payload)
+ * @param payload Pointer to an opaque thread payload object.
+ */
+void launch_threads(
+ int thread_count,
+ void (*func)(int, int, void*),
+ void *payload);
#endif
diff --git a/Source/astc_kmeans_partitioning.cpp b/Source/astcenc_kmeans_partitioning.cpp
similarity index 99%
rename from Source/astc_kmeans_partitioning.cpp
rename to Source/astcenc_kmeans_partitioning.cpp
index 3831f0a..49046d5 100644
--- a/Source/astc_kmeans_partitioning.cpp
+++ b/Source/astcenc_kmeans_partitioning.cpp
@@ -27,7 +27,7 @@
* how well the bitmaps matched.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
// for k++ means, we need pseudo-random numbers, however using random numbers
// directly results in unreproducible encoding results. As such, we will
diff --git a/Source/astc_mathlib.cpp b/Source/astcenc_mathlib.cpp
similarity index 99%
rename from Source/astc_mathlib.cpp
rename to Source/astcenc_mathlib.cpp
index 082c5c8..dce0237 100644
--- a/Source/astc_mathlib.cpp
+++ b/Source/astcenc_mathlib.cpp
@@ -15,7 +15,7 @@
// under the License.
// ----------------------------------------------------------------------------
-#include "astc_mathlib.h"
+#include "astcenc_mathlib.h"
float3 cross(float3 p, float3 q)
{
diff --git a/Source/astc_mathlib.h b/Source/astcenc_mathlib.h
similarity index 97%
rename from Source/astc_mathlib.h
rename to Source/astcenc_mathlib.h
index b849e22..4f85674 100644
--- a/Source/astc_mathlib.h
+++ b/Source/astcenc_mathlib.h
@@ -26,7 +26,7 @@
#include
#include
-#if ASTC_SSE != 0 || ASTC_AVX != 0
+#if ASTCENC_SSE != 0 || ASTCENC_AVX != 0
#include
#endif
@@ -100,7 +100,7 @@ float atan2(float y, float x);
*/
static inline float fabs(float val)
{
-#if (ASTC_SSE >= 20) && USE_SCALAR_SSE
+#if (ASTCENC_SSE >= 20) && USE_SCALAR_SSE
static const union {
uint32_t u[4];
__m128 v;
@@ -125,7 +125,7 @@ static inline float fabs(float val)
*/
static inline float fmin(float p, float q)
{
-#if (ASTC_SSE >= 20) && USE_SCALAR_SSE
+#if (ASTCENC_SSE >= 20) && USE_SCALAR_SSE
return _mm_cvtss_f32(_mm_min_ss(_mm_set_ss(p),_mm_set_ss(q)));
#else
return p < q ? p : q;
@@ -146,7 +146,7 @@ static inline float fmin(float p, float q)
*/
static inline float fmax(float p, float q)
{
-#if (ASTC_SSE >= 20) && USE_SCALAR_SSE
+#if (ASTCENC_SSE >= 20) && USE_SCALAR_SSE
return _mm_cvtss_f32(_mm_max_ss(_mm_set_ss(p),_mm_set_ss(q)));
#else
return q < p ? p : q;
@@ -258,7 +258,7 @@ static inline float srgb_transform(float val)
*/
static inline float flt_rte(float val)
{
-#if (ASTC_SSE >= 42)
+#if (ASTCENC_SSE >= 42)
const int flag = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC;
__m128 tmp = _mm_set_ss(val);
tmp = _mm_round_ss(tmp, tmp, flag);
@@ -277,7 +277,7 @@ static inline float flt_rte(float val)
*/
static inline float flt_rd(float val)
{
-#if (ASTC_SSE >= 42)
+#if (ASTCENC_SSE >= 42)
const int flag = _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC;
__m128 tmp = _mm_set_ss(val);
tmp = _mm_round_ss(tmp, tmp, flag);
@@ -296,7 +296,7 @@ static inline float flt_rd(float val)
*/
static inline int flt2int_rtn(float val)
{
-#if (ASTC_SSE >= 42) && USE_SCALAR_SSE
+#if (ASTCENC_SSE >= 42) && USE_SCALAR_SSE
return _mm_cvt_ss2si(_mm_set_ss(val));
#else
return (int)(val + 0.5f);
@@ -312,7 +312,7 @@ static inline int flt2int_rtn(float val)
*/
static inline int flt2int_rd(float val)
{
-#if (ASTC_SSE >= 42) && USE_SCALAR_SSE
+#if (ASTCENC_SSE >= 42) && USE_SCALAR_SSE
return _mm_cvt_ss2si(_mm_set_ss(val));
#else
return (int)(val);
@@ -328,7 +328,7 @@ static inline int flt2int_rd(float val)
*/
static inline int popcount(uint64_t p)
{
-#if ASTC_POPCNT >= 1
+#if ASTCENC_POPCNT >= 1
return (int)_mm_popcnt_u64(p);
#else
uint64_t mask1 = 0x5555555555555555ULL;
@@ -353,7 +353,7 @@ static inline int popcount(uint64_t p)
*/
static inline float rsqrt(float val)
{
-#if (ASTC_SSE >= 20) && USE_SCALAR_SSE
+#if (ASTCENC_SSE >= 20) && USE_SCALAR_SSE
// FIXME: setting val = 99 causes a crash, which it really shouldn't.
return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ss(val)));
#else
@@ -370,7 +370,7 @@ static inline float rsqrt(float val)
*/
static inline float sqrt(float val)
{
-#if (ASTC_SSE >= 20) && USE_SCALAR_SSE
+#if (ASTCENC_SSE >= 20) && USE_SCALAR_SSE
return 1.0f * astc::rsqrt(val);
#else
return std::sqrt(val);
@@ -386,7 +386,7 @@ static inline float sqrt(float val)
*/
static inline float recip(float val)
{
-#if (ASTC_SSE >= 20) && USE_SCALAR_SSE
+#if (ASTCENC_SSE >= 20) && USE_SCALAR_SSE
return _mm_cvtss_f32(_mm_rcp_ss(_mm_set_ss(val)));
#else
return 1.0f / val;
diff --git a/Source/astc_mathlib_softfloat.cpp b/Source/astcenc_mathlib_softfloat.cpp
similarity index 99%
rename from Source/astc_mathlib_softfloat.cpp
rename to Source/astcenc_mathlib_softfloat.cpp
index 50bad0a..98ebac7 100644
--- a/Source/astc_mathlib_softfloat.cpp
+++ b/Source/astcenc_mathlib_softfloat.cpp
@@ -19,7 +19,7 @@
* @brief Soft-float library for IEEE-754.
*/
-#include "astc_mathlib.h"
+#include "astcenc_mathlib.h"
/******************************************
helper functions and their lookup tables
@@ -226,7 +226,7 @@ sf16 sf32_to_sf16(sf32 inp, roundmode rmode)
switch (idx)
{
/*
- Positive number which may be Infinity or NaN.
+ Positive number which may be Infinity or NaN.
We need to check whether it is NaN; if it is, quieten it by setting the top bit of the mantissa.
(If we don't do this quieting, then a NaN that is distinguished only by having
its low-order bits set, would be turned into an INF. */
diff --git a/Source/astc_partition_tables.cpp b/Source/astcenc_partition_tables.cpp
similarity index 99%
rename from Source/astc_partition_tables.cpp
rename to Source/astcenc_partition_tables.cpp
index 618c777..028a3b2 100644
--- a/Source/astc_partition_tables.cpp
+++ b/Source/astcenc_partition_tables.cpp
@@ -19,7 +19,7 @@
* @brief Functions for generating partition tables on demand.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
/*
Produce a canonicalized representation of a partition pattern
diff --git a/Source/astc_percentile_tables.cpp b/Source/astcenc_percentile_tables.cpp
similarity index 99%
rename from Source/astc_percentile_tables.cpp
rename to Source/astcenc_percentile_tables.cpp
index 9dbb7d5..fc41c41 100644
--- a/Source/astc_percentile_tables.cpp
+++ b/Source/astcenc_percentile_tables.cpp
@@ -22,7 +22,7 @@
* encoding
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
/**
* @brief Structure containing packed percentile metadata.
diff --git a/Source/astc_pick_best_endpoint_format.cpp b/Source/astcenc_pick_best_endpoint_format.cpp
similarity index 93%
rename from Source/astc_pick_best_endpoint_format.cpp
rename to Source/astcenc_pick_best_endpoint_format.cpp
index 521d652..8040166 100644
--- a/Source/astc_pick_best_endpoint_format.cpp
+++ b/Source/astcenc_pick_best_endpoint_format.cpp
@@ -19,11 +19,7 @@
* @brief Functions to pick best ASTC endpoint for a block.
*/
-#include "astc_codec_internals.h"
-
-#ifdef DEBUG_PRINT_DIAGNOSTICS
- #include
-#endif
+#include "astcenc_internal.h"
/*
functions to determine, for a given partitioning, which color endpoint formats are the best to use.
@@ -73,15 +69,8 @@ static void compute_color_error_for_every_integer_count_and_quantization_level(
float4 ep0 = ep->endpt0[partition_index];
float4 ep1 = ep->endpt1[partition_index];
- float ep0_max = MAX(MAX(ep0.x, ep0.y), ep0.z);
- float ep0_min = MIN(MIN(ep0.x, ep0.y), ep0.z);
- float ep1_max = MAX(MAX(ep1.x, ep1.y), ep1.z);
float ep1_min = MIN(MIN(ep1.x, ep1.y), ep1.z);
-
- ep0_min = MAX(ep0_min, 0.0f);
ep1_min = MAX(ep1_min, 0.0f);
- ep0_max = MAX(ep0_max, 1e-10f);
- ep1_max = MAX(ep1_max, 1e-10f);
float4 error_weight = error_weightings[partition_index];
@@ -117,26 +106,14 @@ static void compute_color_error_for_every_integer_count_and_quantization_level(
ep1_range_error_low.w = MIN(0.0f, ep1.w);
float4 sum_range_error =
- (ep0_range_error_low * ep0_range_error_low) + (ep1_range_error_low * ep1_range_error_low) + (ep0_range_error_high * ep0_range_error_high) + (ep1_range_error_high * ep1_range_error_high);
- float rgb_range_error = dot(float3(sum_range_error.x, sum_range_error.y, sum_range_error.z), float3(error_weight.x, error_weight.y, error_weight.z)) * 0.5f * partition_size;
+ (ep0_range_error_low * ep0_range_error_low) +
+ (ep1_range_error_low * ep1_range_error_low) +
+ (ep0_range_error_high * ep0_range_error_high) +
+ (ep1_range_error_high * ep1_range_error_high);
+ float rgb_range_error = dot(float3(sum_range_error.x, sum_range_error.y, sum_range_error.z),
+ float3(error_weight.x, error_weight.y, error_weight.z)) * 0.5f * partition_size;
float alpha_range_error = sum_range_error.w * error_weight.w * 0.5f * partition_size;
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- printf("%s : partition=%d\nrgb-error_wt=%f alpha_error_wt=%f\n", __func__, partition_index, error_weight_rgbsum, error_weight.w);
-
- printf("ep0 = %f %f %f %f\n", ep0.x, ep0.y, ep0.z, ep0.w);
- printf("ep1 = %f %f %f %f\n", ep1.x, ep1.y, ep1.z, ep1.w);
-
-
- printf("rgb_range_error = %f, alpha_range_error = %f\n", rgb_range_error, alpha_range_error);
-
- printf("rgb-luma-error: %f\n", eci->rgb_luma_error);
- }
- #endif
-
if (encode_hdr_rgb)
{
@@ -253,11 +230,6 @@ static void compute_color_error_for_every_integer_count_and_quantization_level(
float alpha_quantization_error = error_weight.w * base_quant_error * 2.0f;
float rgba_quantization_error = rgb_quantization_error + alpha_quantization_error;
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("rgba-quant = %f can_offset_encode=%d\n", rgba_quantization_error, eci->can_offset_encode);
- #endif
-
// for 8 integers, we have two encodings: one with HDR alpha and another one
// with LDR alpha.
@@ -280,16 +252,6 @@ static void compute_color_error_for_every_integer_count_and_quantization_level(
float hdr_luminance_error = (rgb_quantization_error * mode23mult) + rgb_range_error + eci->alpha_drop_error + eci->luminance_error;
best_error[i][0] = hdr_luminance_error;
format_of_choice[i][0] = FMT_HDR_LUMINANCE_LARGE_RANGE;
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- for (int j = 0; j < 4; j++)
- {
- printf("(hdr) quant-level=%d ints=%d format=%d error=%f\n", i, j, format_of_choice[i][j], best_error[i][j]);
- }
- }
- #endif
}
}
else
@@ -315,11 +277,6 @@ static void compute_color_error_for_every_integer_count_and_quantization_level(
float alpha_quantization_error = error_weight.w * base_quant_error;
float rgba_quantization_error = rgb_quantization_error + alpha_quantization_error;
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- printf("rgba-quant = %f can_offset_encode=%d\n", rgba_quantization_error, eci->can_offset_encode);
- #endif
-
// for 8 integers, the available encodings are:
// full LDR RGB-Alpha
float full_ldr_rgba_error = rgba_quantization_error;
@@ -377,16 +334,6 @@ static void compute_color_error_for_every_integer_count_and_quantization_level(
best_error[i][0] = luminance_error;
format_of_choice[i][0] = FMT_LUMINANCE;
-
- #ifdef DEBUG_PRINT_DIAGNOSTICS
- if (print_diagnostics)
- {
- for (int j = 0; j < 4; j++)
- {
- printf(" (ldr) quant-level=%d ints=%d format=%d error=%f\n", i, j, format_of_choice[i][j], best_error[i][j]);
- }
- }
- #endif
}
}
}
diff --git a/Source/astc_platform_dependents.cpp b/Source/astcenc_platform_dependents.cpp
similarity index 85%
rename from Source/astc_platform_dependents.cpp
rename to Source/astcenc_platform_dependents.cpp
index 9614fdf..19cf189 100644
--- a/Source/astc_platform_dependents.cpp
+++ b/Source/astcenc_platform_dependents.cpp
@@ -30,7 +30,7 @@
* task has also been provided.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
/* ============================================================================
Platform code for Windows using the Win32 APIs.
@@ -64,16 +64,6 @@ static int pthread_join(
return 0;
}
-/* Public function, see header file for detailed documentation */
-double get_time()
-{
- FILETIME tv;
- GetSystemTimeAsFileTime(&tv);
- unsigned long long ticks = tv.dwHighDateTime;
- ticks = (ticks << 32) | tv.dwLowDateTime;
- return ((double)ticks) / 1.0e7;
-}
-
/* Public function, see header file for detailed documentation */
int get_cpu_count()
{
@@ -82,13 +72,6 @@ int get_cpu_count()
return sysinfo.dwNumberOfProcessors;
}
-/* Public function, see header file for detailed documentation */
-int unlink_file(const char *filename)
-{
- BOOL res = DeleteFileA(filename);
- return (res ? 0 : -1);
-}
-
/* ============================================================================
Platform code for an platform using POSIX APIs.
============================================================================ */
@@ -98,26 +81,12 @@ int unlink_file(const char *filename)
#include
#include
-/* Public function, see header file for detailed documentation */
-double get_time()
-{
- timeval tv;
- gettimeofday(&tv, 0);
- return (double)tv.tv_sec + (double)tv.tv_usec * 1.0e-6;
-}
-
/* Public function, see header file for detailed documentation */
int get_cpu_count()
{
return sysconf(_SC_NPROCESSORS_ONLN);
}
-/* Public function, see header file for detailed documentation */
-int unlink_file(const char *filename)
-{
- return unlink(filename);
-}
-
#endif
/**
diff --git a/Source/astc_platform_isa_detection.cpp b/Source/astcenc_platform_isa_detection.cpp
similarity index 98%
rename from Source/astc_platform_isa_detection.cpp
rename to Source/astcenc_platform_isa_detection.cpp
index 4403ac9..09cf8dc 100644
--- a/Source/astc_platform_isa_detection.cpp
+++ b/Source/astcenc_platform_isa_detection.cpp
@@ -21,7 +21,7 @@
* This module contains functions for querying the host extended ISA support.
*/
-#include "astc_codec_internals.h"
+#include "astcenccli_internal.h"
static int g_cpu_has_sse42 = -1;
static int g_cpu_has_avx2 = -1;
@@ -93,4 +93,4 @@ int cpu_supports_avx2()
detect_cpu_isa();
return g_cpu_has_avx2;
-}
\ No newline at end of file
+}
diff --git a/Source/astc_quantization.cpp b/Source/astcenc_quantization.cpp
similarity index 99%
rename from Source/astc_quantization.cpp
rename to Source/astcenc_quantization.cpp
index 36ab2b3..610cf87 100644
--- a/Source/astc_quantization.cpp
+++ b/Source/astcenc_quantization.cpp
@@ -19,7 +19,7 @@
* @brief Functions and data tables for numeric quantization..
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
const uint8_t color_quantization_tables[21][256] = {
{
diff --git a/Source/astc_symbolic_physical.cpp b/Source/astcenc_symbolic_physical.cpp
similarity index 99%
rename from Source/astc_symbolic_physical.cpp
rename to Source/astcenc_symbolic_physical.cpp
index 57bbed5..7b5ea88 100644
--- a/Source/astc_symbolic_physical.cpp
+++ b/Source/astcenc_symbolic_physical.cpp
@@ -19,7 +19,7 @@
* @brief Functions for converting between symbolic and physical encodings.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
// routine to write up to 8 bits
static inline void write_bits(
diff --git a/Source/astc_weight_align.cpp b/Source/astcenc_weight_align.cpp
similarity index 98%
rename from Source/astc_weight_align.cpp
rename to Source/astcenc_weight_align.cpp
index 4edbda7..92b2202 100644
--- a/Source/astc_weight_align.cpp
+++ b/Source/astcenc_weight_align.cpp
@@ -42,7 +42,7 @@
* (perhaps 1/8 for low levels of quantization).
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
#include
#include
@@ -177,7 +177,7 @@ static void compute_lowest_and_highest_weight(
// TODO: Add AVX2 version of this; SSE4.2 vectorizes almost perfectly in terms
// of user-visible speedup. Might need to change the length of max_angular
// steps to be a multiple of 8 though ...
-#if ASTC_SSE >= 42
+#if ASTCENC_SSE >= 42
// Arrays are always multiple of 4, so this is safe even if overshoot max
for (int sp = 0; sp < max_angular_steps; sp += 4)
{
@@ -349,8 +349,8 @@ void compute_angular_endpoints_for_quantization_levels(
uint8_t cut_low_weight[40];
for (i = 0; i < (max_quantization_steps + 4); i++)
{
- best_errors[i] = 1e30f;
best_scale[i] = -1; // Indicates no solution found
+ best_errors[i] = 1e30f;
cut_low_weight[i] = 0;
}
@@ -410,10 +410,12 @@ void compute_angular_endpoints_for_quantization_levels(
int bsi = best_scale[q];
// Did we find anything?
+ // TODO: Can we do better than bsi = 0 here. We should at least
+ // propagate an error (and move the printf into the CLI).
if (bsi < 0)
{
- printf("ERROR: Unable to find an encoding within the specified error limits\n");
- ASTC_CODEC_INTERNAL_ERROR();
+ printf("WARNING: Unable to find encoding within specified error limit\n");
+ bsi = 0;
}
float stepsize = stepsizes[bsi];
diff --git a/Source/astc_weight_quant_xfer_tables.cpp b/Source/astcenc_weight_quant_xfer_tables.cpp
similarity index 99%
rename from Source/astc_weight_quant_xfer_tables.cpp
rename to Source/astcenc_weight_quant_xfer_tables.cpp
index 9a1b6ae..d87bb5c 100644
--- a/Source/astc_weight_quant_xfer_tables.cpp
+++ b/Source/astcenc_weight_quant_xfer_tables.cpp
@@ -19,7 +19,7 @@
* @brief Data tables for quantization transfer.
*/
-#include "astc_codec_internals.h"
+#include "astcenc_internal.h"
#define _ 0 // using _ to indicate an entry that will not be used.
diff --git a/Source/astc_error_metrics.cpp b/Source/astcenccli_error_metrics.cpp
similarity index 85%
rename from Source/astc_error_metrics.cpp
rename to Source/astcenccli_error_metrics.cpp
index 686134a..40d1324 100644
--- a/Source/astc_error_metrics.cpp
+++ b/Source/astcenccli_error_metrics.cpp
@@ -19,10 +19,10 @@
* @brief Functions for computing image error metrics.
*/
-#include "astc_codec_internals.h"
-
#include
+#include "astcenccli_internal.h"
+
/**
* @brief An accumulator using Kahan compensated floating-point summation.
*
@@ -126,8 +126,8 @@ static float mpsnr_sumdiff(
void compute_error_metrics(
int compute_hdr_metrics,
int input_components,
- const astc_codec_image* img1,
- const astc_codec_image* img2,
+ const astcenc_image* img1,
+ const astcenc_image* img2,
int fstop_lo,
int fstop_hi
) {
@@ -139,36 +139,36 @@ void compute_error_metrics(
kahan_accum4 log_errorsum;
kahan_accum4 mpsnr_errorsum;
- int xsize = MIN(img1->xsize, img2->xsize);
- int ysize = MIN(img1->ysize, img2->ysize);
- int zsize = MIN(img1->zsize, img2->zsize);
+ unsigned int dim_x = MIN(img1->dim_x, img2->dim_x);
+ unsigned int dim_y = MIN(img1->dim_y, img2->dim_y);
+ unsigned int dim_z = MIN(img1->dim_z, img2->dim_z);
- if (img1->xsize != img2->xsize ||
- img1->ysize != img2->ysize ||
- img1->zsize != img2->zsize)
+ if (img1->dim_x != img2->dim_x ||
+ img1->dim_y != img2->dim_y ||
+ img1->dim_z != img2->dim_z)
{
- printf("Warning: Only intersection of images will be compared:\n"
+ printf("WARNING: Only intersection of images will be compared:\n"
" Image 1: %dx%dx%d\n"
" Image 2: %dx%dx%d\n",
- img1->xsize, img1->ysize, img1->zsize,
- img2->xsize, img2->ysize, img2->zsize);
+ img1->dim_x, img1->dim_y, img1->dim_z,
+ img2->dim_x, img2->dim_y, img2->dim_z);
}
- int img1pad = img1->padding;
- int img2pad = img2->padding;
+ int img1pad = img1->dim_pad;
+ int img2pad = img2->dim_pad;
float rgb_peak = 0.0f;
- for (int z = 0; z < zsize; z++)
+ for (unsigned int z = 0; z < dim_z; z++)
{
- for (int y = 0; y < ysize; y++)
+ for (unsigned int y = 0; y < dim_y; y++)
{
- int ze1 = (img1->zsize == 1) ? z : z + img1pad;
- int ze2 = (img2->zsize == 1) ? z : z + img2pad;
+ int ze1 = (img1->dim_z == 1) ? z : z + img1pad;
+ int ze2 = (img2->dim_z == 1) ? z : z + img2pad;
int ye1 = y + img1pad;
int ye2 = y + img2pad;
- for (int x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
float4 color1;
float4 color2;
@@ -255,7 +255,7 @@ void compute_error_metrics(
}
}
- float pixels = (float)(xsize * ysize * zsize);
+ float pixels = (float)(dim_x * dim_y * dim_z);
float num = 0.0f;
float alpha_num = 0.0f;
float log_num = 0.0f;
@@ -309,34 +309,34 @@ void compute_error_metrics(
float rgb_psnr = psnr;
printf("Error metrics\n");
- printf("-------------\n");
+ printf("=============\n\n");
if (channelmask & 8)
{
- printf("PSNR (LDR-RGBA): %9.6f dB\n", (double)psnr);
+ printf(" PSNR (LDR-RGBA): %9.6f dB\n", (double)psnr);
float alpha_psnr;
if (alpha_num == 0.0f)
alpha_psnr = 999.0f;
else
alpha_psnr = 10.0f * log10f(denom / alpha_num);
- printf("Alpha-weighted PSNR: %9.6f dB\n", (double)alpha_psnr);
+ printf(" Alpha-weighted PSNR: %9.6f dB\n", (double)alpha_psnr);
float rgb_num = errorsum.sum.x + errorsum.sum.y + errorsum.sum.z;
if (rgb_num == 0.0f)
rgb_psnr = 999.0f;
else
rgb_psnr = 10.0f * log10f(pixels * 3.0f / rgb_num);
- printf("PSNR (LDR-RGB): %9.6f dB\n", (double)rgb_psnr);
+ printf(" PSNR (LDR-RGB): %9.6f dB\n", (double)rgb_psnr);
}
else
{
- printf("PSNR (LDR-RGB): %9.6f dB\n", (double)psnr);
+ printf(" PSNR (LDR-RGB): %9.6f dB\n", (double)psnr);
}
if (compute_hdr_metrics)
{
- printf("PSNR (RGB norm to peak): %9.6f dB (peak %f)\n",
+ printf(" PSNR (RGB norm to peak): %9.6f dB (peak %f)\n",
(double)(rgb_psnr + 20.0f * log10f(rgb_peak)),
(double)rgb_peak);
@@ -345,10 +345,12 @@ void compute_error_metrics(
mpsnr = 999.0f;
else
mpsnr = 10.0f * log10f(mpsnr_denom / mpsnr_num);
- printf("mPSNR (RGB): %9.6f dB (fstops %+d to %+d)\n",
+ printf(" mPSNR (RGB): %9.6f dB (fstops %+d to %+d)\n",
(double)mpsnr, fstop_lo, fstop_hi);
float logrmse = astc::sqrt(log_num / pixels);
- printf("LogRMSE (RGB): %9.6f\n", (double)logrmse);
+ printf(" LogRMSE (RGB): %9.6f\n", (double)logrmse);
}
+
+ printf("\n");
}
diff --git a/Source/astcenccli_image.cpp b/Source/astcenccli_image.cpp
new file mode 100644
index 0000000..1cacbbf
--- /dev/null
+++ b/Source/astcenccli_image.cpp
@@ -0,0 +1,401 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2020 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions for creating in-memory ASTC image structures.
+ */
+
+#include
+#include
+
+#include "astcenccli_internal.h"
+
+astcenc_image *alloc_image(
+ unsigned int bitness,
+ unsigned int dim_x,
+ unsigned int dim_y,
+ unsigned int dim_z,
+ unsigned int dim_pad
+) {
+ astcenc_image *img = new astcenc_image;
+ img->dim_x = dim_x;
+ img->dim_y = dim_y;
+ img->dim_z = dim_z;
+ img->dim_pad = dim_pad;
+
+ unsigned int dim_ex = dim_x + 2 * dim_pad;
+ unsigned int dim_ey = dim_y + 2 * dim_pad;
+ unsigned int dim_ez = (dim_z == 1) ? 1 : dim_z + 2 * dim_pad;
+
+ assert(bitness == 8 || bitness == 16);
+ if (bitness == 8)
+ {
+ img->data8 = new uint8_t **[dim_ez];
+ img->data8[0] = new uint8_t *[dim_ez * dim_ey];
+ img->data8[0][0] = new uint8_t[4 * dim_ez * dim_ey * dim_ex];
+ memset(img->data8[0][0], 0, 4 * dim_ez * dim_ey * dim_ex);
+
+ for (unsigned int z = 1; z < dim_ez; z++)
+ {
+ img->data8[z] = img->data8[0] + z * dim_ey;
+ img->data8[z][0] = img->data8[0][0] + 4 * z * dim_ex * dim_ey;
+ }
+
+ for (unsigned int z = 0; z < dim_ez; z++)
+ {
+ for (unsigned int y = 1; y < dim_ey; y++)
+ {
+ img->data8[z][y] = img->data8[z][0] + 4 * y * dim_ex;
+ }
+ }
+
+ img->data16 = nullptr;
+ }
+ else if (bitness == 16)
+ {
+ img->data16 = new uint16_t **[dim_ez];
+ img->data16[0] = new uint16_t *[dim_ez * dim_ey];
+ img->data16[0][0] = new uint16_t[4 * dim_ez * dim_ey * dim_ex];
+ memset(img->data16[0][0], 0, 8 * dim_ez * dim_ey * dim_ex);
+
+ for (unsigned int z = 1; z < dim_ez; z++)
+ {
+ img->data16[z] = img->data16[0] + z * dim_ey;
+ img->data16[z][0] = img->data16[0][0] + 4 * z * dim_ex * dim_ey;
+ }
+
+ for (unsigned int z = 0; z < dim_ez; z++)
+ {
+ for (unsigned int y = 1; y < dim_ey; y++)
+ {
+ img->data16[z][y] = img->data16[z][0] + 4 * y * dim_ex;
+ }
+ }
+
+ img->data8 = nullptr;
+ }
+
+ return img;
+}
+
+void free_image(astcenc_image * img)
+{
+ if (img == nullptr)
+ {
+ return;
+ }
+
+ if (img->data8)
+ {
+ delete[] img->data8[0][0];
+ delete[] img->data8[0];
+ delete[] img->data8;
+ }
+
+ if (img->data16)
+ {
+ delete[] img->data16[0][0];
+ delete[] img->data16[0];
+ delete[] img->data16;
+ }
+
+ delete img;
+}
+
+
+// fill the padding area of the input-file buffer with clamp-to-edge data
+// Done inefficiently, in that it will overwrite all the interior data at least once;
+// this is not considered a problem, since this makes up a very small part of total
+// running time.
+void fill_image_padding_area(astcenc_image * img)
+{
+ if (img->dim_pad == 0)
+ {
+ return;
+ }
+
+ unsigned int dim_ex = img->dim_x + 2 * img->dim_pad;
+ unsigned int dim_ey = img->dim_y + 2 * img->dim_pad;
+ unsigned int dim_ez = (img->dim_z == 1) ? 1 : (img->dim_z + 2 * img->dim_pad);
+
+ unsigned int xmin = img->dim_pad;
+ unsigned int ymin = img->dim_pad;
+ unsigned int zmin = (img->dim_z == 1) ? 0 : img->dim_pad;
+ unsigned int xmax = img->dim_x + img->dim_pad - 1;
+ unsigned int ymax = img->dim_y + img->dim_pad - 1;
+ unsigned int zmax = (img->dim_z == 1) ? 0 : img->dim_z + img->dim_pad - 1;
+
+ // This is a very simple implementation. Possible optimizations include:
+ // * Testing if texel is outside the edge.
+ // * Looping over texels that we know are outside the edge.
+ if (img->data8)
+ {
+ for (unsigned int z = 0; z < dim_ez; z++)
+ {
+ int zc = MIN(MAX(z, zmin), zmax);
+ for (unsigned int y = 0; y < dim_ey; y++)
+ {
+ int yc = MIN(MAX(y, ymin), ymax);
+ for (unsigned int x = 0; x < dim_ex; x++)
+ {
+ int xc = MIN(MAX(x, xmin), xmax);
+ for (unsigned int i = 0; i < 4; i++)
+ {
+ img->data8[z][y][4 * x + i] = img->data8[zc][yc][4 * xc + i];
+ }
+ }
+ }
+ }
+ }
+ else if (img->data16)
+ {
+ for (unsigned int z = 0; z < dim_ez; z++)
+ {
+ int zc = MIN(MAX(z, zmin), zmax);
+ for (unsigned int y = 0; y < dim_ey; y++)
+ {
+ int yc = MIN(MAX(y, ymin), ymax);
+ for (unsigned int x = 0; x < dim_ex; x++)
+ {
+ int xc = MIN(MAX(x, xmin), xmax);
+ for (unsigned int i = 0; i < 4; i++)
+ {
+ img->data16[z][y][4 * x + i] = img->data16[zc][yc][4 * xc + i];
+ }
+ }
+ }
+ }
+ }
+}
+
+int determine_image_channels(const astcenc_image * img)
+{
+ unsigned int dim_x = img->dim_x;
+ unsigned int dim_y = img->dim_y;
+ unsigned int dim_z = img->dim_z;
+
+ // scan through the image data
+ // to determine how many color channels the image has.
+
+ int lum_mask;
+ int alpha_mask;
+ int alpha_mask_ref;
+ if (img->data8)
+ {
+ alpha_mask_ref = 0xFF;
+ alpha_mask = 0xFF;
+ lum_mask = 0;
+ for (unsigned int z = 0; z < dim_z; z++)
+ {
+ for (unsigned int y = 0; y < dim_y; y++)
+ {
+ for (unsigned int x = 0; x < dim_x; x++)
+ {
+ int r = img->data8[z][y][4 * x];
+ int g = img->data8[z][y][4 * x + 1];
+ int b = img->data8[z][y][4 * x + 2];
+ int a = img->data8[z][y][4 * x + 3];
+ lum_mask |= (r ^ g) | (r ^ b);
+ alpha_mask &= a;
+ }
+ }
+ }
+ }
+ else // (bitness == 16)
+ {
+ alpha_mask_ref = 0xFFFF;
+ alpha_mask = 0xFFFF;
+ lum_mask = 0;
+ for (unsigned int z = 0; z < dim_z; z++)
+ {
+ for (unsigned int y = 0; y < dim_y; y++)
+ {
+ for (unsigned int x = 0; x < dim_x; x++)
+ {
+ int r = img->data16[z][y][4 * x];
+ int g = img->data16[z][y][4 * x + 1];
+ int b = img->data16[z][y][4 * x + 2];
+ int a = img->data16[z][y][4 * x + 3];
+ lum_mask |= (r ^ g) | (r ^ b);
+ alpha_mask &= (a ^ 0xC3FF); // a ^ 0xC3FF returns FFFF if and only if the input is 1.0
+ }
+ }
+ }
+ }
+
+ int image_channels = 1 + (lum_mask == 0 ? 0 : 2) + (alpha_mask == alpha_mask_ref ? 0 : 1);
+
+ return image_channels;
+}
+
+// initialize an astcenc_image data structure from a 2D array of RGBA float*4
+astcenc_image* astc_img_from_floatx4_array(
+ const float* data,
+ unsigned int dim_x,
+ unsigned int dim_y,
+ unsigned int dim_pad,
+ bool y_flip
+) {
+ astcenc_image* img = alloc_image(16, dim_x, dim_y, 1, dim_pad);
+
+ for (unsigned int y = 0; y < dim_y; y++)
+ {
+ unsigned int y_dst = y + dim_pad;
+ unsigned int y_src = y_flip ? (dim_y - y - 1) : y;
+ const float* src = data + 4 * dim_y * y_src;
+
+ for (unsigned int x = 0; x < dim_x; x++)
+ {
+ unsigned int x_dst = x + dim_pad;
+ img->data16[0][y_dst][4 * x_dst] = float_to_sf16(src[4 * x], SF_NEARESTEVEN);
+ img->data16[0][y_dst][4 * x_dst + 1] = float_to_sf16(src[4 * x + 1], SF_NEARESTEVEN);
+ img->data16[0][y_dst][4 * x_dst + 2] = float_to_sf16(src[4 * x + 2], SF_NEARESTEVEN);
+ img->data16[0][y_dst][4 * x_dst + 3] = float_to_sf16(src[4 * x + 3], SF_NEARESTEVEN);
+ }
+ }
+
+ fill_image_padding_area(img);
+ return img;
+}
+
+// initialize an astcenc_image data structure from a 2D array of UNORM8
+astcenc_image* astc_img_from_unorm8x4_array(
+ const uint8_t* data,
+ unsigned int dim_x,
+ unsigned int dim_y,
+ unsigned int dim_pad,
+ bool y_flip
+) {
+ astcenc_image* img = alloc_image(8, dim_x, dim_y, 1, dim_pad);
+
+ for (unsigned int y = 0; y < dim_y; y++)
+ {
+ unsigned int y_dst = y + dim_pad;
+ unsigned int y_src = y_flip ? (dim_y - y - 1) : y;
+ const uint8_t* src = data + 4 * dim_x * y_src;
+
+ for (unsigned int x = 0; x < dim_x; x++)
+ {
+ unsigned int x_dst = x + dim_pad;
+ img->data8[0][y_dst][4 * x_dst] = src[4 * x];
+ img->data8[0][y_dst][4 * x_dst + 1] = src[4 * x + 1];
+ img->data8[0][y_dst][4 * x_dst + 2] = src[4 * x + 2];
+ img->data8[0][y_dst][4 * x_dst + 3] = src[4 * x + 3];
+ }
+ }
+
+ fill_image_padding_area(img);
+ return img;
+}
+
+// initialize a flattened array of float4 values from an ASTC codec image
+// The returned array is allocated with new[] and must be deleted with delete[].
+float* floatx4_array_from_astc_img(
+ const astcenc_image* img,
+ bool y_flip
+) {
+ unsigned int dim_x = img->dim_x;
+ unsigned int dim_y = img->dim_y;
+ unsigned int dim_pad = img->dim_pad;
+ float *buf = new float[4 * dim_x * dim_y];
+
+ if (img->data8)
+ {
+ for (unsigned int y = 0; y < dim_y; y++)
+ {
+ unsigned int ymod = y_flip ? dim_y - y - 1 : y;
+ const uint8_t* src = img->data8[0][ymod + dim_pad] + (4 * dim_pad);
+ float* dst = buf + y * dim_x * 4;
+
+ for (unsigned int x = 0; x < dim_x; x++)
+ {
+ dst[4 * x] = src[4 * x] * (1.0f / 255.0f);
+ dst[4 * x + 1] = src[4 * x + 1] * (1.0f / 255.0f);
+ dst[4 * x + 2] = src[4 * x + 2] * (1.0f / 255.0f);
+ dst[4 * x + 3] = src[4 * x + 3] * (1.0f / 255.0f);
+ }
+ }
+ }
+ else
+ {
+ for (unsigned int y = 0; y < dim_y; y++)
+ {
+ unsigned int ymod = y_flip ? dim_y - y - 1 : y;
+ const uint16_t *src = img->data16[0][ymod + dim_pad] + (4 * dim_pad);
+ float *dst = buf + y * dim_x * 4;
+
+ for (unsigned int x = 0; x < dim_x; x++)
+ {
+ dst[4 * x] = sf16_to_float(src[4 * x]);
+ dst[4 * x + 1] = sf16_to_float(src[4 * x + 1]);
+ dst[4 * x + 2] = sf16_to_float(src[4 * x + 2]);
+ dst[4 * x + 3] = sf16_to_float(src[4 * x + 3]);
+ }
+ }
+ }
+
+ return buf;
+}
+
+// initialize a flattened array of unorm8x4 values from an ASTC codec image
+// The returned array is allocated with new[] and must be deleted with delete[].
+uint8_t* unorm8x4_array_from_astc_img(
+ const astcenc_image* img,
+ bool y_flip
+) {
+ unsigned int dim_x = img->dim_x;
+ unsigned int dim_y = img->dim_y;
+ unsigned int dim_pad = img->dim_pad;
+ uint8_t* buf = new uint8_t[4 * dim_x * dim_y];
+
+ if (img->data8)
+ {
+ for (unsigned int y = 0; y < dim_y; y++)
+ {
+ unsigned int ymod = y_flip ? dim_y - y - 1 : y;
+ const uint8_t* src = img->data8[0][ymod + dim_pad] + (4 * dim_pad);
+ uint8_t* dst = buf + y * dim_x * 4;
+
+ for (unsigned int x = 0; x < dim_x; x++)
+ {
+ dst[4 * x] = src[4 * x];
+ dst[4 * x + 1] = src[4 * x + 1];
+ dst[4 * x + 2] = src[4 * x + 2];
+ dst[4 * x + 3] = src[4 * x + 3];
+ }
+ }
+ }
+ else
+ {
+ for (unsigned int y = 0; y < dim_y; y++)
+ {
+ unsigned int ymod = y_flip ? dim_y - y - 1 : y;
+ const uint16_t* src = img->data16[0][ymod + dim_pad] + (4 * dim_pad);
+ uint8_t* dst = buf + y * dim_x * 4;
+
+ for (unsigned int x = 0; x < dim_x; x++)
+ {
+ dst[4 * x] = (uint8_t)astc::flt2int_rtn(astc::clamp1f(sf16_to_float(src[4*x])) * 255.0f);
+ dst[4 * x + 1] = (uint8_t)astc::flt2int_rtn(astc::clamp1f(sf16_to_float(src[4*x+1])) * 255.0f);
+ dst[4 * x + 2] = (uint8_t)astc::flt2int_rtn(astc::clamp1f(sf16_to_float(src[4*x+2])) * 255.0f);
+ dst[4 * x + 3] = (uint8_t)astc::flt2int_rtn(astc::clamp1f(sf16_to_float(src[4*x+3])) * 255.0f);
+ }
+ }
+ }
+
+ return buf;
+}
diff --git a/Source/astc_image_load_store.cpp b/Source/astcenccli_image_load_store.cpp
similarity index 77%
rename from Source/astc_image_load_store.cpp
rename to Source/astcenccli_image_load_store.cpp
index daada85..f706376 100644
--- a/Source/astc_image_load_store.cpp
+++ b/Source/astcenccli_image_load_store.cpp
@@ -19,12 +19,12 @@
* @brief Functions for loading/storing ASTC compressed images.
*/
-
-#include "astc_codec_internals.h"
-
#include
#include
#include
+#include
+
+#include "astcenccli_internal.h"
// on windows/msvc, compile stb and tinyexr together with this file;
// on other systems, use makefile to compile them separately.
@@ -49,115 +49,112 @@
Image load and store through the stb_iamge and tinyexr libraries
*******************************************************************/
-static astc_codec_image* load_image_with_tinyexr(
+static astcenc_image* load_image_with_tinyexr(
const char* filename,
- int padding,
- int y_flip,
- int* result
+ unsigned int dim_pad,
+ bool y_flip,
+ bool& is_hdr,
+ unsigned int& num_components
) {
- int xsize;
- int ysize;
+ int dim_x, dim_y;
float* image;
const char* err;
- int load_res = LoadEXR(&image, &xsize, &ysize, filename, &err);
+
+ int load_res = LoadEXR(&image, &dim_x, &dim_y, filename, &err);
if (load_res != TINYEXR_SUCCESS)
{
printf("ERROR: Failed to load image %s (%s)\n", filename, err);
free((void*)err);
- *result = -1;
return nullptr;
}
- astc_codec_image* res_img = astc_img_from_floatx4_array(
- image, xsize, ysize, padding, y_flip);
-
+ astcenc_image* res_img = astc_img_from_floatx4_array(image, dim_x, dim_y, dim_pad, y_flip);
free(image);
- *result = 0x84; // 4 components of 16-bit data.
+ is_hdr = true;
+ num_components = 4;
return res_img;
}
-static astc_codec_image* load_image_with_stb(
+static astcenc_image* load_image_with_stb(
const char* filename,
- int padding,
- int y_flip,
- int* result
+ unsigned int dim_pad,
+ bool y_flip,
+ bool& is_hdr,
+ unsigned int& num_components
) {
- int xsize, ysize;
- int components;
-
- astc_codec_image* astc_img = nullptr;
+ int dim_x, dim_y;
if (stbi_is_hdr(filename))
{
- float* image = stbi_loadf(filename, &xsize, &ysize, &components, STBI_rgb_alpha);
- if (image)
+ float* data = stbi_loadf(filename, &dim_x, &dim_y, nullptr, STBI_rgb_alpha);
+ if (data)
{
- astc_img = astc_img_from_floatx4_array(image, xsize, ysize, padding, y_flip);
- stbi_image_free(image);
- *result = components + 0x80;
- return astc_img;
+ astcenc_image* img = astc_img_from_floatx4_array(data, dim_x, dim_y, dim_pad, y_flip);
+ stbi_image_free(data);
+ is_hdr = true;
+ num_components = 4;
+ return img;
}
}
else
{
- stbi_uc* image = stbi_load(filename, &xsize, &ysize, &components, STBI_rgb_alpha);
- uint8_t* imageptr = (uint8_t*)image;
- if (image)
+ uint8_t* data = stbi_load(filename, &dim_x, &dim_y, nullptr, STBI_rgb_alpha);
+ if (data)
{
- astc_img = astc_img_from_unorm8x4_array(imageptr, xsize, ysize, padding, y_flip);
- stbi_image_free(image);
- *result = components;
- return astc_img;
+ astcenc_image* img = astc_img_from_unorm8x4_array(data, dim_x, dim_y, dim_pad, y_flip);
+ stbi_image_free(data);
+ is_hdr = false;
+ num_components = 4;
+ return img;
}
}
printf("ERROR: Failed to load image %s (%s)\n", filename, stbi_failure_reason());
- *result = -1;
return nullptr;
}
static int store_exr_image_with_tinyexr(
- const astc_codec_image* img,
+ const astcenc_image* img,
const char* filename,
int y_flip
) {
float *buf = floatx4_array_from_astc_img(img, y_flip);
- int res = SaveEXR(buf, img->xsize, img->ysize, 4, 1, filename, nullptr);
- free(buf);
+ int res = SaveEXR(buf, img->dim_x, img->dim_y, 4, 1, filename, nullptr);
+ delete[] buf;
return (res == 0) ? 4 : res;
}
static int store_png_image_with_stb(
- const astc_codec_image* img,
+ const astcenc_image* img,
const char* filename,
int y_flip
) {
uint8_t* buf = unorm8x4_array_from_astc_img(img, y_flip);
- int res = stbi_write_png(filename, img->xsize, img->ysize, 4, buf, img->xsize * 4);
- free(buf);
+ int res = stbi_write_png(filename, img->dim_x, img->dim_y, 4, buf, img->dim_x * 4);
+ delete[] buf;
return (res == 0) ? -1 : 4;
}
static int store_tga_image_with_stb(
- const astc_codec_image* img,
+ const astcenc_image* img,
const char* filename,
int y_flip
) {
uint8_t* buf = unorm8x4_array_from_astc_img(img, y_flip);
- int res = stbi_write_tga(filename, img->xsize, img->ysize, 4, buf);
- free(buf);
+ int res = stbi_write_tga(filename, img->dim_x, img->dim_y, 4, buf);
+ delete[] buf;
return (res == 0) ? -1 : 4;
}
static int store_bmp_image_with_stb(
- const astc_codec_image* img,
+ const astcenc_image* img,
const char* filename,
int y_flip
) {
uint8_t* buf = unorm8x4_array_from_astc_img(img, y_flip);
- int res = stbi_write_bmp(filename, img->xsize, img->ysize, 4, buf);
- free(buf);
+ int res = stbi_write_bmp(filename, img->dim_x, img->dim_y, 4, buf);
+ delete[] buf;
return (res == 0) ? -1 : 4;
}
@@ -585,19 +582,17 @@ static void ktx_header_switch_endianness(ktx_header * kt)
#undef REV
}
-static astc_codec_image* load_ktx_uncompressed_image(
+static astcenc_image* load_ktx_uncompressed_image(
const char* filename,
- int padding,
- int y_flip,
- int* result
+ unsigned int dim_pad,
+ bool y_flip,
+ bool& is_hdr,
+ unsigned int& num_components
) {
- int y, z;
-
FILE *f = fopen(filename, "rb");
if (!f)
{
printf("Failed to open file %s\n", filename);
- *result = -1;
return nullptr;
}
@@ -608,7 +603,6 @@ static astc_codec_image* load_ktx_uncompressed_image(
{
printf("Failed to read header of KTX file %s\n", filename);
fclose(f);
- *result = -2;
return nullptr;
}
@@ -616,7 +610,6 @@ static astc_codec_image* load_ktx_uncompressed_image(
{
printf("File %s does not have a valid KTX header\n", filename);
fclose(f);
- *result = -3;
return nullptr;
}
@@ -631,7 +624,6 @@ static astc_codec_image* load_ktx_uncompressed_image(
{
printf("File %s appears to be compressed, not supported as input\n", filename);
fclose(f);
- *result = -4;
return nullptr;
}
@@ -669,7 +661,6 @@ static astc_codec_image* load_ktx_uncompressed_image(
default:
printf("KTX file %s has unsupported GL type\n", filename);
fclose(f);
- *result = -5;
return nullptr;
};
@@ -815,28 +806,22 @@ static astc_codec_image* load_ktx_uncompressed_image(
default:
printf("KTX file %s has unsupported GL format\n", filename);
fclose(f);
- *result = -5;
return nullptr;
}
if (hdr.number_of_mipmap_levels > 1)
- printf("warning: KTX file %s has %d mipmap levels; only the first one will be encoded.\n", filename, hdr.number_of_mipmap_levels);
+ printf("WARNING: KTX file %s has %d mipmap levels; only the first one will be encoded.\n", filename, hdr.number_of_mipmap_levels);
if (hdr.number_of_array_elements > 1)
- printf("warning: KTX file %s contains a texture array with %d layers; only the first one will be encoded.\n", filename, hdr.number_of_array_elements);
+ printf("WARNING: KTX file %s contains a texture array with %d layers; only the first one will be encoded.\n", filename, hdr.number_of_array_elements);
if (hdr.number_of_faces > 1)
- printf("warning: KTX file %s contains a cubemap with 6 faces; only the first one will be encoded.\n", filename);
+ printf("WARNING: KTX file %s contains a cubemap with 6 faces; only the first one will be encoded.\n", filename);
- int xsize = hdr.pixel_width;
- int ysize = hdr.pixel_height;
- int zsize = hdr.pixel_depth;
-
- if (ysize == 0)
- ysize = 1;
- if (zsize == 0)
- zsize = 1;
+ unsigned int dim_x = hdr.pixel_width;
+ unsigned int dim_y = MAX(hdr.pixel_height, 1);
+ unsigned int dim_z = MAX(hdr.pixel_depth, 1);
// ignore the key/value data
fseek(f, hdr.bytes_of_key_value_data, SEEK_CUR);
@@ -847,33 +832,32 @@ static astc_codec_image* load_ktx_uncompressed_image(
{
printf("Failed to read header of KTX file %s\n", filename);
fclose(f);
- *result = -2;
return nullptr;
}
if (switch_endianness)
+ {
specified_bytes_of_surface = u32_byterev(specified_bytes_of_surface);
+ }
// read the surface
- uint32_t xstride = bytes_per_component * components * xsize;
- uint32_t ystride = xstride * ysize;
- uint32_t computed_bytes_of_surface = zsize * ystride;
+ uint32_t xstride = bytes_per_component * components * dim_x;
+ uint32_t ystride = xstride * dim_y;
+ uint32_t computed_bytes_of_surface = dim_z * ystride;
if (computed_bytes_of_surface != specified_bytes_of_surface)
{
fclose(f);
printf("%s: KTX file inconsistency: computed surface size is %d bytes, but specified size is %d bytes\n", filename, computed_bytes_of_surface, specified_bytes_of_surface);
- *result = -5;
return nullptr;
}
- uint8_t *buf = (uint8_t *) malloc(specified_bytes_of_surface);
+ uint8_t *buf = new uint8_t[specified_bytes_of_surface];
size_t bytes_read = fread(buf, 1, specified_bytes_of_surface, f);
fclose(f);
if (bytes_read != specified_bytes_of_surface)
{
- free(buf);
+ delete[] buf;
printf("Failed to read file %s\n", filename);
- *result = -6;
return nullptr;
}
@@ -881,49 +865,54 @@ static astc_codec_image* load_ktx_uncompressed_image(
if (switch_endianness)
{
if (hdr.gl_type_size == 2)
- switch_endianness2(buf, specified_bytes_of_surface);
- if (hdr.gl_type_size == 4)
- switch_endianness4(buf, specified_bytes_of_surface);
- }
-
- // then transfer data from the surface to our own image-data-structure.
- astc_codec_image *astc_img = alloc_image(bitness, xsize, ysize, zsize, padding);
-
- for (z = 0; z < zsize; z++)
- {
- int zdst = (zsize == 1) ? z : z + padding;
- for (y = 0; y < ysize; y++)
{
- int ym = y_flip ? ysize - y - 1 : y;
- int ydst = ym + padding;
- void *dst;
- if (bitness == 16)
- dst = (void *)(astc_img->data16[zdst][ydst] + 4 * padding);
- else
- dst = (void *)(astc_img->data8[zdst][ydst] + 4 * padding);
+ switch_endianness2(buf, specified_bytes_of_surface);
+ }
- uint8_t *src = buf + (z * ystride) + (y * xstride);
- copy_scanline(dst, src, xsize, cm);
+ if (hdr.gl_type_size == 4)
+ {
+ switch_endianness4(buf, specified_bytes_of_surface);
}
}
- free(buf);
+ // then transfer data from the surface to our own image-data-structure.
+ astcenc_image *astc_img = alloc_image(bitness, dim_x, dim_y, dim_z, dim_pad);
+
+ for (unsigned int z = 0; z < dim_z; z++)
+ {
+ unsigned int zdst = (dim_z == 1) ? z : z + dim_pad;
+
+ for (unsigned int y = 0; y < dim_y; y++)
+ {
+ unsigned int ymod = y_flip ? dim_y - y - 1 : y;
+ unsigned int ydst = ymod + dim_pad;
+ void *dst;
+
+ if (bitness == 16)
+ dst = (void *)(astc_img->data16[zdst][ydst] + 4 * dim_pad);
+ else
+ dst = (void *)(astc_img->data8[zdst][ydst] + 4 * dim_pad);
+
+ uint8_t *src = buf + (z * ystride) + (y * xstride);
+ copy_scanline(dst, src, dim_x, cm);
+ }
+ }
+
+ delete[] buf;
fill_image_padding_area(astc_img);
- *result = components + (bitness == 16 ? 0x80 : 0);
+ is_hdr = bitness == 16;
+ num_components = components;
return astc_img;
}
static int store_ktx_uncompressed_image(
- const astc_codec_image* img,
+ const astcenc_image* img,
const char* ktx_filename,
int y_flip
) {
- int x, y, z;
- int i, j;
-
- int xsize = img->xsize;
- int ysize = img->ysize;
- int zsize = img->zsize;
+ unsigned int dim_x = img->dim_x;
+ unsigned int dim_y = img->dim_y;
+ unsigned int dim_z = img->dim_z;
int bitness = img->data16 == nullptr ? 8 : 16;
int image_channels = determine_image_channels(img);
@@ -939,9 +928,9 @@ static int store_ktx_uncompressed_image(
hdr.gl_format = gl_format_of_channels[image_channels - 1];
hdr.gl_internal_format = gl_format_of_channels[image_channels - 1];
hdr.gl_base_internal_format = gl_format_of_channels[image_channels - 1];
- hdr.pixel_width = xsize;
- hdr.pixel_height = ysize;
- hdr.pixel_depth = (zsize == 1) ? 0 : zsize;
+ hdr.pixel_width = dim_x;
+ hdr.pixel_height = dim_y;
+ hdr.pixel_depth = (dim_z == 1) ? 0 : dim_z;
hdr.number_of_array_elements = 0;
hdr.number_of_faces = 1;
hdr.number_of_mipmap_levels = 1;
@@ -952,41 +941,46 @@ static int store_ktx_uncompressed_image(
uint16_t ***row_pointers16 = nullptr;
if (bitness == 8)
{
- row_pointers8 = new uint8_t **[zsize];
- row_pointers8[0] = new uint8_t *[ysize * zsize];
- row_pointers8[0][0] = new uint8_t[xsize * ysize * zsize * image_channels + 3];
+ row_pointers8 = new uint8_t **[dim_z];
+ row_pointers8[0] = new uint8_t *[dim_y * dim_z];
+ row_pointers8[0][0] = new uint8_t[dim_x * dim_y * dim_z * image_channels + 3];
- for (i = 1; i < zsize; i++)
+ for (unsigned int z = 1; z < dim_z; z++)
{
- row_pointers8[i] = row_pointers8[0] + ysize * i;
- row_pointers8[i][0] = row_pointers8[0][0] + ysize * xsize * image_channels * i;
+ row_pointers8[z] = row_pointers8[0] + dim_y * z;
+ row_pointers8[z][0] = row_pointers8[0][0] + dim_y * dim_x * image_channels * z;
}
- for (i = 0; i < zsize; i++)
- for (j = 1; j < ysize; j++)
- row_pointers8[i][j] = row_pointers8[i][0] + xsize * image_channels * j;
- for (z = 0; z < zsize; z++)
+ for (unsigned int z = 0; z < dim_z; z++)
{
- for (y = 0; y < ysize; y++)
+ for (unsigned int y = 1; y < dim_y; y++)
{
- int ym = y_flip ? ysize - y - 1 : y;
+ row_pointers8[z][y] = row_pointers8[z][0] + dim_x * image_channels * y;
+ }
+ }
+
+ for (unsigned int z = 0; z < dim_z; z++)
+ {
+ for (unsigned int y = 0; y < dim_y; y++)
+ {
+ int ym = y_flip ? dim_y - y - 1 : y;
switch (image_channels)
{
case 1: // single-component, treated as Luminance
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers8[z][y][x] = img->data8[z][ym][4 * x];
}
break;
case 2: // two-component, treated as Luminance-Alpha
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers8[z][y][2 * x] = img->data8[z][ym][4 * x];
row_pointers8[z][y][2 * x + 1] = img->data8[z][ym][4 * x + 3];
}
break;
case 3: // three-component, treated as RGB
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers8[z][y][3 * x] = img->data8[z][ym][4 * x];
row_pointers8[z][y][3 * x + 1] = img->data8[z][ym][4 * x + 1];
@@ -994,7 +988,7 @@ static int store_ktx_uncompressed_image(
}
break;
case 4: // four-component, treated as RGBA
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers8[z][y][4 * x] = img->data8[z][ym][4 * x];
row_pointers8[z][y][4 * x + 1] = img->data8[z][ym][4 * x + 1];
@@ -1008,41 +1002,46 @@ static int store_ktx_uncompressed_image(
}
else // if bitness == 16
{
- row_pointers16 = new uint16_t **[zsize];
- row_pointers16[0] = new uint16_t *[ysize * zsize];
- row_pointers16[0][0] = new uint16_t[xsize * ysize * zsize * image_channels + 1];
+ row_pointers16 = new uint16_t **[dim_z];
+ row_pointers16[0] = new uint16_t *[dim_y * dim_z];
+ row_pointers16[0][0] = new uint16_t[dim_x * dim_y * dim_z * image_channels + 1];
- for (i = 1; i < zsize; i++)
+ for (unsigned int z = 1; z < dim_z; z++)
{
- row_pointers16[i] = row_pointers16[0] + ysize * i;
- row_pointers16[i][0] = row_pointers16[0][0] + ysize * xsize * image_channels * i;
+ row_pointers16[z] = row_pointers16[0] + dim_y * z;
+ row_pointers16[z][0] = row_pointers16[0][0] + dim_y * dim_x * image_channels * z;
}
- for (i = 0; i < zsize; i++)
- for (j = 1; j < ysize; j++)
- row_pointers16[i][j] = row_pointers16[i][0] + xsize * image_channels * j;
- for (z = 0; z < zsize; z++)
+ for (unsigned int z = 0; z < dim_z; z++)
{
- for (y = 0; y < ysize; y++)
+ for (unsigned int y = 1; y < dim_y; y++)
{
- int ym = y_flip ? ysize - y - 1 : y;
+ row_pointers16[z][y] = row_pointers16[z][0] + dim_x * image_channels * y;
+ }
+ }
+
+ for (unsigned int z = 0; z < dim_z; z++)
+ {
+ for (unsigned int y = 0; y < dim_y; y++)
+ {
+ int ym = y_flip ? dim_y - y - 1 : y;
switch (image_channels)
{
case 1: // single-component, treated as Luminance
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers16[z][y][x] = img->data16[z][ym][4 * x];
}
break;
case 2: // two-component, treated as Luminance-Alpha
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers16[z][y][2 * x] = img->data16[z][ym][4 * x];
row_pointers16[z][y][2 * x + 1] = img->data16[z][ym][4 * x + 3];
}
break;
case 3: // three-component, treated as RGB
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers16[z][y][3 * x] = img->data16[z][ym][4 * x];
row_pointers16[z][y][3 * x + 1] = img->data16[z][ym][4 * x + 1];
@@ -1050,7 +1049,7 @@ static int store_ktx_uncompressed_image(
}
break;
case 4: // four-component, treated as RGBA
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers16[z][y][4 * x] = img->data16[z][ym][4 * x];
row_pointers16[z][y][4 * x + 1] = img->data16[z][ym][4 * x + 1];
@@ -1064,7 +1063,7 @@ static int store_ktx_uncompressed_image(
}
int retval = image_channels + (bitness == 16 ? 0x80 : 0);
- uint32_t image_bytes = xsize * ysize * zsize * image_channels * (bitness / 8);
+ uint32_t image_bytes = dim_x * dim_y * dim_z * image_channels * (bitness / 8);
uint32_t image_write_bytes = (image_bytes + 3) & ~3;
FILE *wf = fopen(ktx_filename, "wb");
@@ -1189,20 +1188,17 @@ struct dds_header_dx10
#define DDS_MAGIC 0x20534444
#define DX10_MAGIC 0x30315844
-astc_codec_image* load_dds_uncompressed_image(
+astcenc_image* load_dds_uncompressed_image(
const char* filename,
- int padding,
- int y_flip,
- int* result
+ unsigned int dim_pad,
+ bool y_flip,
+ bool& is_hdr,
+ unsigned int& num_components
) {
- int i;
- int y, z;
-
FILE *f = fopen(filename, "rb");
if (!f)
{
printf("Failed to open file %s\n", filename);
- *result = -1;
return nullptr;
}
@@ -1215,7 +1211,6 @@ astc_codec_image* load_dds_uncompressed_image(
{
printf("Failed to read header of DDS file %s\n", filename);
fclose(f);
- *result = -2;
return nullptr;
}
@@ -1225,7 +1220,6 @@ astc_codec_image* load_dds_uncompressed_image(
{
printf("File %s does not have a valid DDS header\n", filename);
fclose(f);
- *result = -3;
return nullptr;
}
@@ -1240,7 +1234,6 @@ astc_codec_image* load_dds_uncompressed_image(
{
printf("DDS file %s is compressed, not supported\n", filename);
fclose(f);
- *result = -4;
return nullptr;
}
}
@@ -1253,14 +1246,13 @@ astc_codec_image* load_dds_uncompressed_image(
{
printf("Failed to read header of DDS file %s\n", filename);
fclose(f);
- *result = -2;
return nullptr;
}
}
- int xsize = hdr.width;
- int ysize = hdr.height;
- int zsize = (hdr.flags & 0x800000) ? hdr.depth : 1;
+ unsigned int dim_x = hdr.width;
+ unsigned int dim_y = hdr.height;
+ unsigned int dim_z = (hdr.flags & 0x800000) ? hdr.depth : 1;
int bitness; // the bitcount that we will use internally in the codec
int bytes_per_component; // the bytes per component in the DDS file itself
@@ -1316,7 +1308,7 @@ astc_codec_image* load_dds_uncompressed_image(
int dxgi_modes_supported = sizeof(format_params) / sizeof(format_params[0]);
int did_select_format = 0;
- for (i = 0; i < dxgi_modes_supported; i++)
+ for (int i = 0; i < dxgi_modes_supported; i++)
{
if (dx10_header.dxgi_format == format_params[i].dxgi_format_number)
{
@@ -1329,11 +1321,10 @@ astc_codec_image* load_dds_uncompressed_image(
}
}
- if (did_select_format == 0)
+ if (!did_select_format)
{
printf("DDS file %s: DXGI format not supported by codec\n", filename);
fclose(f);
- *result = -4;
return nullptr;
}
}
@@ -1422,7 +1413,6 @@ astc_codec_image* load_dds_uncompressed_image(
{
printf("DDS file %s: Non-DXGI format not supported by codec\n", filename);
fclose(f);
- *result = -4;
return nullptr;
}
@@ -1430,59 +1420,62 @@ astc_codec_image* load_dds_uncompressed_image(
}
// then, load the actual file.
- uint32_t xstride = bytes_per_component * components * xsize;
- uint32_t ystride = xstride * ysize;
- uint32_t bytes_of_surface = zsize * ystride;
+ uint32_t xstride = bytes_per_component * components * dim_x;
+ uint32_t ystride = xstride * dim_y;
+ uint32_t bytes_of_surface = ystride * dim_z;
- uint8_t *buf = (uint8_t *) malloc(bytes_of_surface);
+ uint8_t *buf = new uint8_t[bytes_of_surface];
size_t bytes_read = fread(buf, 1, bytes_of_surface, f);
fclose(f);
if (bytes_read != bytes_of_surface)
{
- free(buf);
+ delete[] buf;
printf("Failed to read file %s\n", filename);
- *result = -6;
return nullptr;
}
// then transfer data from the surface to our own image-data-structure.
- astc_codec_image *astc_img = alloc_image(bitness, xsize, ysize, zsize, padding);
+ astcenc_image *astc_img = alloc_image(bitness, dim_x, dim_y, dim_z, dim_pad);
- for (z = 0; z < zsize; z++)
+ for (unsigned int z = 0; z < dim_z; z++)
{
- int zdst = zsize == 1 ? z : z + padding;
- for (y = 0; y < ysize; y++)
+ unsigned int zdst = dim_z == 1 ? z : z + dim_pad;
+
+ for (unsigned int y = 0; y < dim_y; y++)
{
- int ym = y_flip ? ysize - y - 1 : y;
- int ydst = ym + padding;
- void *dst;
+ unsigned int ymod = y_flip ? dim_y - y - 1 : y;
+ unsigned int ydst = ymod + dim_pad;
+ void* dst;
+
if (bitness == 16)
- dst = (void *)(astc_img->data16[zdst][ydst] + 4 * padding);
+ {
+ dst = (void*)(astc_img->data16[zdst][ydst] + 4 * dim_pad);
+ }
else
- dst = (void *)(astc_img->data8[zdst][ydst] + 4 * padding);
+ {
+ dst = (void*)(astc_img->data8[zdst][ydst] + 4 * dim_pad);
+ }
uint8_t *src = buf + (z * ystride) + (y * xstride);
- copy_scanline(dst, src, xsize, copy_method);
+ copy_scanline(dst, src, dim_x, copy_method);
}
}
- free(buf);
+ delete[] buf;
fill_image_padding_area(astc_img);
- *result = components + (bitness == 16 ? 0x80 : 0);
+ is_hdr = bitness == 16;
+ num_components = components;
return astc_img;
}
static int store_dds_uncompressed_image(
- const astc_codec_image* img,
+ const astcenc_image* img,
const char* dds_filename,
int y_flip
) {
- int i, j;
- int x, y, z;
-
- int xsize = img->xsize;
- int ysize = img->ysize;
- int zsize = img->zsize;
+ unsigned int dim_x = img->dim_x;
+ unsigned int dim_y = img->dim_y;
+ unsigned int dim_z = img->dim_z;
int bitness = img->data16 == nullptr ? 8 : 16;
int image_channels = (bitness == 16) ? 4 : determine_image_channels(img);
@@ -1512,29 +1505,35 @@ static int store_dds_uncompressed_image(
// main header data
dds_header hdr;
hdr.size = 124;
- hdr.flags = 0x100F | (zsize > 1 ? 0x800000 : 0);
- hdr.height = ysize;
- hdr.width = xsize;
- hdr.pitch_or_linear_size = image_channels * (bitness / 8) * xsize;
- hdr.depth = zsize;
+ hdr.flags = 0x100F | (dim_z > 1 ? 0x800000 : 0);
+ hdr.height = dim_y;
+ hdr.width = dim_x;
+ hdr.pitch_or_linear_size = image_channels * (bitness / 8) * dim_x;
+ hdr.depth = dim_z;
hdr.mipmapcount = 1;
- for (i = 0; i < 11; i++)
+ for (unsigned int i = 0; i < 11; i++)
+ {
hdr.reserved1[i] = 0;
+ }
hdr.caps = 0x1000;
- hdr.caps2 = (zsize > 1) ? 0x200000 : 0;
+ hdr.caps2 = (dim_z > 1) ? 0x200000 : 0;
hdr.caps3 = 0;
hdr.caps4 = 0;
// pixel-format data
if (bitness == 8)
+ {
hdr.ddspf = format_of_image_channels[image_channels - 1];
+ }
else
+ {
hdr.ddspf = dxt10_diverter;
+ }
// DX10 data
dds_header_dx10 dx10;
dx10.dxgi_format = DXGI_FORMAT_R16G16B16A16_FLOAT;
- dx10.resource_dimension = (zsize > 1) ? 4 : 3;
+ dx10.resource_dimension = (dim_z > 1) ? 4 : 3;
dx10.misc_flag = 0;
dx10.array_size = 1;
dx10.reserved = 0;
@@ -1545,46 +1544,46 @@ static int store_dds_uncompressed_image(
if (bitness == 8)
{
- row_pointers8 = new uint8_t **[zsize];
- row_pointers8[0] = new uint8_t *[ysize * zsize];
- row_pointers8[0][0] = new uint8_t[xsize * ysize * zsize * image_channels];
+ row_pointers8 = new uint8_t **[dim_z];
+ row_pointers8[0] = new uint8_t *[dim_y * dim_z];
+ row_pointers8[0][0] = new uint8_t[dim_x * dim_y * dim_z * image_channels];
- for (i = 1; i < zsize; i++)
+ for (unsigned int z = 1; z < dim_z; z++)
{
- row_pointers8[i] = row_pointers8[0] + ysize * i;
- row_pointers8[i][0] = row_pointers8[0][0] + ysize * xsize * image_channels * i;
+ row_pointers8[z] = row_pointers8[0] + dim_y * z;
+ row_pointers8[z][0] = row_pointers8[0][0] + dim_y * dim_z * image_channels * z;
}
- for (i = 0; i < zsize; i++)
+ for (unsigned int z = 0; z < dim_z; z++)
{
- for (j = 1; j < ysize; j++)
+ for (unsigned int y = 1; y < dim_y; y++)
{
- row_pointers8[i][j] = row_pointers8[i][0] + xsize * image_channels * j;
+ row_pointers8[z][y] = row_pointers8[z][0] + dim_x * image_channels * y;
}
}
- for (z = 0; z < zsize; z++)
+ for (unsigned int z = 0; z < dim_z; z++)
{
- for (y = 0; y < ysize; y++)
+ for (unsigned int y = 0; y < dim_y; y++)
{
- int ym = y_flip ? ysize - y - 1 : y;
+ int ym = y_flip ? dim_y - y - 1 : y;
switch (image_channels)
{
case 1: // single-component, treated as Luminance
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers8[z][y][x] = img->data8[z][ym][4 * x];
}
break;
case 2: // two-component, treated as Luminance-Alpha
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers8[z][y][2 * x] = img->data8[z][ym][4 * x];
row_pointers8[z][y][2 * x + 1] = img->data8[z][ym][4 * x + 3];
}
break;
case 3: // three-component, treated as RGB
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers8[z][y][3 * x] = img->data8[z][ym][4 * x];
row_pointers8[z][y][3 * x + 1] = img->data8[z][ym][4 * x + 1];
@@ -1592,7 +1591,7 @@ static int store_dds_uncompressed_image(
}
break;
case 4: // four-component, treated as RGBA
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers8[z][y][4 * x] = img->data8[z][ym][4 * x];
row_pointers8[z][y][4 * x + 1] = img->data8[z][ym][4 * x + 1];
@@ -1606,46 +1605,46 @@ static int store_dds_uncompressed_image(
}
else // if bitness == 16
{
- row_pointers16 = new uint16_t **[zsize];
- row_pointers16[0] = new uint16_t *[ysize * zsize];
- row_pointers16[0][0] = new uint16_t[xsize * ysize * zsize * image_channels];
+ row_pointers16 = new uint16_t **[dim_z];
+ row_pointers16[0] = new uint16_t *[dim_y * dim_z];
+ row_pointers16[0][0] = new uint16_t[dim_x * dim_y * dim_z * image_channels];
- for (i = 1; i < zsize; i++)
+ for (unsigned int z = 1; z < dim_z; z++)
{
- row_pointers16[i] = row_pointers16[0] + ysize * i;
- row_pointers16[i][0] = row_pointers16[0][0] + ysize * xsize * image_channels * i;
+ row_pointers16[z] = row_pointers16[0] + dim_y * z;
+ row_pointers16[z][0] = row_pointers16[0][0] + dim_y * dim_x * image_channels * z;
}
- for (i = 0; i < zsize; i++)
+ for (unsigned int z = 0; z < dim_z; z++)
{
- for (j = 1; j < ysize; j++)
+ for (unsigned int y = 1; y < dim_y; y++)
{
- row_pointers16[i][j] = row_pointers16[i][0] + xsize * image_channels * j;
+ row_pointers16[z][y] = row_pointers16[z][0] + dim_x * image_channels * y;
}
}
- for (z = 0; z < zsize; z++)
+ for (unsigned int z = 0; z < dim_z; z++)
{
- for (y = 0; y < ysize; y++)
+ for (unsigned int y = 0; y < dim_y; y++)
{
- int ym = y_flip ? ysize - y - 1: y;
+ int ym = y_flip ? dim_y - y - 1: y;
switch (image_channels)
{
case 1: // single-component, treated as Luminance
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers16[z][y][x] = img->data16[z][ym][4 * x];
}
break;
case 2: // two-component, treated as Luminance-Alpha
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers16[z][y][2 * x] = img->data16[z][ym][4 * x];
row_pointers16[z][y][2 * x + 1] = img->data16[z][ym][4 * x + 3];
}
break;
case 3: // three-component, treated as RGB
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers16[z][y][3 * x] = img->data16[z][ym][4 * x];
row_pointers16[z][y][3 * x + 1] = img->data16[z][ym][4 * x + 1];
@@ -1653,7 +1652,7 @@ static int store_dds_uncompressed_image(
}
break;
case 4: // four-component, treated as RGBA
- for (x = 0; x < xsize; x++)
+ for (unsigned int x = 0; x < dim_x; x++)
{
row_pointers16[z][y][4 * x] = img->data16[z][ym][4 * x];
row_pointers16[z][y][4 * x + 1] = img->data16[z][ym][4 * x + 1];
@@ -1667,7 +1666,7 @@ static int store_dds_uncompressed_image(
}
int retval = image_channels;
- uint32_t image_bytes = xsize * ysize * zsize * image_channels * (bitness / 8);
+ uint32_t image_bytes = dim_x * dim_y * dim_z * image_channels * (bitness / 8);
uint32_t dds_magic = DDS_MAGIC;
@@ -1736,9 +1735,9 @@ we use tinyexr; for TGA, BMP and PNG, we use stb_image_write.
// loader function. The last entry is a catch-all to use when nothing else matches;
// this will result in an attempt to use stb_image to load the image.
static const struct {
- const char *ending1;
- const char *ending2;
- astc_codec_image *(*loader_func)(const char *filename, int padding, int y_flip, int *load_result);
+ const char* ending1;
+ const char* ending2;
+ astcenc_image* (*loader_func)(const char*, unsigned int, bool, bool&, unsigned int&);
} loader_descs[] = {
// HDR formats
{".exr", ".EXR", load_image_with_tinyexr },
@@ -1759,7 +1758,7 @@ static const struct
const char *ending2;
const char *file_format_name;
int enforced_bitness;
- int (*storer_func)(const astc_codec_image *output_image, const char *output_filename, int y_flip);
+ int (*storer_func)(const astcenc_image *output_image, const char *output_filename, int y_flip);
} storer_descs[] = {
// LDR formats
{".bmp", ".BMP", "BMP", 8, store_bmp_image_with_stb},
@@ -1805,46 +1804,37 @@ int get_output_filename_enforced_bitness(
exit(1);
}
-astc_codec_image* astc_codec_load_image(
- const char* input_filename,
- int padding,
- int y_flip,
- int linearize_srgb,
- int rgb_force_use_of_hdr,
- int alpha_force_use_of_hdr,
- int* load_result
+astcenc_image* load_ncimage(
+ const char* filename,
+ unsigned int dim_pad,
+ bool y_flip,
+ bool& is_hdr,
+ unsigned int& num_components
) {
- // get hold of the filename ending
- const char* eptr = strrchr(input_filename, '.');
+ // Get the file extension
+ const char* eptr = strrchr(filename, '.');
if (!eptr)
{
- eptr = input_filename;
+ eptr = filename;
}
- // scan through descriptors until a match is found, then perform the load.
- for (int i = 0; i < loader_descr_count; i++)
+ // Scan through descriptors until a matching loader is found
+ for (unsigned int i = 0; i < loader_descr_count; i++)
{
if (loader_descs[i].ending1 == nullptr
|| strcmp(eptr, loader_descs[i].ending1) == 0
|| strcmp(eptr, loader_descs[i].ending2) == 0)
{
- astc_codec_image* img = loader_descs[i].loader_func(input_filename, padding, y_flip, load_result);
- if (img)
- {
- img->linearize_srgb = linearize_srgb;
- img->rgb_force_use_of_hdr = rgb_force_use_of_hdr;
- img->alpha_force_use_of_hdr = alpha_force_use_of_hdr;
- }
- return img;
+ return loader_descs[i].loader_func(filename, dim_pad, y_flip, is_hdr, num_components);
}
}
// Should never reach here - stb_image provides a generic handler
- ASTC_CODEC_INTERNAL_ERROR();
+ return nullptr;
}
-int astc_codec_store_image(
- const astc_codec_image* output_image,
+int store_ncimage(
+ const astcenc_image* output_image,
const char* output_filename,
const char** file_format_name,
int y_flip
@@ -1867,5 +1857,143 @@ int astc_codec_store_image(
// Should never reach here - get_output_filename_enforced_bitness should
// have acted as a preflight check
- ASTC_CODEC_INTERNAL_ERROR();
+ return -1;
+}
+
+/* ============================================================================
+ ASTC compressed file loading
+============================================================================ */
+struct astc_header
+{
+ uint8_t magic[4];
+ uint8_t block_x;
+ uint8_t block_y;
+ uint8_t block_z;
+ uint8_t dim_x[3]; // dims = dim[0] + (dim[1] << 8) + (dim[2] << 16)
+ uint8_t dim_y[3]; // Sizes are given in texels;
+ uint8_t dim_z[3]; // block count is inferred
+};
+
+
+static const uint32_t ASTC_MAGIC_ID = 0x5CA1AB13;
+
+static unsigned int unpack_bytes(
+ uint8_t a,
+ uint8_t b,
+ uint8_t c,
+ uint8_t d
+) {
+ return ((unsigned int)(a)) +
+ ((unsigned int)(b) << 8) +
+ ((unsigned int)(c) << 16) +
+ ((unsigned int)(d) << 24);
+}
+
+int load_cimage(
+ const char* filename,
+ astc_compressed_image& out_image
+) {
+ std::ifstream file(filename, std::ios::in | std::ios::binary);
+ if (!file)
+ {
+ printf("ERROR: File open failed '%s'\n", filename);
+ return 1;
+ }
+
+ astc_header hdr;
+ file.read((char*)&hdr, sizeof(astc_header));
+ if (!file)
+ {
+ printf("ERROR: File read failed '%s'\n", filename);
+ return 1;
+ }
+
+ unsigned int magicval = unpack_bytes(hdr.magic[0], hdr.magic[1], hdr.magic[2], hdr.magic[3]);
+ if (magicval != ASTC_MAGIC_ID)
+ {
+ printf("ERROR: File not recognized '%s'\n", filename);
+ return 1;
+ }
+
+ // Ensure these are not zero to avoid div by zero
+ unsigned int block_x = MAX(hdr.block_x, 1);
+ unsigned int block_y = MAX(hdr.block_y, 1);
+ unsigned int block_z = MAX(hdr.block_z, 1);
+
+ unsigned int dim_x = unpack_bytes(hdr.dim_x[0], hdr.dim_x[1], hdr.dim_x[2], 0);
+ unsigned int dim_y = unpack_bytes(hdr.dim_y[0], hdr.dim_y[1], hdr.dim_y[2], 0);
+ unsigned int dim_z = unpack_bytes(hdr.dim_z[0], hdr.dim_z[1], hdr.dim_z[2], 0);
+
+ if (dim_x == 0 || dim_z == 0 || dim_z == 0)
+ {
+ printf("ERROR: File corrupt '%s'\n", filename);
+ return 1;
+ }
+
+ unsigned int xblocks = (dim_x + block_x - 1) / block_x;
+ unsigned int yblocks = (dim_y + block_y - 1) / block_y;
+ unsigned int zblocks = (dim_z + block_z - 1) / block_z;
+
+ size_t data_size = xblocks * yblocks * zblocks * 16;
+ uint8_t *buffer = new uint8_t[data_size];
+
+ file.read((char*)buffer, data_size);
+ if (!file)
+ {
+ printf("ERROR: File read failed '%s'\n", filename);
+ return 1;
+ }
+
+ out_image.data = buffer;
+ out_image.block_x = block_x;
+ out_image.block_y = block_y;
+ out_image.block_z = block_z;
+ out_image.dim_x = dim_x;
+ out_image.dim_y = dim_y;
+ out_image.dim_z = dim_z;
+ return 0;
+}
+
+
+int store_cimage(
+ const astc_compressed_image& comp_img,
+ const char* filename
+) {
+ int xblocks = (comp_img.dim_x + comp_img.block_x - 1) / comp_img.block_x;
+ int yblocks = (comp_img.dim_y + comp_img.block_y - 1) / comp_img.block_y;
+ int zblocks = (comp_img.dim_z + comp_img.block_z - 1) / comp_img.block_z;
+ size_t data_bytes = xblocks * yblocks * zblocks * 16;
+
+ astc_header hdr;
+ hdr.magic[0] = ASTC_MAGIC_ID & 0xFF;
+ hdr.magic[1] = (ASTC_MAGIC_ID >> 8) & 0xFF;
+ hdr.magic[2] = (ASTC_MAGIC_ID >> 16) & 0xFF;
+ hdr.magic[3] = (ASTC_MAGIC_ID >> 24) & 0xFF;
+
+ hdr.block_x = comp_img.block_x;
+ hdr.block_y = comp_img.block_y;
+ hdr.block_z = comp_img.block_z;
+
+ hdr.dim_x[0] = comp_img.dim_x & 0xFF;
+ hdr.dim_x[1] = (comp_img.dim_x >> 8) & 0xFF;
+ hdr.dim_x[2] = (comp_img.dim_x >> 16) & 0xFF;
+
+ hdr.dim_y[0] = comp_img.dim_y & 0xFF;
+ hdr.dim_y[1] = (comp_img.dim_y >> 8) & 0xFF;
+ hdr.dim_y[2] = (comp_img.dim_y >> 16) & 0xFF;
+
+ hdr.dim_z[0] = comp_img.dim_z & 0xFF;
+ hdr.dim_z[1] = (comp_img.dim_z >> 8) & 0xFF;
+ hdr.dim_z[2] = (comp_img.dim_z >> 16) & 0xFF;
+
+ std::ofstream file(filename, std::ios::out | std::ios::binary);
+ if (!file)
+ {
+ printf("ERROR: File open failed '%s'\n", filename);
+ return 1;
+ }
+
+ file.write((char*)&hdr, sizeof(astc_header));
+ file.write((char*)comp_img.data, data_bytes);
+ return 0;
}
diff --git a/Source/astcenccli_internal.h b/Source/astcenccli_internal.h
new file mode 100644
index 0000000..7808401
--- /dev/null
+++ b/Source/astcenccli_internal.h
@@ -0,0 +1,171 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2020 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions and data declarations.
+ */
+
+#ifndef ASTCENCCLI_INTERNAL_INCLUDED
+#define ASTCENCCLI_INTERNAL_INCLUDED
+
+#include
+#include
+#include
+#include
+
+#include "astcenc.h"
+#include "astcenc_mathlib.h"
+
+struct astc_compressed_image
+{
+ unsigned int block_x;
+ unsigned int block_y;
+ unsigned int block_z;
+ unsigned int dim_x;
+ unsigned int dim_y;
+ unsigned int dim_z;
+ uint8_t* data;
+};
+
+// Config options to be read from command line
+struct cli_config_options
+{
+ unsigned int thread_count;
+ unsigned int array_size;
+ bool silentmode;
+ bool y_flip;
+ bool linearize_srgb;
+ int low_fstop;
+ int high_fstop;
+ astcenc_swizzle swz_encode;
+ astcenc_swizzle swz_decode;
+};
+
+/**
+ * Functions to load image from file.
+ *
+ * @param filename The file path on disk.
+ * @param padding The texel padding needed around the image.
+ * @param y_flip Should this image be Y flipped?
+ * @param[out] is_hdr Is the loaded image HDR?
+ * @param[out] num_components The number of components in the loaded image.
+ *
+ * @return The astc image file, or nullptr on error.
+ */
+astcenc_image* load_ncimage(
+ const char* filename,
+ unsigned int dim_pad,
+ bool y_flip,
+ bool& is_hdr,
+ unsigned int& num_components);
+
+int store_ncimage(
+ const astcenc_image* output_image,
+ const char* output_filename,
+ const char** file_format_name,
+ int y_flip);
+
+int get_output_filename_enforced_bitness(
+ const char* filename);
+
+
+astcenc_image* alloc_image(
+ unsigned int bitness,
+ unsigned int dim_x,
+ unsigned int dim_y,
+ unsigned int dim_z,
+ unsigned int dim_pad);
+
+void free_image(
+ astcenc_image* img);
+
+void fill_image_padding_area(
+ astcenc_image* img);
+
+int determine_image_channels(
+ const astcenc_image* img);
+
+int load_cimage(
+ const char* filename,
+ astc_compressed_image& out_image);
+
+int store_cimage(
+ const astc_compressed_image& comp_img,
+ const char* filename);
+
+// helper functions to prepare an ASTC image object from a flat array
+// Used by the image loaders in "astc_file_load_store.cpp"
+astcenc_image* astc_img_from_floatx4_array(
+ const float* data,
+ unsigned int dim_x,
+ unsigned int dim_y,
+ unsigned int dim_pad,
+ bool y_flip);
+
+astcenc_image*astc_img_from_unorm8x4_array(
+ const uint8_t* data,
+ unsigned int dim_x,
+ unsigned int dim_y,
+ unsigned int dim_pad,
+ bool y_flip);
+
+// helper functions to prepare a flat array from an ASTC image object.
+// the array is allocated with new[], and must be freed with delete[].
+float* floatx4_array_from_astc_img(
+ const astcenc_image* img,
+ bool y_flip);
+
+uint8_t* unorm8x4_array_from_astc_img(
+ const astcenc_image* img,
+ bool y_flip);
+
+/* ============================================================================
+ Functions for printing build info and help messages
+============================================================================ */
+void astcenc_print_header();
+
+void astcenc_print_shorthelp();
+
+void astcenc_print_longhelp();
+
+/**
+ * @brief Compute error metrics comparing two images.
+ *
+ * @param compute_hdr_metrics Non-zero if HDR metrics should be computed.
+ * @param input_components The number of input color components.
+ * @param img1 The original iamge.
+ * @param img2 The compressed image.
+ * @param fstop_lo The low exposure fstop (HDR only).
+ * @param fstop_hi The high exposure fstop (HDR only).
+ * @param show_psnr Non-zero if metrics should be logged to stdout.
+ */
+void compute_error_metrics(
+ int compute_hdr_metrics,
+ int input_components,
+ const astcenc_image* img1,
+ const astcenc_image* img2,
+ int fstop_lo,
+ int fstop_hi);
+
+/**
+ * @brief Get the current time.
+ *
+ * @returns The current time in seconds since arbitrary epoch.
+ */
+double get_time();
+
+#endif
diff --git a/Source/astcenccli_platform_dependents.cpp b/Source/astcenccli_platform_dependents.cpp
new file mode 100644
index 0000000..76b9e75
--- /dev/null
+++ b/Source/astcenccli_platform_dependents.cpp
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2020 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Platform-specific function implementations.
+ *
+ * This module contains functions with strongly OS-dependent implementations:
+ *
+ * * CPU count queries
+ * * Threading
+ * * Time
+ *
+ * In addition to the basic thread abstraction (which is native pthreads on
+ * all platforms, except Windows where it is an emulation of pthreads), a
+ * utility function to create N threads and wait for them to complete a batch
+ * task has also been provided.
+ */
+
+#include "astcenccli_internal.h"
+
+/* ============================================================================
+ Platform code for Windows using the Win32 APIs.
+============================================================================ */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+
+#define WIN32_LEAN_AND_MEAN
+#include
+
+/* Public function, see header file for detailed documentation */
+double get_time()
+{
+ FILETIME tv;
+ GetSystemTimeAsFileTime(&tv);
+ unsigned long long ticks = tv.dwHighDateTime;
+ ticks = (ticks << 32) | tv.dwLowDateTime;
+ return ((double)ticks) / 1.0e7;
+}
+
+/* Public function, see header file for detailed documentation */
+int unlink_file(const char *filename)
+{
+ BOOL res = DeleteFileA(filename);
+ return (res ? 0 : -1);
+}
+
+/* ============================================================================
+ Platform code for an platform using POSIX APIs.
+============================================================================ */
+#else
+
+#include
+#include
+
+/* Public function, see header file for detailed documentation */
+double get_time()
+{
+ timeval tv;
+ gettimeofday(&tv, 0);
+ return (double)tv.tv_sec + (double)tv.tv_usec * 1.0e-6;
+}
+
+/* Public function, see header file for detailed documentation */
+int unlink_file(const char *filename)
+{
+ return unlink(filename);
+}
+
+#endif
diff --git a/Source/astcenccli_toplevel.cpp b/Source/astcenccli_toplevel.cpp
new file mode 100644
index 0000000..7f5ddc1
--- /dev/null
+++ b/Source/astcenccli_toplevel.cpp
@@ -0,0 +1,1093 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2020 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions for codec library front-end.
+ */
+
+#include "astcenc.h"
+#include "astcenccli_internal.h"
+
+#include
+#include
+#include
+#include
+
+/* ============================================================================
+ Data structure definitions
+============================================================================ */
+
+typedef unsigned int astcenc_operation;
+
+struct mode_entry {
+ std::string opt;
+ astcenc_operation operation;
+ astcenc_profile decode_mode;
+};
+
+/* ============================================================================
+ Constants and literals
+============================================================================ */
+
+static const unsigned int ASTCENC_STAGE_LD_COMP = 1 << 0;
+static const unsigned int ASTCENC_STAGE_ST_COMP = 1 << 1;
+
+static const unsigned int ASTCENC_STAGE_LD_NCOMP = 1 << 2;
+static const unsigned int ASTCENC_STAGE_ST_NCOMP = 1 << 3;
+
+static const unsigned int ASTCENC_STAGE_COMPRESS = 1 << 4;
+static const unsigned int ASTCENC_STAGE_DECOMPRESS = 1 << 5;
+static const unsigned int ASTCENC_STAGE_COMPARE = 1 << 6;
+
+static const astcenc_operation ASTCENC_OP_UNKNOWN = 0;
+static const astcenc_operation ASTCENC_OP_HELP = 1 << 7;
+static const astcenc_operation ASTCENC_OP_VERSION = 1 << 8;
+
+static const astcenc_operation ASTCENC_OP_COMPRESS =
+ ASTCENC_STAGE_LD_NCOMP |
+ ASTCENC_STAGE_COMPRESS |
+ ASTCENC_STAGE_ST_COMP;
+
+static const astcenc_operation ASTCENC_OP_DECOMPRESS =
+ ASTCENC_STAGE_LD_COMP |
+ ASTCENC_STAGE_DECOMPRESS |
+ ASTCENC_STAGE_ST_NCOMP;
+
+static const astcenc_operation ASTCENC_OP_TEST =
+ ASTCENC_STAGE_LD_NCOMP |
+ ASTCENC_STAGE_COMPRESS |
+ ASTCENC_STAGE_DECOMPRESS |
+ ASTCENC_STAGE_COMPARE |
+ ASTCENC_STAGE_ST_NCOMP;
+
+static const mode_entry modes[] = {
+ {"-cl", ASTCENC_OP_COMPRESS, ASTCENC_PRF_LDR},
+ {"-dl", ASTCENC_OP_DECOMPRESS, ASTCENC_PRF_LDR},
+ {"-tl", ASTCENC_OP_TEST, ASTCENC_PRF_LDR},
+ {"-cs", ASTCENC_OP_COMPRESS, ASTCENC_PRF_LDR_SRGB},
+ {"-ds", ASTCENC_OP_DECOMPRESS, ASTCENC_PRF_LDR_SRGB},
+ {"-ts", ASTCENC_OP_TEST, ASTCENC_PRF_LDR_SRGB},
+ {"-ch", ASTCENC_OP_COMPRESS, ASTCENC_PRF_HDR},
+ {"-dh", ASTCENC_OP_DECOMPRESS, ASTCENC_PRF_HDR},
+ {"-th", ASTCENC_OP_TEST, ASTCENC_PRF_HDR},
+ {"-cH", ASTCENC_OP_COMPRESS, ASTCENC_PRF_HDR_RGB_LDR_A},
+ {"-dH", ASTCENC_OP_DECOMPRESS, ASTCENC_PRF_HDR_RGB_LDR_A},
+ {"-tH", ASTCENC_OP_TEST, ASTCENC_PRF_HDR_RGB_LDR_A},
+ {"-h", ASTCENC_OP_HELP, ASTCENC_PRF_HDR},
+ {"-help", ASTCENC_OP_HELP, ASTCENC_PRF_HDR},
+ {"-v", ASTCENC_OP_VERSION, ASTCENC_PRF_HDR},
+ {"-version", ASTCENC_OP_VERSION, ASTCENC_PRF_HDR}
+};
+
+
+/**
+ * @brief Utility to generate a slice file name from a pattern.
+ *
+ * Convert "foo/bar.png" in to "foo/bar_.png"
+ *
+ * @param basename The base pattern; must contain a file extension.
+ * @param index The slice index.
+ * @param error Set to true on success, false on error (no extension found).
+ *
+ * @return The slice file name.
+ */
+static std::string get_slice_filename(
+ const std::string& basename,
+ unsigned int index,
+ bool& error
+) {
+ size_t sep = basename.find_last_of(".");
+ if (sep == std::string::npos)
+ {
+ error = true;
+ return "";
+ }
+
+ std::string base = basename.substr(0, sep);
+ std::string ext = basename.substr(sep);
+ std::string name = base + "_" + std::to_string(index) + ext;
+ error = false;
+ return name;
+}
+
+/**
+ * @brief Load a non-astc image file from memory.
+ *
+ * @param filename The file to load, or a pattern for array loads.
+ * @param dim_z The number of slices to load.
+ * @param padding The number of texels of padding.
+ * @param y_flip Should this image be Y flipped?
+ * @param linearize_srgb Should this image be converted to linear from sRGB?
+ * @param[out] is_hdr Is the loaded image HDR?
+ * @param[out] num_components The number of components in the loaded image.
+ *
+ * @return The astc image file, or nullptr on error.
+ */
+static astcenc_image* load_uncomp_file(
+ const char* filename,
+ unsigned int dim_z,
+ unsigned int dim_pad,
+ bool y_flip,
+ bool& is_hdr,
+ unsigned int& num_components
+) {
+ astcenc_image *image = nullptr;
+
+ // For a 2D image just load the image directly
+ if (dim_z == 1)
+ {
+ image = load_ncimage(filename, dim_pad, y_flip, is_hdr, num_components);
+ }
+ else
+ {
+ bool slice_is_hdr;
+ unsigned int slice_num_components;
+ astcenc_image* slice = nullptr;
+ std::vector slices;
+
+ // For a 3D image load an array of slices
+ for (unsigned int image_index = 0; image_index < dim_z; image_index++)
+ {
+ bool error;
+ std::string slice_name = get_slice_filename(filename, image_index, error);
+ if (error)
+ {
+ printf("ERROR: Image pattern does not contain file extension: %s\n", filename);
+ break;
+ }
+
+ slice = load_ncimage(slice_name.c_str(), dim_pad, y_flip,
+ slice_is_hdr, slice_num_components);
+ if (!slice)
+ {
+ break;
+ }
+
+ slices.push_back(slice);
+
+ // Check it is not a 3D image
+ if (slice->dim_z != 1)
+ {
+ printf("ERROR: Image arrays do not support 3D sources: %s\n", slice_name.c_str());
+ break;
+ }
+
+ // Check slices are consistent with each other
+ if (image_index != 0)
+ {
+ if ((is_hdr != slice_is_hdr) || (num_components != slice_num_components))
+ {
+ printf("ERROR: Image array[0] and [%d] are different formats\n", image_index);
+ break;
+ }
+
+ if ((slices[0]->dim_x != slice->dim_x) ||
+ (slices[0]->dim_y != slice->dim_y) ||
+ (slices[0]->dim_z != slice->dim_z))
+ {
+ printf("ERROR: Image array[0] and [%d] are different dimensions\n", image_index);
+ break;
+ }
+ }
+ else
+ {
+ is_hdr = slice_is_hdr;
+ num_components = slice_num_components;
+ }
+ }
+
+ // If all slices loaded correctly then repack them into a single image
+ if (slices.size() == dim_z)
+ {
+ unsigned int dim_x = slices[0]->dim_x;
+ unsigned int dim_y = slices[0]->dim_y;
+ int bitness = is_hdr ? 16 : 8;
+ int slice_size = (dim_x + (2 * dim_pad)) * (dim_y + (2 * dim_pad));
+
+ image = alloc_image(bitness, dim_x, dim_y, dim_z, dim_pad);
+
+ // Combine 2D source images into one 3D image; skipping padding slices
+ for (unsigned int z = dim_pad; z < dim_z + dim_pad; z++)
+ {
+ if (bitness == 8)
+ {
+ size_t copy_size = slice_size * 4 * sizeof(uint8_t);
+ memcpy(*image->data8[z], *slices[z - dim_pad]->data8[0], copy_size);
+ }
+ else
+ {
+ size_t copy_size = slice_size * 4 * sizeof(uint16_t);
+ memcpy(*image->data16[z], *slices[z - dim_pad]->data16[0], copy_size);
+ }
+ }
+
+ // Fill in the padding slices with clamped data
+ fill_image_padding_area(image);
+ }
+
+ for (auto &i : slices)
+ {
+ free_image(i);
+ }
+ }
+
+ return image;
+}
+
+/**
+ * @brief Parse the command line and read operation, profile
+ * input and output file names
+ *
+ * @param argc
+ * @param argv
+ * @param operation ASTC operation mode
+ * @param profile ASTC profile
+ *
+ * @return 0 if everything is Okay, 1 if there is some error
+ */
+int parse_commandline_options(
+ int argc,
+ char **argv,
+ astcenc_operation& operation,
+ astcenc_profile& profile
+) {
+ assert(argc >= 2); (void)argc;
+
+ profile = ASTCENC_PRF_LDR;
+ operation = ASTCENC_OP_UNKNOWN;
+
+ int modes_count = sizeof(modes) / sizeof(modes[0]);
+ for (int i = 0; i < modes_count; i++)
+ {
+ if (modes[i].opt == argv[1])
+ {
+ operation = modes[i].operation;
+ profile = modes[i].decode_mode;
+ break;
+ }
+ }
+
+ if (operation == ASTCENC_OP_UNKNOWN)
+ {
+ printf("ERROR: Unrecognized operation '%s'\n", argv[1]);
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Initialize the astcenc_config
+ *
+ * @param argc
+ * @param argv
+ * @param operation ASTC operation mode
+ * @param comp_image
+ * @param config The astcenc configuration
+ *
+ * @return 0 if everything is Okay, 1 if there is some error
+ */
+astcenc_error init_astcenc_config(
+ int argc,
+ char **argv,
+ astcenc_profile profile,
+ astcenc_operation operation,
+ astc_compressed_image& comp_image,
+ astcenc_config& config
+) {
+ unsigned int block_x = 0;
+ unsigned int block_y = 0;
+ unsigned int block_z = 1;
+
+ // For decode the block size is set by the incoming image.
+ if (operation == ASTCENC_OP_DECOMPRESS)
+ {
+ block_x = comp_image.block_x;
+ block_y = comp_image.block_y;
+ block_z = comp_image.block_y;
+ }
+
+ astcenc_preset preset = ASTCENC_PRE_FAST;
+
+ // parse the command line's encoding options.
+ int argidx = 4;
+ if (operation & ASTCENC_STAGE_COMPRESS)
+ {
+ // Read and decode block size
+ if (argc < 5)
+ {
+ return ASTCENC_ERR_BAD_BLOCK_SIZE;
+ }
+
+ int cnt2D, cnt3D;
+ int dimensions = sscanf(argv[4], "%ux%u%nx%u%n",
+ &block_x, &block_y, &cnt2D, &block_z, &cnt3D);
+ // Character after the last match should be a NUL
+ if (!(((dimensions == 2) && !argv[4][cnt2D]) || ((dimensions == 3) && !argv[4][cnt3D])))
+ {
+ return ASTCENC_ERR_BAD_BLOCK_SIZE;
+ }
+
+ // Read and decode search preset
+ if (argc < 6)
+ {
+ return ASTCENC_ERR_BAD_PRESET;
+ }
+
+ if (!strcmp(argv[5], "-fast"))
+ {
+ preset = ASTCENC_PRE_FAST;
+ }
+ else if (!strcmp(argv[5], "-medium"))
+ {
+ preset = ASTCENC_PRE_MEDIUM;
+ }
+ else if (!strcmp(argv[5], "-thorough"))
+ {
+ preset = ASTCENC_PRE_THOROUGH;
+ }
+ else if (!strcmp(argv[5], "-exhaustive"))
+ {
+ preset = ASTCENC_PRE_EXHAUSTIVE;
+ }
+ else
+ {
+ return ASTCENC_ERR_BAD_PRESET;
+ }
+
+ argidx = 6;
+ }
+
+ unsigned int flags = 0;
+
+ // Gather the flags that we need
+ while (argidx < argc)
+ {
+ if (!strcmp(argv[argidx], "-a"))
+ {
+ // Skip over the data value for now
+ argidx++;
+ flags |= ASTCENC_FLG_USE_ALPHA_WEIGHT;
+ }
+ else if (!strcmp(argv[argidx], "-normal_psnr"))
+ {
+ flags |= ASTCENC_FLG_MAP_NORMAL;
+ }
+ else if (!strcmp(argv[argidx], "-normal_percep"))
+ {
+ flags |= ASTCENC_FLG_MAP_NORMAL;
+ flags |= ASTCENC_FLG_USE_PERCEPTUAL;
+ }
+ else if (!strcmp(argv[argidx], "-mask"))
+ {
+
+ flags |= ASTCENC_FLG_MAP_MASK;
+ }
+ else if (!strcmp(argv[argidx], "-linsrgb"))
+ {
+ flags |= ASTCENC_FLG_USE_LINEARIZED_SRGB;
+ }
+ argidx ++;
+ }
+
+ astcenc_error status = astcenc_init_config(profile, block_x, block_y, block_z, preset, flags, config);
+ return status;
+}
+
+/**
+ * @brief Edit the astcenc_config
+ *
+ * @param argc
+ * @param argv
+ * @param operation ASTC operation mode
+ * @param cli_config Command line config options
+ * @param config The astcenc configuration
+ *
+ * @return 0 if everything is Okay, 1 if there is some error
+ */
+int edit_astcenc_config(
+ int argc,
+ char **argv,
+ const astcenc_operation operation,
+ cli_config_options& cli_config,
+ astcenc_config& config
+) {
+
+ int argidx = (operation & ASTCENC_STAGE_COMPRESS) ? 6 : 4;
+
+ while (argidx < argc)
+ {
+ if (!strcmp(argv[argidx], "-silent"))
+ {
+ argidx++;
+ cli_config.silentmode = 1;
+ }
+ else
+ if (!strcmp(argv[argidx], "-v"))
+ {
+ argidx += 7;
+ if (argidx > argc)
+ {
+ printf("ERROR: -v switch with less than 6 arguments\n");
+ return 1;
+ }
+
+ config.v_rgba_radius = atoi(argv[argidx - 6]);
+ config.v_rgb_power = static_cast(atof(argv[argidx - 5]));
+ config.v_rgb_base = static_cast(atof(argv[argidx - 4]));
+ config.v_rgb_mean = static_cast(atof(argv[argidx - 3]));
+ config.v_rgb_stdev = static_cast(atof(argv[argidx - 2]));
+ config.v_rgba_mean_stdev_mix = static_cast(atof(argv[argidx - 1]));
+ }
+ else if (!strcmp(argv[argidx], "-va"))
+ {
+ argidx += 5;
+ if (argidx > argc)
+ {
+ printf("ERROR: -va switch with less than 4 arguments\n");
+ return 1;
+ }
+
+ config.v_a_power= static_cast(atof(argv[argidx - 4]));
+ config.v_a_base = static_cast(atof(argv[argidx - 3]));
+ config.v_a_mean = static_cast(atof(argv[argidx - 2]));
+ config.v_a_stdev = static_cast(atof(argv[argidx - 1]));
+ }
+ else if (!strcmp(argv[argidx], "-cw"))
+ {
+ argidx += 5;
+ if (argidx > argc)
+ {
+ printf("ERROR: -cw switch with less than 4 arguments\n");
+ return 1;
+ }
+
+ config.cw_r_weight = static_cast(atof(argv[argidx - 4]));
+ config.cw_g_weight = static_cast(atof(argv[argidx - 3]));
+ config.cw_b_weight = static_cast(atof(argv[argidx - 2]));
+ config.cw_a_weight = static_cast(atof(argv[argidx - 1]));
+ }
+ else if (!strcmp(argv[argidx], "-a"))
+ {
+ argidx += 2;
+ if (argidx > argc)
+ {
+ printf("ERROR: -a switch with no argument\n");
+ return 1;
+ }
+
+ config.a_scale_radius = atoi(argv[argidx - 1]);
+ }
+ else if (!strcmp(argv[argidx], "-b"))
+ {
+ argidx += 2;
+ if (argidx > argc)
+ {
+ printf("ERROR: -b switch with no argument\n");
+ return 1;
+ }
+
+ config.b_deblock_weight = static_cast(atof(argv[argidx - 1]));
+ }
+ else if (!strcmp(argv[argidx], "-esw"))
+ {
+ argidx += 2;
+ if (argidx > argc)
+ {
+ printf("ERROR: -esw switch with no argument\n");
+ return 1;
+ }
+
+ if (strlen(argv[argidx - 1]) != 4)
+ {
+ printf("ERROR: -esw pattern does not contain 4 characters\n");
+ return 1;
+ }
+
+ astcenc_swz swizzle_components[4];
+ for (int i = 0; i < 4; i++)
+ {
+ switch (argv[argidx - 1][i])
+ {
+ case 'r':
+ swizzle_components[i] = ASTCENC_SWZ_R;
+ break;
+ case 'g':
+ swizzle_components[i] = ASTCENC_SWZ_G;
+ break;
+ case 'b':
+ swizzle_components[i] = ASTCENC_SWZ_B;
+ break;
+ case 'a':
+ swizzle_components[i] = ASTCENC_SWZ_A;
+ break;
+ case '0':
+ swizzle_components[i] = ASTCENC_SWZ_0;
+ break;
+ case '1':
+ swizzle_components[i] = ASTCENC_SWZ_1;
+ break;
+ default:
+ printf("ERROR: -esw channel '%c' is not valid\n", argv[argidx - 1][i]);
+ return 1;
+ }
+ }
+
+ cli_config.swz_encode.r = swizzle_components[0];
+ cli_config.swz_encode.g = swizzle_components[1];
+ cli_config.swz_encode.b = swizzle_components[2];
+ cli_config.swz_encode.a = swizzle_components[3];
+ }
+ else if (!strcmp(argv[argidx], "-dsw"))
+ {
+ argidx += 2;
+ if (argidx > argc)
+ {
+ printf("ERROR: -dsw switch with no argument\n");
+ return 1;
+ }
+
+ if (strlen(argv[argidx - 1]) != 4)
+ {
+ printf("ERROR: -dsw switch does not contain 4 characters\n");
+ return 1;
+ }
+
+ astcenc_swz swizzle_components[4];
+ for (int i = 0; i < 4; i++)
+ {
+ switch (argv[argidx - 1][i])
+ {
+ case 'r':
+ swizzle_components[i] = ASTCENC_SWZ_R;
+ break;
+ case 'g':
+ swizzle_components[i] = ASTCENC_SWZ_G;
+ break;
+ case 'b':
+ swizzle_components[i] = ASTCENC_SWZ_B;
+ break;
+ case 'a':
+ swizzle_components[i] = ASTCENC_SWZ_A;
+ break;
+ case '0':
+ swizzle_components[i] = ASTCENC_SWZ_0;
+ break;
+ case '1':
+ swizzle_components[i] = ASTCENC_SWZ_1;
+ break;
+ case 'z':
+ swizzle_components[i] = ASTCENC_SWZ_Z;
+ break;
+ default:
+ printf("ERROR: ERROR: -dsw channel '%c' is not valid\n", argv[argidx - 1][i]);
+ return 1;
+ }
+ }
+
+ cli_config.swz_decode.r = swizzle_components[0];
+ cli_config.swz_decode.g = swizzle_components[1];
+ cli_config.swz_decode.b = swizzle_components[2];
+ cli_config.swz_decode.a = swizzle_components[3];
+ }
+ // presets begin here
+ else if (!strcmp(argv[argidx], "-normal_psnr"))
+ {
+ argidx++;
+
+ cli_config.swz_encode.r = ASTCENC_SWZ_R;
+ cli_config.swz_encode.g = ASTCENC_SWZ_R;
+ cli_config.swz_encode.b = ASTCENC_SWZ_R;
+ cli_config.swz_encode.a = ASTCENC_SWZ_G;
+
+ cli_config.swz_decode.r = ASTCENC_SWZ_R;
+ cli_config.swz_decode.g = ASTCENC_SWZ_A;
+ cli_config.swz_decode.b = ASTCENC_SWZ_Z;
+ cli_config.swz_decode.a = ASTCENC_SWZ_1;
+ }
+ else if (!strcmp(argv[argidx], "-normal_percep"))
+ {
+ argidx++;
+
+ cli_config.swz_encode.r = ASTCENC_SWZ_R;
+ cli_config.swz_encode.g = ASTCENC_SWZ_R;
+ cli_config.swz_encode.b = ASTCENC_SWZ_R;
+ cli_config.swz_encode.a = ASTCENC_SWZ_G;
+
+ cli_config.swz_decode.r = ASTCENC_SWZ_R;
+ cli_config.swz_decode.g = ASTCENC_SWZ_A;
+ cli_config.swz_decode.b = ASTCENC_SWZ_Z;
+ cli_config.swz_decode.a = ASTCENC_SWZ_1;
+ }
+ else if (!strcmp(argv[argidx], "-mask"))
+ {
+ argidx++;
+ }
+ else if (!strcmp(argv[argidx], "-blockmodelimit"))
+ {
+ argidx += 2;
+ if (argidx > argc)
+ {
+ printf("ERROR: -blockmodelimit switch with no argument\n");
+ return 1;
+ }
+
+ config.tune_block_mode_limit = atoi(argv[argidx - 1]);
+ }
+ else if (!strcmp(argv[argidx], "-partitionlimit"))
+ {
+ argidx += 2;
+ if (argidx > argc)
+ {
+ printf("ERROR: -partitionlimit switch with no argument\n");
+ return 1;
+ }
+
+ config.tune_partition_limit = atoi(argv[argidx - 1]);
+ }
+ else if (!strcmp(argv[argidx], "-dblimit"))
+ {
+ argidx += 2;
+ if (argidx > argc)
+ {
+ printf("ERROR: -dblimit switch with no argument\n");
+ return 1;
+ }
+
+ if ((config.profile == ASTCENC_PRF_LDR) || (config.profile == ASTCENC_PRF_LDR_SRGB))
+ {
+ config.tune_db_limit = static_cast(atof(argv[argidx - 1]));
+ }
+ }
+ else if (!strcmp(argv[argidx], "-partitionearlylimit"))
+ {
+ argidx += 2;
+ if (argidx > argc)
+ {
+ printf("ERROR: -partitionearlylimit switch with no argument\n");
+ return 1;
+ }
+
+ config.tune_partition_early_out_limit = static_cast(atof(argv[argidx - 1]));
+ }
+ else if (!strcmp(argv[argidx], "-planecorlimit"))
+ {
+ argidx += 2;
+ if (argidx > argc)
+ {
+ printf("ERROR: -planecorlimit switch with no argument\n");
+ return 1;
+ }
+
+ config.tune_two_plane_early_out_limit = static_cast(atof(argv[argidx - 1]));
+ }
+ else if (!strcmp(argv[argidx], "-refinementlimit"))
+ {
+ argidx += 2;
+ if (argidx > argc)
+ {
+ printf("ERROR: -refinementlimit switch with no argument\n");
+ return 1;
+ }
+
+ config.tune_refinement_limit = atoi(argv[argidx - 1]);
+ }
+ else if (!strcmp(argv[argidx], "-j"))
+ {
+ argidx += 2;
+ if (argidx > argc)
+ {
+ printf("ERROR: -j switch with no argument\n");
+ return 1;
+ }
+
+ cli_config.thread_count = atoi(argv[argidx - 1]);
+ }
+ else if (!strcmp(argv[argidx], "-linsrgb"))
+ {
+ argidx++;
+ cli_config.linearize_srgb = 1;
+ }
+ else if (!strcmp(argv[argidx], "-yflip"))
+ {
+ argidx++;
+ cli_config.y_flip = 1;
+ }
+ else if (!strcmp(argv[argidx], "-mpsnr"))
+ {
+ argidx += 3;
+ if (argidx > argc)
+ {
+ printf("ERROR: -mpsnr switch with less than 2 arguments\n");
+ return 1;
+ }
+
+ cli_config.low_fstop = atoi(argv[argidx - 2]);
+ cli_config.high_fstop = atoi(argv[argidx - 1]);
+ if (cli_config.high_fstop < cli_config.low_fstop)
+ {
+ printf("ERROR: -mpsnr switch is greater than the \n");
+ return 1;
+ }
+ }
+ // Option: Encode a 3D image from an array of 2D images.
+ else if (!strcmp(argv[argidx], "-array"))
+ {
+ // Only supports compressing
+ if (!(operation & ASTCENC_STAGE_COMPRESS))
+ {
+ printf("ERROR: -array switch is only valid for compression\n");
+ return 1;
+ }
+
+ // Image depth must be specified.
+ if (argidx + 2 > argc)
+ {
+ printf("ERROR: -array switch with no argument\n");
+ return 1;
+ }
+ argidx++;
+
+ // Read array size (image depth).
+ if (!sscanf(argv[argidx], "%u", &cli_config.array_size) || cli_config.array_size == 0)
+ {
+ printf("ERROR: -array size '%s' is invalid\n", argv[argidx]);
+ return 1;
+ }
+
+ if ((cli_config.array_size > 1) && (config.block_z == 1))
+ {
+ printf("ERROR: -array with 3D input data for a 2D output format\n");
+ return 1;
+ }
+ argidx++;
+ }
+ else // check others as well
+ {
+ printf("ERROR: Argument '%s' not recognized\n", argv[argidx]);
+ return 1;
+ }
+ }
+
+ if (operation & ASTCENC_STAGE_COMPRESS)
+ {
+ // print all encoding settings unless specifically told otherwise.
+ if (!cli_config.silentmode)
+ {
+ printf("Compressor settings\n");
+ printf("===================\n\n");
+
+ switch(config.profile)
+ {
+ case ASTCENC_PRF_LDR:
+ printf(" Color profile: LDR linear\n");
+ break;
+ case ASTCENC_PRF_LDR_SRGB:
+ printf(" Color profile: LDR sRGB\n");
+ break;
+ case ASTCENC_PRF_HDR_RGB_LDR_A:
+ printf(" Color profile: HDR RGB + LDR A\n");
+ break;
+ case ASTCENC_PRF_HDR:
+ printf(" Color profile: HDR RGBA\n");
+ break;
+ }
+
+ if (config.block_z == 1)
+ {
+ printf(" Block size: %ux%u\n", config.block_x, config.block_y);
+ }
+ else
+ {
+ printf(" Block size: %ux%ux%u\n", config.block_x, config.block_y, config.block_z);
+ }
+
+ printf(" Bitrate: %3.2f bpp\n", 128.0 / (config.block_x * config.block_y * config.block_z));
+
+ printf(" Radius mean/stdev: %u texels\n", config.v_rgba_radius);
+ printf(" RGB power: %g\n", (double)config.v_rgb_power );
+ printf(" RGB base weight: %g\n", (double)config.v_rgb_base);
+ printf(" RGB mean weight: %g\n", (double)config.v_rgb_mean);
+ printf(" RGB stdev weight: %g\n", (double)config.v_rgba_mean_stdev_mix);
+ printf(" RGB mean/stdev mixing: %g\n", (double)config.v_rgba_mean_stdev_mix);
+ printf(" Alpha power: %g\n", (double)config.v_a_power);
+ printf(" Alpha base weight: %g\n", (double)config.v_a_base);
+ printf(" Alpha mean weight: %g\n", (double)config.v_a_mean);
+ printf(" Alpha stdev weight: %g\n", (double)config.v_a_stdev);
+ printf(" RGB alpha scale weight: %d\n", (config.flags & ASTCENC_FLG_MAP_NORMAL));
+ if ((config.flags & ASTCENC_FLG_MAP_NORMAL))
+ {
+ printf(" Radius RGB alpha scale: %u texels\n", config.a_scale_radius);
+ }
+
+ printf(" R channel weight: %g\n",(double)config.cw_r_weight);
+ printf(" G channel weight: %g\n",(double)config.cw_g_weight);
+ printf(" B channel weight: %g\n",(double)config.cw_b_weight);
+ printf(" A channel weight: %g\n",(double)config.cw_a_weight);
+ printf(" Deblock artifact setting: %g\n", (double)config.b_deblock_weight);
+ printf(" Block partition cutoff: %u partitions\n", config.tune_partition_limit);
+ printf(" PSNR cutoff: %g dB\n", (double)config.tune_db_limit);
+ printf(" 1->2 partition cutoff: %g\n", (double)config.tune_partition_early_out_limit);
+ printf(" 2 plane correlation cutoff: %g\n", (double)config.tune_two_plane_early_out_limit);
+ printf(" Block mode centile cutoff: %g%%\n", (double)(config.tune_block_mode_limit));
+ printf(" Max refinement cutoff: %u iterations\n", config.tune_refinement_limit);
+ printf(" Compressor thread count: %d\n", cli_config.thread_count);
+ printf("\n");
+ }
+ }
+
+ return 0;
+}
+
+int main(
+ int argc,
+ char **argv
+) {
+ double start_time = get_time();
+
+ #ifdef DEBUG_CAPTURE_NAN
+ feenableexcept(FE_DIVBYZERO | FE_INVALID);
+ #endif
+
+ if (argc < 2)
+ {
+ astcenc_print_shorthelp();
+ return 0;
+ }
+
+ astcenc_operation operation;
+ astcenc_profile profile;
+ int error = parse_commandline_options(argc, argv, operation, profile);
+ if (error)
+ {
+ return 1;
+ }
+
+ switch (operation)
+ {
+ case ASTCENC_OP_HELP:
+ astcenc_print_longhelp();
+ return 0;
+ case ASTCENC_OP_VERSION:
+ astcenc_print_header();
+ return 0;
+ default:
+ break;
+ }
+
+
+ std::string input_filename = argc >= 3 ? argv[2] : "";
+ std::string output_filename = argc >= 4 ? argv[3] : "";
+
+ if (input_filename.empty())
+ {
+ printf("ERROR: Input file not specified\n");
+ return 1;
+ }
+
+ if (output_filename.empty())
+ {
+ printf("ERROR: Output file not specified\n");
+ return 1;
+ }
+
+ // TODO: Handle RAII resources so they get freed when out of scope
+ // Load the compressed input file if needed
+
+ // This has to come first, as the block size is in the file header
+ astc_compressed_image image_comp;
+ if (operation & ASTCENC_STAGE_LD_COMP)
+ {
+ error = load_cimage(input_filename.c_str(), image_comp);
+ if (error)
+ {
+ return 1;
+ }
+ }
+
+ astcenc_config config;
+ error = init_astcenc_config(argc, argv, profile, operation, image_comp, config);
+ if (error)
+ {
+ printf("ERROR: Astcenc configuration initialization failed.\n");
+ return 1;
+ }
+
+ // Initialize cli_config_options with default values
+ cli_config_options cli_config { 0, 1, false, false, false, -10, 10,
+ { ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A },
+ { ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A } };
+
+ error = edit_astcenc_config(argc, argv, operation, cli_config, config);
+ if (error)
+ {
+ printf("ERROR: Astcenc configuration initialization failed.\n");
+ return 1;
+ }
+
+ int padding = MAX(config.v_rgba_radius, config.a_scale_radius);
+ astcenc_image* image_uncomp_in = nullptr ;
+ unsigned int image_uncomp_in_num_chan = 0;
+ bool image_uncomp_in_is_hdr = false;
+ astcenc_image* image_decomp_out = nullptr;
+
+ // TODO: Handle RAII resources so they get freed when out of scope
+ astcenc_error codec_status;
+ astcenc_context* codec_context;
+
+ codec_status = astcenc_context_alloc(config, cli_config.thread_count, &codec_context);
+ if (codec_status != ASTCENC_SUCCESS)
+ {
+ printf("ERROR: Codec context alloc failed: %s\n", astcenc_get_error_string(codec_status));
+ return 1;
+ }
+
+ // Load the uncompressed input file if needed
+ if (operation & ASTCENC_STAGE_LD_NCOMP)
+ {
+ image_uncomp_in = load_uncomp_file(input_filename.c_str(), cli_config.array_size, padding,
+ cli_config.y_flip, image_uncomp_in_is_hdr, image_uncomp_in_num_chan);
+ if (!image_uncomp_in)
+ {
+ printf ("ERROR: Failed to load uncompressed image file\n");
+ return 1;
+ }
+
+ if (!cli_config.silentmode)
+ {
+ printf("Source image\n");
+ printf("============\n\n");
+ printf(" Source: %s\n", input_filename.c_str());
+ printf(" Color profile: %s\n", image_uncomp_in_is_hdr ? "HDR" : "LDR");
+ if (image_uncomp_in->dim_z > 1)
+ {
+ printf(" Dimensions: 3D, %ux%ux%u\n",
+ image_uncomp_in->dim_x, image_uncomp_in->dim_y, image_uncomp_in->dim_z);
+ }
+ else
+ {
+ printf(" Dimensions: 2D, %ux%u\n",
+ image_uncomp_in->dim_x, image_uncomp_in->dim_y);
+ }
+ printf(" Channels: %d\n\n", image_uncomp_in_num_chan);
+ }
+ }
+
+ double start_coding_time = get_time();
+
+ // Compress an image
+ if (operation & ASTCENC_STAGE_COMPRESS)
+ {
+ unsigned int blocks_x = (image_uncomp_in->dim_x + config.block_x - 1) / config.block_x;
+ unsigned int blocks_y = (image_uncomp_in->dim_y + config.block_y - 1) / config.block_y;
+ unsigned int blocks_z = (image_uncomp_in->dim_z + config.block_z - 1) / config.block_z;
+ size_t buffer_size = blocks_x * blocks_y * blocks_z * 16;
+ uint8_t* buffer = new uint8_t[buffer_size];
+
+ codec_status = astcenc_compress_image(codec_context, *image_uncomp_in, cli_config.swz_encode,
+ buffer, buffer_size, 0);
+ if (codec_status != ASTCENC_SUCCESS)
+ {
+ printf("ERROR: Codec compress failed: %s\n", astcenc_get_error_string(codec_status));
+ return 1;
+ }
+
+ image_comp.block_x = config.block_x;
+ image_comp.block_y = config.block_y;
+ image_comp.block_z = config.block_z;
+ image_comp.dim_x = image_uncomp_in->dim_x;
+ image_comp.dim_y = image_uncomp_in->dim_y;
+ image_comp.dim_z = image_uncomp_in->dim_z;
+ image_comp.data = buffer;
+ }
+
+ // Decompress an image
+ if (operation & ASTCENC_STAGE_DECOMPRESS)
+ {
+ int out_bitness = get_output_filename_enforced_bitness(output_filename.c_str());
+ if (out_bitness == -1)
+ {
+ bool is_hdr = (config.profile == ASTCENC_PRF_HDR) || (config.profile == ASTCENC_PRF_HDR_RGB_LDR_A);
+ out_bitness = is_hdr ? 16 : 8;
+ }
+
+ image_decomp_out = alloc_image(
+ out_bitness, image_comp.dim_x, image_comp.dim_y, image_comp.dim_z, 0);
+
+ // TODO: Pass through data len to avoid out-of-bounds reads
+ codec_status = astcenc_decompress_image(codec_context, image_comp.data, 0,
+ *image_decomp_out, cli_config.swz_decode, 0);
+ if (codec_status != ASTCENC_SUCCESS)
+ {
+ printf("ERROR: Codec decompress failed: %s\n", astcenc_get_error_string(codec_status));
+ return 1;
+ }
+ }
+
+ double end_coding_time = get_time();
+
+ // Print metrics in comparison mode
+ if (operation & ASTCENC_STAGE_COMPARE)
+ {
+ compute_error_metrics(image_uncomp_in_is_hdr, image_uncomp_in_num_chan, image_uncomp_in,
+ image_decomp_out, cli_config.low_fstop, cli_config.high_fstop);
+ }
+
+ // Store compressed image
+ if (operation & ASTCENC_STAGE_ST_COMP)
+ {
+ error = store_cimage(image_comp, output_filename.c_str());
+ if (error)
+ {
+ printf ("ERROR: Failed to store compressed image\n");
+ return 1;
+ }
+ }
+
+ // Store decompressed image
+ if (operation & ASTCENC_STAGE_ST_NCOMP)
+ {
+ int store_result = -1;
+ const char *format_string = "";
+
+ store_result = store_ncimage(image_decomp_out, output_filename.c_str(),
+ &format_string, cli_config.y_flip);
+ if (store_result < 0)
+ {
+ printf("ERROR: Failed to write output image %s\n", output_filename.c_str());
+ return 1;
+ }
+ }
+
+ free_image(image_uncomp_in);
+ free_image(image_decomp_out);
+ astcenc_context_free(codec_context);
+
+ delete[] image_comp.data;
+
+ double end_time = get_time();
+
+ if ((operation & ASTCENC_STAGE_COMPARE) || (!cli_config.silentmode))
+ {
+ printf("Coding time\n");
+ printf("===========\n\n");
+ printf(" Total time: %6.2f s\n", end_time - start_time);
+ printf(" Coding time: %6.2f s\n", end_coding_time - start_coding_time);
+ }
+
+ return 0;
+}
diff --git a/Source/astc_toplevel_help.cpp b/Source/astcenccli_toplevel_help.cpp
similarity index 96%
rename from Source/astc_toplevel_help.cpp
rename to Source/astcenccli_toplevel_help.cpp
index a1ba17e..d647c4e 100644
--- a/Source/astc_toplevel_help.cpp
+++ b/Source/astcenccli_toplevel_help.cpp
@@ -19,7 +19,7 @@
* @brief Functions for printing build info and help messages.
*/
-#include "astc_codec_internals.h"
+#include "astcenccli_internal.h"
const char *astcenc_copyright_string =
R"(ASTC codec v2.0.alpha, %u-bit %s%s
@@ -78,7 +78,6 @@ SYNOPSIS
astcenc {-cl|-cs|-ch|-cH} [options]
astcenc {-dl|-ds|-dh|-dH} [options]
astcenc {-tl|-ts|-th|-tH} [options]
- astcenc {-compare} [options]
DESCRIPTION
astcenc compresses image files into the Adaptive Scalable Texture
@@ -136,9 +135,9 @@ COMPRESSION
5x4x4: 1.60 bpp 6x6x6: 0.59 bpp
The quality preset configures the quality-performance tradeoff for
- the compressor; more complete searches of the available search
- space improve image quality at the expense of compression time.
- Available presets include:
+ the compressor; more complete searches of the search space improve
+ image quality at the expense of compression time. The available
+ presets are:
-fast
-medium
@@ -212,11 +211,11 @@ ADVANCED COMPRESSION
These options provide low-level control of the codec error metric
computation, used to determine what good compression looks like.
- -v
+ -v
Compute the per-texel relative error weighting for the RGB color
channels as follows:
- weight = 1 / ( + * average^2 + * stdev^2)
+ weight = 1 / ( + * mean^2 + * stdev^2)
The argument specifies the pixel radius of the
neighborhood over which the average and standard deviation are
@@ -235,7 +234,7 @@ ADVANCED COMPRESSION
e.g. a power of 0.5 causes the codec to take the square root
of every input pixel value.
- -va
+ -va
Compute the per-texel relative error weighting for the alpha
channel, when used in conjunction with -v. See documentation for
-v for parameter documentation.
@@ -362,11 +361,14 @@ ADVANCED COMPRESSION
Convert input images from sRGB to linear RGB before compression,
and output images from linear RGB to sRGB after decompression.
For compression, the transform is applied after any swizzle; for
- decode, the transform is applied before any swizzle.
+ decode, the transform is applied before any swizzle. Note that
+ using this option in a test mode (-t*) will have no obvious
+ effect as the image will be converted twice, although some image
+ precision loss may occur.
Note that this switch is only intended for diagnostic purposes;
real use cases should directly compress/decompress sRGB data
- using the ASTC LDR sRGB format, using the -cs, -ds, and -ts
+ using the LDR sRGB profile, using the -cs, -ds, and -ts
operation modes. This preserves more perceptual image quality.
-yflip
@@ -474,17 +476,17 @@ DECOMPRESSION FILE FORMATS
// print version and basic build information
void astcenc_print_header()
{
-#if (ASTC_AVX == 2)
+#if (ASTCENC_AVX == 2)
const char* simdtype = "avx2";
-#elif (ASTC_SSE == 42)
- const char* simdtype = "sse42";
-#elif (ASTC_SSE == 20)
+#elif (ASTCENC_SSE == 42)
+ const char* simdtype = "sse4.2";
+#elif (ASTCENC_SSE == 20)
const char* simdtype = "sse2";
#else
const char* simdtype = "unknown";
#endif
-#if (ASTC_POPCNT == 1)
+#if (ASTCENC_POPCNT == 1)
const char* pcnttype = "+popcnt";
#else
const char* pcnttype = "";
diff --git a/Test/astc_test_functional.py b/Test/astc_test_functional.py
index 662a7b8..42f8318 100644
--- a/Test/astc_test_functional.py
+++ b/Test/astc_test_functional.py
@@ -105,7 +105,7 @@ ASTCENC_TEST_PATTERN_HDR = {
"BR": (0.25, 0.75, 0.00, 0.87)
}
-LDR_RGB_PSNR_PATTERN = re.compile(r"PSNR \(LDR-RGB\): (.*) dB")
+LDR_RGB_PSNR_PATTERN = re.compile(r"\s*PSNR \(LDR-RGB\): (.*) dB")
class CLITestBase(unittest.TestCase):
@@ -488,7 +488,10 @@ class CLIPTest(CLITestBase):
# Emit debug logging if needed
if ASTCENC_CLI_ALWAYS or (error and ASTCENC_CLI_ON_ERROR):
- print(" ".join(command))
+ # Format for shell replay
+ print("\n" + " ".join(command))
+ # Format for script command list replay
+ print("\n" + ", ".join(("\"%s\"" % x for x in command)))
if ASTCENC_LOG_ALWAYS or (error and ASTCENC_LOG_ON_ERROR):
print(result.stdout)
@@ -1342,7 +1345,7 @@ class CLIPTest(CLITestBase):
# Test time should get slower with fewer threads
self.assertGreater(testTime, refTime)
- def test_linearize_srgb1(self):
+ def test_linearize_srgb_compress(self):
"""
Test linearize srgb on compression.
@@ -1376,7 +1379,7 @@ class CLIPTest(CLITestBase):
self.assertColorSame(refColors[:3], srgbColors[:3], threshold=0.05)
self.assertColorSame(refColors[3:], srgbColors[3:], threshold=0.0)
- def test_linearize_srgb2(self):
+ def test_linearize_srgb_decompress(self):
"""
Test linearize srgb on decompression.
@@ -1410,13 +1413,13 @@ class CLIPTest(CLITestBase):
self.assertColorSame(refColors[:3], linColors[:3], threshold=0.05)
self.assertColorSame(refColors[3:], linColors[3:], threshold=0.0)
- def test_linearize_srgb3(self):
+ def test_linearize_srgb_roundtrip(self):
"""
Test linearize srgb on round-trip.
- This should behave the same as linearizing with compression only; i.e.
- we convert to linear before compression, but we do NOT sRGB encode the
- output after decompression.
+ This linearizes on input, and converts back to sRGB on output, so
+ overall no conversion should occur. There may be some precision
+ losses however.
"""
inputFile = "./Test/Data/Tiles/ldr.png"
decompFile = self.get_tmp_image_path("LDR", "decomp")
@@ -1433,11 +1436,10 @@ class CLIPTest(CLITestBase):
img = tli.Image(decompFile)
testColors = img.get_colors((7, 7))
- srgbColors = self.to_srgb_color(testColors)
# Test we get a match within 5% on the RGB channels, exact on alpha
- self.assertColorSame(refColors[:3], srgbColors[:3], threshold=0.05)
- self.assertColorSame(refColors[3:], srgbColors[3:], threshold=0.0)
+ self.assertColorSame(refColors[:3], testColors[:3], threshold=0.0)
+ self.assertColorSame(refColors[3:], testColors[3:], threshold=0.0)
def test_silent(self):
"""
@@ -1507,7 +1509,10 @@ class CLINTest(CLITestBase):
badResult = (error == expectPass) or (rcode < 0)
if ASTCENC_CLI_ALWAYS or (badResult and ASTCENC_CLI_ON_ERROR_NEG):
- print(" ".join(command))
+ # Format for shell replay
+ print("\n" + " ".join(command))
+ # Format for script command list replay
+ print("\n" + ", ".join(("\"%s\"" % x for x in command)))
if ASTCENC_LOG_ALWAYS or (badResult and ASTCENC_LOG_ON_ERROR_NEG):
print(result.stdout)
@@ -1525,10 +1530,7 @@ class CLINTest(CLITestBase):
# Otherwise just assert that we got an error log, and some positive
# return code value was returned
-
- # TODO: Disabled until we fix GitHub issue #100
- # self.assertIn("ERROR", result.stdout)
-
+ self.assertIn("ERROR", result.stdout)
self.assertGreater(rcode, 0, "Exec did not fail as expected")
def exec_with_omit(self, command, startOmit):
@@ -1842,18 +1844,6 @@ class CLINTest(CLITestBase):
self.exec(command)
- def test_compare_missing(self):
- """
- Test -compare with missing arguments.
- """
- command = [
- self.binary, "-compare",
- self.get_ref_image_path("LDR", "input", "A"),
- self.get_ref_image_path("LDR", "input", "A")]
-
- # Run the command, incrementally omitting arguments
- self.exec_with_omit(command, 2)
-
def test_cl_v_missing_args(self):
"""
Test -cl with -v and missing arguments.
diff --git a/Test/astc_test_image.py b/Test/astc_test_image.py
index 483e19e..756bf7d 100644
--- a/Test/astc_test_image.py
+++ b/Test/astc_test_image.py
@@ -264,11 +264,6 @@ def get_encoder_params(encoderName, imageSet):
name = "reference-prototype"
outDir = "Test/Images/%s" % imageSet
refName = None
- elif encoderName == "ref-intelispc":
- encoder = te.EncoderISPC()
- name = "reference-intelispc"
- outDir = "Test/Images/%s" % imageSet
- refName = None
else:
encoder = te.Encoder2x(encoderName)
name = "develop-%s" % encoderName
@@ -287,7 +282,7 @@ def parse_command_line():
"""
parser = argparse.ArgumentParser()
- refcoders = ["ref-1.7", "ref-2.0", "ref-prototype", "ref-intelispc"]
+ refcoders = ["ref-1.7", "ref-2.0", "ref-prototype"]
testcoders = ["nointrin", "sse2", "sse4.2", "avx2"]
coders = refcoders + testcoders + ["all"]
parser.add_argument("--encoder", dest="encoders", default="avx2",
diff --git a/Test/testlib/encoder.py b/Test/testlib/encoder.py
index 4dd4cbd..7c46cdf 100644
--- a/Test/testlib/encoder.py
+++ b/Test/testlib/encoder.py
@@ -270,18 +270,18 @@ class Encoder2x(EncoderBase):
def get_psnr_pattern(self, image):
if image.colorProfile != "hdr":
if image.colorFormat != "rgba":
- patternPSNR = r"PSNR \(LDR-RGB\):\s*([0-9.]*) dB"
+ patternPSNR = r"\s*PSNR \(LDR-RGB\):\s*([0-9.]*) dB"
else:
- patternPSNR = r"PSNR \(LDR-RGBA\):\s*([0-9.]*) dB"
+ patternPSNR = r"\s*PSNR \(LDR-RGBA\):\s*([0-9.]*) dB"
else:
- patternPSNR = r"mPSNR \(RGB\)(?: \[.*?\] )?:\s*([0-9.]*) dB.*"
+ patternPSNR = r"\s*mPSNR \(RGB\)(?: \[.*?\] )?:\s*([0-9.]*) dB.*"
return patternPSNR
def get_total_time_pattern(self):
- return r"Total time:\s*([0-9.]*) s"
+ return r"\s*Total time:\s*([0-9.]*) s"
def get_coding_time_pattern(self):
- return r"Coding time:\s*([0-9.]*) s"
+ return r"\s*Coding time:\s*([0-9.]*) s"
class Encoder1x(EncoderBase):
@@ -379,127 +379,3 @@ class EncoderProto(Encoder1x):
assert os.name != 'nt', "Windows builds not available"
binary = "./Binaries/Prototype/astcenc"
super().__init__(binary)
-
-
-class EncoderISPC(EncoderBase):
- """
- This class wraps the Intel ISPC compressor, which is widely used due to its
- good performance (although with worse quality).
-
- Note that the compressor does not support all features of ASTC (only a
- subset of 2D block sizes, only LDR color profile), and doesn't support
- decode at all. For round-trip analysis we use `astcenc` to provide the
- decompression and image comparisons.
- """
-
- VERSION = "IntelISPC"
-
- def __init__(self):
- """
- Create a new encoder instance.
- """
- binary = "./Binaries/ispc/astcispc"
- super().__init__("intel-ispc", None, binary)
- self.decodeBinary = "./Binaries/1.7/astcenc"
-
- def get_psnr_pattern(self, image):
- if image.colorFormat != "rgba":
- patternPSNR = r"PSNR \(LDR-RGB\):\s*([0-9.]*) dB"
- else:
- patternPSNR = r"PSNR \(LDR-RGBA\):\s*([0-9.]*) dB"
-
- return patternPSNR
-
- def get_total_time_pattern(self):
- return r"Total time:\s*([0-9.]*) s"
-
- def get_coding_time_pattern(self):
- return r"Coding time:\s*([0-9.]*) s"
-
- def execute(self, command):
- """
- Run a subprocess with the specified command.
-
- Args:
- command (list(str)): The list of command line arguments.
-
- Returns:
- list(str): The output log (stdout) split into lines.
- """
- command = " ".join(command)
- try:
- result = sp.run(command, stdout=sp.PIPE, stderr=sp.PIPE,
- shell=True, check=True, universal_newlines=True)
- except OSError:
- print("ERROR: Test run failed (binary not found)")
- print(" + %s" % command)
- sys.exit(1)
- except sp.CalledProcessError:
- print("ERROR: Test run failed")
- print(" + %s" % command)
- sys.exit(1)
-
- return result.stdout.splitlines()
-
- def run_test(self, image, blockSize, preset, testRuns):
- """
- Run the test N times.
-
- Args:
- image (TestImage): The test image to compress.
- blockSize (str): The block size to use.
- preset (str): Unused - we always use ISPC's slow preset as this
- gives acceptable image quality which is likely to be used.
- testRuns (int): The number of test repeats to run for the image.
-
- Returns:
- tuple(float, float, float): Returns the best results from the N
- test runs, as PSNR (dB), total time (seconds), and coding time
- (seconds).
- """
- dstDir = os.path.dirname(image.outFilePath)
- dstFile = os.path.basename(image.outFilePath)
- dstDir = os.path.join(dstDir, self.name, blockSize)
- dstPath = os.path.join(dstDir, dstFile)
-
- compressCommand = [
- "env",
- "LD_LIBRARY_PATH=./Binaries/ispc",
- self.binary,
- image.filePath,
- dstPath + ".astc",
- blockSize
- ]
-
- decompressCommand = [
- self.decodeBinary,
- "-dl",
- dstPath + ".astc",
- dstPath + ".tga"
- ]
-
- compareCommand = [
- self.decodeBinary,
- "-compare",
- image.filePath,
- dstPath + ".tga",
- "-showpsnr"
- ]
-
- os.makedirs(dstDir, exist_ok=True)
-
- # Execute test runs
- bestPSNR = 0
- bestTTime = sys.float_info.max
- bestCTime = sys.float_info.max
- for _ in range(0, testRuns):
- output = self.execute(compressCommand)
- self.execute(decompressCommand)
- output += self.execute(compareCommand)
-
- output = self.parse_output(image, output)
- bestPSNR = max(bestPSNR, output[0])
- bestTTime = min(bestTTime, output[1])
- bestCTime = min(bestCTime, output[2])
-
- return (bestPSNR, bestTTime, bestCTime)