Skip to content

Support KTX on big-endian systems #564

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 27 additions & 33 deletions Source/astcenccli_image_load_store.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@
#include "ThirdParty/stb_image_write.h"
#include "ThirdParty/tinyexr.h"

/**
* @brief Reverse the bytes in a uint32_t value.
*/
static uint32_t reverse_bytes_u32(
uint32_t val
) {
return ((val >> 24) & 0x000000FF) |
((val >> 8) & 0x0000FF00) |
((val << 8) & 0x00FF0000) |
((val << 24) & 0xFF000000);
}

/**
* @brief Determine the output file name to use for a sliced image write.
*
Expand Down Expand Up @@ -656,18 +668,6 @@ static void switch_endianness4(
}
}

/**
* @brief Swap endianness of a u32 value.
*
* @param v The data to convert.
*
* @return The converted value.
*/
static uint32_t u32_byterev(uint32_t v)
{
return (v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24);
}

/*
Notes about KTX:

Expand Down Expand Up @@ -904,7 +904,7 @@ static uint8_t ktx_magic[12] {

static void ktx_header_switch_endianness(ktx_header * kt)
{
#define REV(x) kt->x = u32_byterev(kt->x)
#define REV(x) kt->x = reverse_bytes_u32(kt->x)
REV(endianness);
REV(gl_type);
REV(gl_type_size);
Expand Down Expand Up @@ -961,11 +961,11 @@ static astcenc_image* load_ktx_uncompressed_image(
return nullptr;
}

int switch_endianness = 0;
bool switch_endianness = false;
if (hdr.endianness == 0x01020304)
{
ktx_header_switch_endianness(&hdr);
switch_endianness = 1;
switch_endianness = true;
}

if (hdr.gl_type == 0 || hdr.gl_format == 0)
Expand Down Expand Up @@ -1191,7 +1191,7 @@ static astcenc_image* load_ktx_uncompressed_image(

if (switch_endianness)
{
specified_bytes_of_surface = u32_byterev(specified_bytes_of_surface);
specified_bytes_of_surface = reverse_bytes_u32(specified_bytes_of_surface);
}

// read the surface
Expand Down Expand Up @@ -1346,7 +1346,7 @@ bool load_ktx_compressed_image(

if (switch_endianness)
{
data_len = u32_byterev(data_len);
data_len = reverse_bytes_u32(data_len);
}

// Read the data
Expand Down Expand Up @@ -1409,6 +1409,10 @@ bool store_ktx_compressed_image(
hdr.number_of_mipmap_levels = 1;
hdr.bytes_of_key_value_data = 0;

#if defined(ASTCENC_BIG_ENDIAN)
ktx_header_switch_endianness(&hdr);
#endif

size_t expected = sizeof(ktx_header) + 4 + img.data_len;
size_t actual = 0;

Expand All @@ -1418,8 +1422,13 @@ bool store_ktx_compressed_image(
return true;
}

uint32_t data_len = static_cast<uint32_t>(img.data_len);
#if defined(ASTCENC_BIG_ENDIAN)
data_len = reverse_bytes_u32(data_len);
#endif

actual += fwrite(&hdr, 1, sizeof(ktx_header), wf);
actual += fwrite(&img.data_len, 1, 4, wf);
actual += fwrite(&data_len, 1, sizeof(uint32_t), wf);
actual += fwrite(img.data, 1, img.data_len, wf);
fclose(wf);

Expand Down Expand Up @@ -1746,21 +1755,6 @@ struct dds_header_dx10
#define DDS_MAGIC 0x20534444
#define DX10_MAGIC 0x30315844


#if defined(ASTCENC_BIG_ENDIAN)
/**
* @brief Reverse the bytes in a uint32_t value.
*/
static uint32_t reverse_bytes_u32(
uint32_t val
) {
return ((val >> 24) & 0x000000FF) |
((val >> 8) & 0x0000FF00) |
((val << 8) & 0x00FF0000) |
((val << 24) & 0xFF000000);
}
#endif

/**
* @brief Load an uncompressed DDS image using the local custom loader.
*
Expand Down
3 changes: 2 additions & 1 deletion Source/astcenccli_toplevel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2267,7 +2267,8 @@ int astcenc_main(

if (work.error != ASTCENC_SUCCESS)
{
print_error("ERROR: Codec decompress failed: %s\n", astcenc_get_error_string(codec_status));
print_error("ERROR: Codec decompress failed: %s\n",
astcenc_get_error_string(work.error));
return 1;
}
}
Expand Down