From 5837e1fe3fe6637137596ef8723f882179c742d5 Mon Sep 17 00:00:00 2001 From: BlueCube3310 <53150244+BlueCube3310@users.noreply.github.com> Date: Wed, 6 Dec 2023 13:57:22 +0100 Subject: [PATCH] Improve normal map VRAM Compression with RGTC --- modules/etcpak/SCsub | 1 + modules/etcpak/image_compress_etcpak.cpp | 13 ++- modules/etcpak/image_compress_etcpak.h | 2 + thirdparty/etcpak/ProcessRgtc.cpp | 106 +++++++++++++++++++++++ thirdparty/etcpak/ProcessRgtc.hpp | 14 +++ 5 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 thirdparty/etcpak/ProcessRgtc.cpp create mode 100644 thirdparty/etcpak/ProcessRgtc.hpp diff --git a/modules/etcpak/SCsub b/modules/etcpak/SCsub index 2d3b69be75fd..3a4bff8e8728 100644 --- a/modules/etcpak/SCsub +++ b/modules/etcpak/SCsub @@ -13,6 +13,7 @@ thirdparty_dir = "#thirdparty/etcpak/" thirdparty_sources = [ "Dither.cpp", "ProcessDxtc.cpp", + "ProcessRgtc.cpp", "ProcessRGB.cpp", "Tables.cpp", ] diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp index 14cce2686c66..f528b92cf22a 100644 --- a/modules/etcpak/image_compress_etcpak.cpp +++ b/modules/etcpak/image_compress_etcpak.cpp @@ -35,6 +35,7 @@ #include #include +#include EtcpakType _determine_etc_type(Image::UsedChannels p_channels) { switch (p_channels) { @@ -62,9 +63,9 @@ EtcpakType _determine_dxt_type(Image::UsedChannels p_channels) { case Image::USED_CHANNELS_LA: return EtcpakType::ETCPAK_TYPE_DXT5; case Image::USED_CHANNELS_R: - return EtcpakType::ETCPAK_TYPE_DXT5; + return EtcpakType::ETCPAK_TYPE_RGTC_R; case Image::USED_CHANNELS_RG: - return EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG; + return EtcpakType::ETCPAK_TYPE_RGTC_RG; case Image::USED_CHANNELS_RGB: return EtcpakType::ETCPAK_TYPE_DXT1; case Image::USED_CHANNELS_RGBA: @@ -127,6 +128,10 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img) { r_img->convert_rg_to_ra_rgba8(); } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5) { target_format = Image::FORMAT_DXT5; + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_RGTC_R) { + target_format = Image::FORMAT_RGTC_R; + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_RGTC_RG) { + target_format = Image::FORMAT_RGTC_RG; } else { ERR_FAIL_MSG("Invalid or unsupported etcpak compression format, not ETC or DXT."); } @@ -229,6 +234,10 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img) { CompressDxt1Dither(src_mip_read, dest_mip_write, blocks, mip_w); } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5 || p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) { CompressDxt5(src_mip_read, dest_mip_write, blocks, mip_w); + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_RGTC_RG) { + CompressRgtcRG(src_mip_read, dest_mip_write, blocks, mip_w); + } else if (p_compresstype == EtcpakType::ETCPAK_TYPE_RGTC_R) { + CompressRgtcR(src_mip_read, dest_mip_write, blocks, mip_w); } else { ERR_FAIL_MSG("etcpak: Invalid or unsupported compression format."); } diff --git a/modules/etcpak/image_compress_etcpak.h b/modules/etcpak/image_compress_etcpak.h index ff267631a6a4..ff8bb635b40f 100644 --- a/modules/etcpak/image_compress_etcpak.h +++ b/modules/etcpak/image_compress_etcpak.h @@ -41,6 +41,8 @@ enum class EtcpakType { ETCPAK_TYPE_DXT1, ETCPAK_TYPE_DXT5, ETCPAK_TYPE_DXT5_RA_AS_RG, + ETCPAK_TYPE_RGTC_R, + ETCPAK_TYPE_RGTC_RG, }; void _compress_etc1(Image *r_img); diff --git a/thirdparty/etcpak/ProcessRgtc.cpp b/thirdparty/etcpak/ProcessRgtc.cpp new file mode 100644 index 000000000000..3a283b743bd0 --- /dev/null +++ b/thirdparty/etcpak/ProcessRgtc.cpp @@ -0,0 +1,106 @@ +// -- GODOT start -- + +#include "ForceInline.hpp" +#include "ProcessRgtc.hpp" + +#include +#include + +static const uint8_t AlphaIndexTable[8] = { 1, 7, 6, 5, 4, 3, 2, 0 }; + +static etcpak_force_inline uint64_t ProcessAlpha( const uint8_t* src ) +{ + uint8_t solid8 = *src; + uint16_t solid16 = uint16_t( solid8 ) | ( uint16_t( solid8 ) << 8 ); + uint32_t solid32 = uint32_t( solid16 ) | ( uint32_t( solid16 ) << 16 ); + uint64_t solid64 = uint64_t( solid32 ) | ( uint64_t( solid32 ) << 32 ); + if( memcmp( src, &solid64, 8 ) == 0 && memcmp( src+8, &solid64, 8 ) == 0 ) + { + return solid8; + } + + uint8_t min = src[0]; + uint8_t max = min; + for( int i=1; i<16; i++ ) + { + const auto v = src[i]; + if( v > max ) max = v; + else if( v < min ) min = v; + } + + uint32_t range = ( 8 << 13 ) / ( 1 + max - min ); + uint64_t data = 0; + for( int i=0; i<16; i++ ) + { + uint8_t a = src[i] - min; + uint64_t idx = AlphaIndexTable[( a * range ) >> 13]; + data |= idx << (i*3); + } + + return max | ( min << 8 ) | ( data << 16 ); +} + +void CompressRgtcR(const uint32_t *src, uint64_t *dst, uint32_t blocks, size_t width) +{ + int i = 0; + auto ptr = dst; + do + { + uint32_t rgba[4 * 4]; + uint8_t r[4 * 4]; + + auto tmp = (char *)rgba; + memcpy(tmp, src + width * 0, 4 * 4); + memcpy(tmp + 4 * 4, src + width * 1, 4 * 4); + memcpy(tmp + 8 * 4, src + width * 2, 4 * 4); + memcpy(tmp + 12 * 4, src + width * 3, 4 * 4); + src += 4; + if (++i == width / 4) + { + src += width * 3; + i = 0; + } + + for (int i = 0; i < 16; i++) + { + r[i] = rgba[i] & 0x000000FF; + } + *ptr++ = ProcessAlpha(r); + } + while (--blocks); +} + +void CompressRgtcRG(const uint32_t *src, uint64_t *dst, uint32_t blocks, size_t width) +{ + int i = 0; + auto ptr = dst; + do + { + uint32_t rgba[4 * 4]; + uint8_t r[4 * 4]; + uint8_t g[4 * 4]; + + auto tmp = (char *)rgba; + memcpy(tmp, src + width * 0, 4 * 4); + memcpy(tmp + 4 * 4, src + width * 1, 4 * 4); + memcpy(tmp + 8 * 4, src + width * 2, 4 * 4); + memcpy(tmp + 12 * 4, src + width * 3, 4 * 4); + src += 4; + if (++i == width / 4) + { + src += width * 3; + i = 0; + } + + for (int i = 0; i < 16; i++) + { + r[i] = rgba[i] & 0x000000FF; + g[i] = (rgba[i] & 0x0000FF00) >> 8; + } + *ptr++ = ProcessAlpha(r); + *ptr++ = ProcessAlpha(g); + } + while (--blocks); +} + +// -- GODOT end -- diff --git a/thirdparty/etcpak/ProcessRgtc.hpp b/thirdparty/etcpak/ProcessRgtc.hpp new file mode 100644 index 000000000000..0905b7d9ad06 --- /dev/null +++ b/thirdparty/etcpak/ProcessRgtc.hpp @@ -0,0 +1,14 @@ +// -- GODOT start -- + +#ifndef __PROCESSRGTC_HPP__ +#define __PROCESSRGTC_HPP__ + +#include +#include + +void CompressRgtcR(const uint32_t *src, uint64_t *dst, uint32_t blocks, size_t width); +void CompressRgtcRG(const uint32_t *src, uint64_t *dst, uint32_t blocks, size_t width); + +#endif + +// -- GODOT end --