From 5d87e9b616b29c284d18f150bad442dd94ee896e Mon Sep 17 00:00:00 2001 From: Dario Date: Thu, 15 Jan 2026 12:36:09 -0300 Subject: [PATCH] Add support for ASTC 6x6 and high quality compression profiles. --- core/io/image.compat.inc | 21 +++++ core/io/image.cpp | 88 +++++++++++++------ core/io/image.h | 30 +++++-- doc/classes/Image.xml | 33 +++++-- .../ResourceImporterLayeredTexture.xml | 8 ++ doc/classes/ResourceImporterTexture.xml | 8 ++ drivers/gles3/storage/texture_storage.cpp | 20 +++++ .../metal/rendering_device_driver_metal.cpp | 3 +- .../resource_importer_layered_texture.cpp | 22 +++-- .../resource_importer_layered_texture.h | 3 +- editor/import/resource_importer_texture.cpp | 28 +++--- editor/import/resource_importer_texture.h | 4 +- .../scene/texture/texture_editor_plugin.cpp | 4 +- .../4.7-stable/GH-115003.txt | 9 ++ modules/astcenc/image_compress_astcenc.cpp | 63 +++++++++---- modules/astcenc/image_compress_astcenc.h | 2 +- modules/cvtt/image_compress_cvtt.cpp | 3 +- modules/ktx/texture_loader_ktx.cpp | 15 +++- .../resources/portable_compressed_texture.cpp | 2 +- .../storage_rd/texture_storage.cpp | 65 ++++++++++++++ servers/rendering/rendering_device.cpp | 15 ++-- .../rendering/rendering_device_commons.cpp | 31 ++++--- servers/rendering/rendering_device_commons.h | 2 +- 23 files changed, 368 insertions(+), 111 deletions(-) create mode 100644 misc/extension_api_validation/4.7-stable/GH-115003.txt diff --git a/core/io/image.compat.inc b/core/io/image.compat.inc index c60ff9382a..b62ce5dfe6 100644 --- a/core/io/image.compat.inc +++ b/core/io/image.compat.inc @@ -32,6 +32,25 @@ #include "core/object/class_db.h" +static Image::CompressProfile _astc_format_to_compress_profile(Image::ASTCFormat p_format) { + switch (p_format) { + case Image::ASTC_FORMAT_4x4: + return Image::COMPRESS_PROFILE_MAX_QUALITY; + case Image::ASTC_FORMAT_8x8: + return Image::COMPRESS_PROFILE_MAX_COMPRESSION; + default: + return Image::COMPRESS_PROFILE_AUTOMATIC; + } +} + +Error Image::_compress_bind_compat_115003(CompressMode p_mode, CompressSource p_source, ASTCFormat p_format) { + return compress(p_mode, p_source, _astc_format_to_compress_profile(p_format)); +} + +Error Image::_compress_from_channels_compat_115003(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_format) { + return compress_from_channels(p_mode, p_channels, _astc_format_to_compress_profile(p_format)); +} + Vector Image::_save_exr_to_buffer_bind_compat_117800(bool p_grayscale) const { return save_exr_to_buffer(p_grayscale); } @@ -41,6 +60,8 @@ Error Image::_save_exr_bind_compat_117800(const String &p_path, bool p_grayscale } void Image::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("compress", "mode", "source", "astc_format"), &Image::_compress_bind_compat_115003, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(ASTC_FORMAT_4x4)); + ClassDB::bind_compatibility_method(D_METHOD("compress_from_channels", "mode", "channels", "astc_format"), &Image::_compress_from_channels_compat_115003, DEFVAL(ASTC_FORMAT_4x4)); ClassDB::bind_compatibility_method(D_METHOD("save_exr", "path", "grayscale"), &Image::_save_exr_bind_compat_117800, DEFVAL(false)); ClassDB::bind_compatibility_method(D_METHOD("save_exr_to_buffer", "grayscale"), &Image::_save_exr_to_buffer_bind_compat_117800, DEFVAL(false)); } diff --git a/core/io/image.cpp b/core/io/image.cpp index 93ba6f0c81..6eb3dc6f11 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -88,6 +88,8 @@ const char *Image::format_names[Image::FORMAT_MAX] = { "RG16Int", "RGB16Int", "RGBA16Int", + "ASTC_6x6", + "ASTC_6x6_HDR", }; // External VRAM compression function pointers. @@ -96,7 +98,7 @@ void (*Image::_image_compress_bc_func)(Image *, Image::UsedChannels) = nullptr; void (*Image::_image_compress_bptc_func)(Image *, Image::UsedChannels, Image::BPTCFormat) = nullptr; void (*Image::_image_compress_etc1_func)(Image *) = nullptr; void (*Image::_image_compress_etc2_func)(Image *, Image::UsedChannels) = nullptr; -void (*Image::_image_compress_astc_func)(Image *, Image::ASTCFormat) = nullptr; +void (*Image::_image_compress_astc_func)(Image *, Image::UsedChannels, Image::CompressProfile) = nullptr; Error (*Image::_image_compress_bptc_rd_func)(Image *, Image::UsedChannels, Image::BPTCFormat) = nullptr; Error (*Image::_image_compress_bc_rd_func)(Image *, Image::UsedChannels) = nullptr; @@ -207,6 +209,10 @@ int Image::get_format_pixel_size(Format p_format) { return 1; case FORMAT_ASTC_4x4_HDR: return 1; + case FORMAT_ASTC_6x6: + return 1; + case FORMAT_ASTC_6x6_HDR: + return 1; case FORMAT_ASTC_8x8: return 1; case FORMAT_ASTC_8x8_HDR: @@ -233,6 +239,27 @@ int Image::get_format_pixel_size(Format p_format) { return 0; } +uint64_t Image::get_format_pixels_shifted(Format p_format, uint64_t p_pixels) { + switch (p_format) { + case FORMAT_ASTC_8x8: + case FORMAT_ASTC_8x8_HDR: + return p_pixels >> 2; + case FORMAT_ASTC_6x6: + case FORMAT_ASTC_6x6_HDR: + return (p_pixels * 4) / 9; + case FORMAT_DXT1: + case FORMAT_RGTC_R: + case FORMAT_ETC: + case FORMAT_ETC2_R11: + case FORMAT_ETC2_R11S: + case FORMAT_ETC2_RGB8: + case FORMAT_ETC2_RGB8A1: + return p_pixels >> 1; + default: + return p_pixels; + } +} + void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) { switch (p_format) { case FORMAT_DXT1: @@ -270,6 +297,11 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) { r_w = 4; r_h = 4; } break; + case FORMAT_ASTC_6x6: + case FORMAT_ASTC_6x6_HDR: { + r_w = 6; + r_h = 6; + } break; case FORMAT_ASTC_8x8: case FORMAT_ASTC_8x8_HDR: { r_w = 8; @@ -282,16 +314,6 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) { } } -int Image::get_format_pixel_rshift(Format p_format) { - if (p_format == FORMAT_ASTC_8x8) { - return 2; - } else if (p_format == FORMAT_DXT1 || p_format == FORMAT_RGTC_R || p_format == FORMAT_ETC || p_format == FORMAT_ETC2_R11 || p_format == FORMAT_ETC2_R11S || p_format == FORMAT_ETC2_RGB8 || p_format == FORMAT_ETC2_RGB8A1) { - return 1; - } else { - return 0; - } -} - int Image::get_format_block_size(Format p_format) { switch (p_format) { case FORMAT_DXT1: @@ -324,6 +346,10 @@ int Image::get_format_block_size(Format p_format) { case FORMAT_ASTC_4x4_HDR: { return 4; } + case FORMAT_ASTC_6x6: + case FORMAT_ASTC_6x6_HDR: { + return 6; + } case FORMAT_ASTC_8x8: case FORMAT_ASTC_8x8_HDR: { return 8; @@ -341,7 +367,6 @@ void Image::_get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_ int64_t ofs = 0; int pixel_size = get_format_pixel_size(format); - int pixel_rshift = get_format_pixel_rshift(format); int block = get_format_block_size(format); int minw, minh; get_format_min_pixel_size(format, minw, minh); @@ -353,7 +378,7 @@ void Image::_get_mipmap_offset_and_size(int p_mipmap, int64_t &r_offset, int &r_ int64_t s = bw * bh; s *= pixel_size; - s >>= pixel_rshift; + s = get_format_pixels_shifted(format, s); ofs += s; w = MAX(minw, w >> 1); h = MAX(minh, h >> 1); @@ -1908,7 +1933,6 @@ int64_t Image::_get_dst_image_size(int p_width, int p_height, Format p_format, i int mm = 0; int pixsize = get_format_pixel_size(p_format); - int pixshift = get_format_pixel_rshift(p_format); int block = get_format_block_size(p_format); // Technically, you can still compress up to 1 px no matter the format, so commenting this. @@ -1923,7 +1947,7 @@ int64_t Image::_get_dst_image_size(int p_width, int p_height, Format p_format, i int64_t s = bw * bh; s *= pixsize; - s >>= pixshift; + s = get_format_pixels_shifted(p_format, s); size += s; @@ -2909,7 +2933,7 @@ bool Image::is_compressed() const { } bool Image::is_format_compressed(Format p_format) { - return p_format > FORMAT_RGBE9995 && p_format < FORMAT_R16; + return (p_format >= FORMAT_DXT1 && p_format <= FORMAT_ASTC_8x8_HDR) || (p_format >= FORMAT_ASTC_6x6 && p_format <= FORMAT_ASTC_6x6_HDR); } Error Image::decompress() { @@ -2921,7 +2945,7 @@ Error Image::decompress() { _image_decompress_etc1(this); } else if (format >= FORMAT_ETC2_R11 && format <= FORMAT_ETC2_RA_AS_RG && _image_decompress_etc2) { _image_decompress_etc2(this); - } else if (format >= FORMAT_ASTC_4x4 && format <= FORMAT_ASTC_8x8_HDR && _image_decompress_astc) { + } else if (((format >= FORMAT_ASTC_4x4 && format <= FORMAT_ASTC_8x8_HDR) || (format >= FORMAT_ASTC_6x6 && format <= FORMAT_ASTC_6x6_HDR)) && _image_decompress_astc) { _image_decompress_astc(this); } else { return ERR_UNAVAILABLE; @@ -2942,17 +2966,17 @@ bool Image::can_decompress(const String &p_format_tag) { return false; } -Error Image::compress(CompressMode p_mode, CompressSource p_source, ASTCFormat p_astc_format) { +Error Image::compress(CompressMode p_mode, CompressSource p_source, CompressProfile p_profile) { ERR_FAIL_INDEX_V_MSG(p_mode, COMPRESS_MAX, ERR_INVALID_PARAMETER, "Invalid compress mode."); ERR_FAIL_INDEX_V_MSG(p_source, COMPRESS_SOURCE_MAX, ERR_INVALID_PARAMETER, "Invalid compress source."); - return compress_from_channels(p_mode, detect_used_channels(p_source), p_astc_format); + return compress_from_channels(p_mode, detect_used_channels(p_source), p_profile); } -Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_astc_format) { - return _compress_from_channels(p_mode, p_channels, p_astc_format, BPTC_DETECT); +Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, CompressProfile p_profile) { + return _compress_from_channels(p_mode, p_channels, p_profile, BPTC_DETECT); } -Error Image::_compress_from_channels(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_astc_format, BPTCFormat p_bptc_format) { +Error Image::_compress_from_channels(CompressMode p_mode, UsedChannels p_channels, CompressProfile p_profile, BPTCFormat p_bptc_format) { ERR_FAIL_COND_V(data.is_empty(), ERR_INVALID_DATA); // RenderingDevice only. @@ -3004,7 +3028,7 @@ Error Image::_compress_from_channels(CompressMode p_mode, UsedChannels p_channel } break; case COMPRESS_ASTC: { ERR_FAIL_NULL_V(_image_compress_astc_func, ERR_UNAVAILABLE); - _image_compress_astc_func(this, p_astc_format); + _image_compress_astc_func(this, p_channels, p_profile); } break; case COMPRESS_MAX: { ERR_FAIL_V(ERR_INVALID_PARAMETER); @@ -3895,8 +3919,8 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("is_invisible"), &Image::is_invisible); ClassDB::bind_method(D_METHOD("detect_used_channels", "source"), &Image::detect_used_channels, DEFVAL(COMPRESS_SOURCE_GENERIC)); - ClassDB::bind_method(D_METHOD("compress", "mode", "source", "astc_format"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(ASTC_FORMAT_4x4)); - ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "astc_format"), &Image::compress_from_channels, DEFVAL(ASTC_FORMAT_4x4)); + ClassDB::bind_method(D_METHOD("compress", "mode", "source", "profile"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(COMPRESS_PROFILE_AUTOMATIC)); + ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "profile"), &Image::compress_from_channels, DEFVAL(COMPRESS_PROFILE_AUTOMATIC)); ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress); ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed); @@ -3999,6 +4023,8 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(FORMAT_RG16I); BIND_ENUM_CONSTANT(FORMAT_RGB16I); BIND_ENUM_CONSTANT(FORMAT_RGBA16I); + BIND_ENUM_CONSTANT(FORMAT_ASTC_6x6); + BIND_ENUM_CONSTANT(FORMAT_ASTC_6x6_HDR); BIND_ENUM_CONSTANT(FORMAT_MAX); BIND_ENUM_CONSTANT(INTERPOLATE_NEAREST); @@ -4029,8 +4055,16 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(COMPRESS_SOURCE_SRGB); BIND_ENUM_CONSTANT(COMPRESS_SOURCE_NORMAL); + BIND_ENUM_CONSTANT(COMPRESS_PROFILE_AUTOMATIC); + BIND_ENUM_CONSTANT(COMPRESS_PROFILE_MAX_QUALITY); + BIND_ENUM_CONSTANT(COMPRESS_PROFILE_COMPRESSED); + BIND_ENUM_CONSTANT(COMPRESS_PROFILE_MAX_COMPRESSION); + BIND_ENUM_CONSTANT(COMPRESS_PROFILE_MAX); + +#ifndef DISABLE_DEPRECATED BIND_ENUM_CONSTANT(ASTC_FORMAT_4x4); BIND_ENUM_CONSTANT(ASTC_FORMAT_8x8); +#endif } void Image::normal_map_to_xy() { @@ -4408,6 +4442,10 @@ uint32_t Image::get_format_component_mask(Format p_format) { return rgba; case FORMAT_ASTC_4x4_HDR: return rgba; + case FORMAT_ASTC_6x6: + return rgba; + case FORMAT_ASTC_6x6_HDR: + return rgba; case FORMAT_ASTC_8x8: return rgba; case FORMAT_ASTC_8x8_HDR: diff --git a/core/io/image.h b/core/io/image.h index e6d101b5f0..37820e0915 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -119,6 +119,8 @@ public: FORMAT_RG16I, FORMAT_RGB16I, FORMAT_RGBA16I, + FORMAT_ASTC_6x6, + FORMAT_ASTC_6x6_HDR, FORMAT_MAX }; @@ -144,11 +146,13 @@ public: USED_CHANNELS_RGBA, }; +#ifndef DISABLE_DEPRECATED // ASTC supports block formats other than 4x4. enum ASTCFormat { ASTC_FORMAT_4x4, ASTC_FORMAT_8x8, }; +#endif enum BPTCFormat { BPTC_DETECT, @@ -190,6 +194,14 @@ public: COMPRESS_SOURCE_MAX, }; + enum CompressProfile { + COMPRESS_PROFILE_AUTOMATIC, + COMPRESS_PROFILE_MAX_QUALITY, + COMPRESS_PROFILE_COMPRESSED, + COMPRESS_PROFILE_MAX_COMPRESSION, + COMPRESS_PROFILE_MAX + }; + enum AlphaMode { ALPHA_NONE, ALPHA_BIT, @@ -233,7 +245,7 @@ public: static void (*_image_compress_bptc_func)(Image *, UsedChannels p_channels, BPTCFormat p_bptc_format); static void (*_image_compress_etc1_func)(Image *); static void (*_image_compress_etc2_func)(Image *, UsedChannels p_channels); - static void (*_image_compress_astc_func)(Image *, ASTCFormat p_format); + static void (*_image_compress_astc_func)(Image *, UsedChannels p_channels, CompressProfile p_profile); static Error (*_image_compress_bptc_rd_func)(Image *, UsedChannels p_channels, BPTCFormat p_bptc_format); static Error (*_image_compress_bc_rd_func)(Image *, UsedChannels p_channels); @@ -264,8 +276,11 @@ protected: static void _bind_methods(); #ifndef DISABLE_DEPRECATED + Error _compress_bind_compat_115003(CompressMode p_mode, CompressSource p_source, ASTCFormat p_format); + Error _compress_from_channels_compat_115003(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_format); Vector _save_exr_to_buffer_bind_compat_117800(bool p_grayscale = false) const; Error _save_exr_bind_compat_117800(const String &p_path, bool p_grayscale = false) const; + static void _bind_compatibility_methods(); #endif @@ -393,7 +408,7 @@ public: bool is_invisible() const; static int get_format_pixel_size(Format p_format); - static int get_format_pixel_rshift(Format p_format); + static uint64_t get_format_pixels_shifted(Format p_format, uint64_t p_pixels); static int get_format_block_size(Format p_format); static void get_format_min_pixel_size(Format p_format, int &r_w, int &r_h); @@ -403,10 +418,9 @@ public: static int64_t get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap); static int64_t get_image_mipmap_offset_and_dimensions(int p_width, int p_height, Format p_format, int p_mipmap, int &r_w, int &r_h); - Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, ASTCFormat p_astc_format = ASTC_FORMAT_4x4); - Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_astc_format = ASTC_FORMAT_4x4); - Error _compress_from_channels(CompressMode p_mode, UsedChannels p_channels, ASTCFormat p_astc_format, BPTCFormat p_bptc_format); - + Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, CompressProfile p_profile = COMPRESS_PROFILE_AUTOMATIC); + Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, CompressProfile p_profile = COMPRESS_PROFILE_AUTOMATIC); + Error _compress_from_channels(CompressMode p_mode, UsedChannels p_channels, CompressProfile p_profile, BPTCFormat p_bptc_format); Error decompress(); bool is_compressed() const; static bool is_format_compressed(Format p_format); @@ -481,4 +495,8 @@ VARIANT_ENUM_CAST(Image::CompressSource) VARIANT_ENUM_CAST(Image::UsedChannels) VARIANT_ENUM_CAST(Image::AlphaMode) VARIANT_ENUM_CAST(Image::RoughnessChannel) +VARIANT_ENUM_CAST(Image::CompressProfile) + +#ifndef DISABLE_DEPRECATED VARIANT_ENUM_CAST(Image::ASTCFormat) +#endif diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index fed764b8cd..3b1d6226b9 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -79,11 +79,11 @@ - + Compresses the image with a VRAM-compressed format to use less memory. Can not directly access pixel data while the image is compressed. Returns error if the chosen compression mode is not available. The [param source] parameter helps to pick the best compression method for DXT and ETC2 formats. It is ignored for ASTC compression. - The [param astc_format] parameter is only taken into account when using ASTC compression; it is ignored for all other formats. + The [param profile] lets the user pick whether the compression should prioritize quality or a smaller size. Only ASTC compression uses this currently. [b]Note:[/b] [method compress] is only supported in editor builds. When run in an exported project, this method always returns [constant ERR_UNAVAILABLE]. @@ -91,11 +91,11 @@ - + Compresses the image with a VRAM-compressed format to use less memory. Can not directly access pixel data while the image is compressed. Returns error if the chosen compression mode is not available. - This is an alternative to [method compress] that lets the user supply the channels used in order for the compressor to pick the best DXT and ETC2 formats. For other formats (non DXT or ETC2), this argument is ignored. - The [param astc_format] parameter is only taken into account when using ASTC compression; it is ignored for all other formats. + This is an alternative to [method compress] that lets the user supply the channels used in order for the compressor to pick the best DXT, ETC2, and ASTC formats. For other formats (non DXT, ETC2, or ASTC), this argument is ignored. + The [param profile] lets the user pick whether the compression should prioritize quality or a smaller size. Only ASTC compression uses this currently. [b]Note:[/b] [method compress_from_channels] is only supported in editor builds. When run in an exported project, this method always returns [constant ERR_UNAVAILABLE]. @@ -815,7 +815,13 @@ [b]Note:[/b] When used in a shader, the texture requires usage of [code]usampler[/code] samplers. Additionally, it only supports nearest-neighbor filtering under the Compatibility renderer. [b]Note:[/b] When sampling using [method Image.get_pixel], returned [Color]s have to be divided by [code]65535[/code] to get the correct color value. - + + [url=https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression]Adaptive Scalable Texture Compression[/url]. This implements the 6×6 (medium quality) mode. + + + Same format as [constant FORMAT_ASTC_6x6], but with the hint to let the GPU know it is used for HDR. + + Represents the size of the [enum Format] enum. @@ -891,6 +897,21 @@ Source texture (before compression) is a normal texture (e.g. it can be compressed into two channels). + + Automatically adjusts the quality level based on the number of unique color channels present in the image. For ASTC, this corresponds to picking 8x8 when only one channel is detected (R, L), 6x6 when two channels are detected (RG, LA), and 4x4 in all other cases. + + + Prioritizes highest quality over compression. For ASTC, this corresponds to using a 4x4 block size. + + + Prioritizes some compression over quality. For ASTC, this corresponds to using a 6x6 block size. + + + Prioritizes highest compression over quality. For ASTC, this corresponds to using an 8x8 block size. + + + Represents the size of the [enum CompressProfile] enum. + Hint to indicate that the high quality 4×4 ASTC compression format should be used. diff --git a/doc/classes/ResourceImporterLayeredTexture.xml b/doc/classes/ResourceImporterLayeredTexture.xml index d4938ecc9f..9a001db02c 100644 --- a/doc/classes/ResourceImporterLayeredTexture.xml +++ b/doc/classes/ResourceImporterLayeredTexture.xml @@ -28,6 +28,14 @@ If [code]false[/code], uses the faster but lower-quality S3TC compression on desktop platforms and ETC2 on mobile/web platforms. When using S3TC, DXT1 (BC1) is used for opaque textures and DXT5 (BC3) is used for transparent or normal map (RGTC) textures. BPTC and ASTC support VRAM compression for HDR textures, but S3TC and ETC2 do not (see [member compress/hdr_compression]). + + Controls the priorities of the VRAM compression when [member compress/high_quality] is enabled. + [b]Automatic:[/b] Automatically adjusts the quality level based on the number of unique color channels present in the image. For ASTC, this corresponds to picking 8x8 when only one channel is detected (R, L), 6x6 when two channels are detected (RG, LA), and 4x4 in all other cases. + [b]Max Quality:[/b] Prioritizes highest quality over compression. For ASTC, this corresponds to using a 4x4 block size. + [b]Compressed:[/b] Prioritizes some compression over quality. For ASTC, this corresponds to using a 6x6 block size. + [b]Max Compression:[/b] Prioritizes highest compression over quality. For ASTC, this corresponds to using an 8x8 block size. + [b]Note:[/b] Currently, only the ASTC compressor uses this setting. Other compressors will ignore it. + The quality to use when using the [b]Lossy[/b] compression mode. Higher values result in better quality, at the cost of larger file sizes. Lossy quality does not affect memory usage of the imported texture, only its file size on disk. diff --git a/doc/classes/ResourceImporterTexture.xml b/doc/classes/ResourceImporterTexture.xml index d9b5dc3404..ba84a05766 100644 --- a/doc/classes/ResourceImporterTexture.xml +++ b/doc/classes/ResourceImporterTexture.xml @@ -27,6 +27,14 @@ If [code]false[/code], uses the faster but lower-quality S3TC compression on desktop platforms and ETC2 on mobile/web platforms. When using S3TC, DXT1 (BC1) is used for opaque textures and DXT5 (BC3) is used for transparent or normal map (RGTC) textures. BPTC and ASTC support VRAM compression for HDR textures, but S3TC and ETC2 do not (see [member compress/hdr_compression]). + + Controls the priorities of the VRAM compression when [member compress/high_quality] is enabled. + [b]Automatic:[/b] Automatically adjusts the quality level based on the number of unique color channels present in the image. For ASTC, this corresponds to picking 8x8 when only one channel is detected (R, L), 6x6 when two channels are detected (RG, LA), and 4x4 in all other cases. + [b]Max Quality:[/b] Prioritizes highest quality over compression. For ASTC, this corresponds to using a 4x4 block size. + [b]Compressed:[/b] Prioritizes some compression over quality. For ASTC, this corresponds to using a 6x6 block size. + [b]Max Compression:[/b] Prioritizes highest compression over quality. For ASTC, this corresponds to using an 8x8 block size. + [b]Note:[/b] Currently, only the ASTC compressor uses this setting. Other compressors will ignore it. + The quality to use when using the [b]Lossy[/b] compression mode. Higher values result in better quality, at the cost of larger file sizes. Lossy quality does not affect memory usage of the imported texture, only its file size on disk. diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index 83f8e898a8..9c3435630a 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -941,6 +941,26 @@ Ref TextureStorage::_get_gl_image_and_format(const Ref &p_image, I need_decompress = true; } } break; + case Image::FORMAT_ASTC_6x6: { + if (config->astc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA_ASTC_6x6_KHR; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_ASTC_6x6_HDR: { + if (config->astc_hdr_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA_ASTC_6x6_KHR; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + } else { + need_decompress = true; + } + } break; case Image::FORMAT_ASTC_8x8: { if (config->astc_supported) { r_gl_internal_format = _EXT_COMPRESSED_RGBA_ASTC_8x8_KHR; diff --git a/drivers/metal/rendering_device_driver_metal.cpp b/drivers/metal/rendering_device_driver_metal.cpp index 90dae10222..aaedd544d9 100644 --- a/drivers/metal/rendering_device_driver_metal.cpp +++ b/drivers/metal/rendering_device_driver_metal.cpp @@ -582,7 +582,6 @@ Vector RenderingDeviceDriverMetal::texture_get_data(TextureID p_texture image_data.resize(tight_mip_size); uint32_t pixel_size = get_image_format_pixel_size(tex_format); - uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(tex_format); uint32_t blockw = 0, blockh = 0; get_compressed_image_format_block_dimensions(tex_format, blockw, blockh); @@ -592,7 +591,7 @@ Vector RenderingDeviceDriverMetal::texture_get_data(TextureID p_texture uint32_t bw = STEPIFY(tex_w, blockw); uint32_t bh = STEPIFY(tex_h, blockh); - uint32_t bytes_per_row = (bw * pixel_size) >> pixel_rshift; + uint32_t bytes_per_row = get_compressed_image_format_pixels_shifted(tex_format, bw * pixel_size); uint32_t bytes_per_img = bytes_per_row * bh; uint32_t mip_size = bytes_per_img * tex_d; diff --git a/editor/import/resource_importer_layered_texture.cpp b/editor/import/resource_importer_layered_texture.cpp index 0273398c9a..ee0d09d7ac 100644 --- a/editor/import/resource_importer_layered_texture.cpp +++ b/editor/import/resource_importer_layered_texture.cpp @@ -119,6 +119,9 @@ String ResourceImporterLayeredTexture::get_resource_type() const { } bool ResourceImporterLayeredTexture::get_option_visibility(const String &p_path, const String &p_option, const HashMap &p_options) const { + if (p_option == "compress/high_quality_mode") { + return bool(p_options["compress/high_quality"]); + } if (p_option == "compress/lossy_quality" && p_options.has("compress/mode")) { return int(p_options["compress/mode"]) == COMPRESS_LOSSY; } @@ -142,7 +145,8 @@ String ResourceImporterLayeredTexture::get_preset_name(int p_idx) const { void ResourceImporterLayeredTexture::get_import_options(const String &p_path, List *r_options, int p_preset) const { r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Lossy,VRAM Compressed,VRAM Uncompressed,Basis Universal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 1)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/high_quality"), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/high_quality", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/high_quality_mode", PROPERTY_HINT_ENUM, "Automatic,Max Quality,Compressed,Max Compression"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7)); Image::BasisUniversalPackerParams basisu_params; @@ -167,7 +171,7 @@ void ResourceImporterLayeredTexture::get_import_options(const String &p_path, Li } } -void ResourceImporterLayeredTexture::_save_tex(Vector> p_images, const String &p_to_path, int p_compress_mode, float p_lossy, const Image::BasisUniversalPackerParams &p_basisu_params, Image::CompressMode p_vram_compression, Image::CompressSource p_csource, Image::UsedChannels used_channels, bool p_mipmaps, bool p_force_po2, Image::BPTCFormat p_bptc_format) { +void ResourceImporterLayeredTexture::_save_tex(Vector> p_images, const String &p_to_path, int p_compress_mode, float p_lossy, const Image::BasisUniversalPackerParams &p_basisu_params, Image::CompressMode p_vram_compression, Image::CompressProfile p_vram_compression_profile, Image::CompressSource p_csource, Image::UsedChannels used_channels, bool p_mipmaps, bool p_force_po2, Image::BPTCFormat p_bptc_format) { Vector> mipmap_images; //for 3D if (mode == MODE_3D) { @@ -287,11 +291,11 @@ void ResourceImporterLayeredTexture::_save_tex(Vector> p_images, cons } for (int i = 0; i < p_images.size(); i++) { - ResourceImporterTexture::save_to_ctex_format(f, p_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy, p_basisu_params, p_bptc_format); + ResourceImporterTexture::save_to_ctex_format(f, p_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_vram_compression_profile, p_lossy, p_basisu_params, p_bptc_format); } for (int i = 0; i < mipmap_images.size(); i++) { - ResourceImporterTexture::save_to_ctex_format(f, mipmap_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy, p_basisu_params, p_bptc_format); + ResourceImporterTexture::save_to_ctex_format(f, mipmap_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_vram_compression_profile, p_lossy, p_basisu_params, p_bptc_format); } } @@ -299,6 +303,7 @@ Error ResourceImporterLayeredTexture::import(ResourceUID::ID p_source_id, const int compress_mode = p_options["compress/mode"]; float lossy = p_options["compress/lossy_quality"]; bool high_quality = p_options["compress/high_quality"]; + int high_quality_mode = p_options["compress/high_quality_mode"]; int hdr_compression = p_options["compress/hdr_compression"]; bool mipmaps = p_options["mipmaps/generate"]; @@ -406,6 +411,7 @@ Error ResourceImporterLayeredTexture::import(ResourceUID::ID p_source_id, const texture_import->mipmaps = mipmaps; texture_import->used_channels = used_channels; texture_import->high_quality = high_quality; + texture_import->compression_profile = (Image::CompressProfile)(high_quality_mode); texture_import->basisu_params = basisu_params; @@ -504,7 +510,7 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source if (r_texture_import->compress_mode != COMPRESS_VRAM_COMPRESSED) { // Import normally. _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, r_texture_import->basisu_params, - Image::COMPRESS_S3TC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false, Image::BPTC_DETECT); + Image::COMPRESS_S3TC /* IGNORED */, Image::COMPRESS_PROFILE_AUTOMATIC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false, Image::BPTC_DETECT); return; } // Must import in all formats, in order of priority (so platform chooses the best supported one. IE, etc2 over etc). @@ -560,7 +566,7 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source if (use_uncompressed) { _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + extension, COMPRESS_VRAM_UNCOMPRESSED, r_texture_import->lossy, r_texture_import->basisu_params, - Image::COMPRESS_S3TC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false, Image::BPTC_DETECT); + Image::COMPRESS_S3TC /* IGNORED */, Image::COMPRESS_PROFILE_AUTOMATIC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false, Image::BPTC_DETECT); } else { if (can_s3tc_bptc) { Image::CompressMode image_compress_mode; @@ -574,7 +580,7 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source image_compress_mode = Image::COMPRESS_S3TC; image_compress_format = "s3tc"; } - _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + image_compress_format + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, r_texture_import->basisu_params, image_compress_mode, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true, image_bptc_format); + _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + image_compress_format + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, r_texture_import->basisu_params, image_compress_mode, r_texture_import->compression_profile, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true, image_bptc_format); r_texture_import->platform_variants->push_back(image_compress_format); } @@ -588,7 +594,7 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source image_compress_mode = Image::COMPRESS_ETC2; image_compress_format = "etc2"; } - _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + image_compress_format + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, r_texture_import->basisu_params, image_compress_mode, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true, Image::BPTC_DETECT); + _save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + image_compress_format + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, r_texture_import->basisu_params, image_compress_mode, r_texture_import->compression_profile, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true, Image::BPTC_DETECT); r_texture_import->platform_variants->push_back(image_compress_format); } } diff --git a/editor/import/resource_importer_layered_texture.h b/editor/import/resource_importer_layered_texture.h index 1e55ee829f..23bf813a93 100644 --- a/editor/import/resource_importer_layered_texture.h +++ b/editor/import/resource_importer_layered_texture.h @@ -55,6 +55,7 @@ public: int hdr_compression = 0; bool mipmaps = true; bool high_quality = false; + Image::CompressProfile compression_profile = Image::COMPRESS_PROFILE_AUTOMATIC; Image::UsedChannels used_channels = Image::USED_CHANNELS_RGBA; }; @@ -111,7 +112,7 @@ public: virtual void get_import_options(const String &p_path, List *r_options, int p_preset = 0) const override; virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap &p_options) const override; - void _save_tex(Vector> p_images, const String &p_to_path, int p_compress_mode, float p_lossy, const Image::BasisUniversalPackerParams &p_basisu_params, Image::CompressMode p_vram_compression, Image::CompressSource p_csource, Image::UsedChannels used_channels, bool p_mipmaps, bool p_force_po2, Image::BPTCFormat p_bptc_format); + void _save_tex(Vector> p_images, const String &p_to_path, int p_compress_mode, float p_lossy, const Image::BasisUniversalPackerParams &p_basisu_params, Image::CompressMode p_vram_compression, Image::CompressProfile p_vram_compression_profile, Image::CompressSource p_csource, Image::UsedChannels used_channels, bool p_mipmaps, bool p_force_po2, Image::BPTCFormat p_bptc_format); virtual Error import(ResourceUID::ID p_source_id, const String &p_source_file, const String &p_save_path, const HashMap &p_options, List *r_platform_variants, List *r_gen_files = nullptr, Variant *r_metadata = nullptr) override; diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index ce08517722..42e3627256 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -180,7 +180,9 @@ String ResourceImporterTexture::get_resource_type() const { } bool ResourceImporterTexture::get_option_visibility(const String &p_path, const String &p_option, const HashMap &p_options) const { - if (p_option == "compress/high_quality" || p_option == "compress/hdr_compression") { + if (p_option == "compress/high_quality_mode") { + return bool(p_options["compress/high_quality"]); + } else if (p_option == "compress/high_quality" || p_option == "compress/hdr_compression") { int compress_mode = int(p_options["compress/mode"]); if (compress_mode != COMPRESS_VRAM_COMPRESSED) { return false; @@ -230,7 +232,8 @@ String ResourceImporterTexture::get_preset_name(int p_idx) const { void ResourceImporterTexture::get_import_options(const String &p_path, List *r_options, int p_preset) const { r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/mode", PROPERTY_HINT_ENUM, "Lossless,Lossy,VRAM Compressed,VRAM Uncompressed,Basis Universal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), p_preset == PRESET_3D ? 2 : 0)); - r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/high_quality"), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/high_quality", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/high_quality_mode", PROPERTY_HINT_ENUM, "Automatic,Max Quality,Compressed,Max Compression"), 0)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7)); Image::BasisUniversalPackerParams basisu_params; @@ -269,7 +272,7 @@ void ResourceImporterTexture::get_import_options(const String &p_path, List f, const Ref &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality, const Image::BasisUniversalPackerParams &p_basisu_params, Image::BPTCFormat p_bptc_format) { +void ResourceImporterTexture::save_to_ctex_format(Ref f, const Ref &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, Image::CompressProfile p_compress_profile, float p_lossy_quality, const Image::BasisUniversalPackerParams &p_basisu_params, Image::BPTCFormat p_bptc_format) { switch (p_compress_mode) { case COMPRESS_LOSSLESS: { bool lossless_force_png = GLOBAL_GET("rendering/textures/lossless_compression/force_png") || !Image::_webp_mem_loader_func; // WebP module disabled or png is forced. @@ -314,7 +317,7 @@ void ResourceImporterTexture::save_to_ctex_format(Ref f, const Ref image = p_image->duplicate(); - image->_compress_from_channels(p_compress_format, p_channels, Image::ASTC_FORMAT_4x4, p_bptc_format); + image->_compress_from_channels(p_compress_format, p_channels, p_compress_profile, p_bptc_format); f->store_32(CompressedTexture2D::DATA_FORMAT_IMAGE); f->store_16(image->get_width()); @@ -349,7 +352,7 @@ void ResourceImporterTexture::save_to_ctex_format(Ref f, const Ref &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, const Image::BasisUniversalPackerParams &p_basisu_params, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_roughness, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref &p_normal, Image::RoughnessChannel p_roughness_channel) { +void ResourceImporterTexture::_save_ctex(const Ref &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, const Image::BasisUniversalPackerParams &p_basisu_params, Image::CompressMode p_vram_compression, Image::CompressProfile p_vram_compression_profile, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_roughness, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref &p_normal, Image::RoughnessChannel p_roughness_channel) { Ref f = FileAccess::open(p_to_path, FileAccess::WRITE); ERR_FAIL_COND(f.is_null()); @@ -429,7 +432,7 @@ void ResourceImporterTexture::_save_ctex(const Ref &p_image, const String used_channels = image->detect_used_channels(comp_source); } - save_to_ctex_format(f, image, p_compress_mode, used_channels, p_vram_compression, p_lossy_quality, p_basisu_params, Image::BPTC_DETECT); + save_to_ctex_format(f, image, p_compress_mode, used_channels, p_vram_compression, p_vram_compression_profile, p_lossy_quality, p_basisu_params, Image::BPTC_DETECT); } void ResourceImporterTexture::_save_editor_meta(const Dictionary &p_metadata, const String &p_to_path) { @@ -707,6 +710,7 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String const int normal = p_options["compress/normal_map"]; const int hdr_compression = p_options["compress/hdr_compression"]; const int high_quality = p_options["compress/high_quality"]; + const int high_quality_mode = p_options["compress/high_quality_mode"]; // Mipmaps. const bool mipmaps = p_options["mipmaps/generate"]; @@ -926,12 +930,13 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String } if (force_uncompressed) { - _save_ctex(image, p_save_path + ".ctex", COMPRESS_VRAM_UNCOMPRESSED, lossy, basisu_params, Image::COMPRESS_S3TC /* This is ignored. */, + _save_ctex(image, p_save_path + ".ctex", COMPRESS_VRAM_UNCOMPRESSED, lossy, basisu_params, Image::COMPRESS_S3TC /* This is ignored. */, Image::COMPRESS_PROFILE_AUTOMATIC /* This is ignored. */, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); } else { if (can_s3tc_bptc) { Image::CompressMode image_compress_mode; String image_compress_format; + Image::CompressProfile image_compress_profile = (Image::CompressProfile)(high_quality_mode); if (high_quality || is_hdr) { image_compress_mode = Image::COMPRESS_BPTC; image_compress_format = "bptc"; @@ -940,7 +945,7 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String image_compress_format = "s3tc"; } - _save_ctex(image, p_save_path + "." + image_compress_format + ".ctex", compress_mode, lossy, basisu_params, image_compress_mode, mipmaps, + _save_ctex(image, p_save_path + "." + image_compress_format + ".ctex", compress_mode, lossy, basisu_params, image_compress_mode, image_compress_profile, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); r_platform_variants->push_back(image_compress_format); } @@ -948,6 +953,7 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String if (can_etc2_astc) { Image::CompressMode image_compress_mode; String image_compress_format; + Image::CompressProfile image_compress_profile = (Image::CompressProfile)(high_quality_mode); if (high_quality || is_hdr) { image_compress_mode = Image::COMPRESS_ASTC; image_compress_format = "astc"; @@ -956,19 +962,19 @@ Error ResourceImporterTexture::import(ResourceUID::ID p_source_id, const String image_compress_format = "etc2"; } - _save_ctex(image, p_save_path + "." + image_compress_format + ".ctex", compress_mode, lossy, basisu_params, image_compress_mode, mipmaps, stream, detect_3d, + _save_ctex(image, p_save_path + "." + image_compress_format + ".ctex", compress_mode, lossy, basisu_params, image_compress_mode, image_compress_profile, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); r_platform_variants->push_back(image_compress_format); } } } else { // Import normally. - _save_ctex(image, p_save_path + ".ctex", compress_mode, lossy, basisu_params, Image::COMPRESS_S3TC /* This is ignored. */, + _save_ctex(image, p_save_path + ".ctex", compress_mode, lossy, basisu_params, Image::COMPRESS_S3TC /* This is ignored. */, Image::COMPRESS_PROFILE_AUTOMATIC /* This is ignored. */, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); } if (editor_image.is_valid()) { - _save_ctex(editor_image, p_save_path + ".editor.ctex", compress_mode, lossy, basisu_params, Image::COMPRESS_S3TC /* This is ignored. */, + _save_ctex(editor_image, p_save_path + ".editor.ctex", compress_mode, lossy, basisu_params, Image::COMPRESS_S3TC /* This is ignored. */, Image::COMPRESS_PROFILE_AUTOMATIC /* This is ignored. */, mipmaps, stream, detect_3d, detect_roughness, detect_normal, force_normal, srgb_friendly_pack, false, mipmap_limit, normal_image, roughness_channel); // Generate and save editor-specific metadata, which we cannot save to the .import file. diff --git a/editor/import/resource_importer_texture.h b/editor/import/resource_importer_texture.h index b21729ed7e..838323ccc9 100644 --- a/editor/import/resource_importer_texture.h +++ b/editor/import/resource_importer_texture.h @@ -86,7 +86,7 @@ protected: static ResourceImporterTexture *singleton; static const char *compression_formats[]; - void _save_ctex(const Ref &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, const Image::BasisUniversalPackerParams &p_basisu_params, Image::CompressMode p_vram_compression, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref &p_normal, Image::RoughnessChannel p_roughness_channel); + void _save_ctex(const Ref &p_image, const String &p_to_path, CompressMode p_compress_mode, float p_lossy_quality, const Image::BasisUniversalPackerParams &p_basisu_params, Image::CompressMode p_vram_compression, Image::CompressProfile p_vram_compression_profile, bool p_mipmaps, bool p_streamable, bool p_detect_3d, bool p_detect_srgb, bool p_detect_normal, bool p_force_normal, bool p_srgb_friendly, bool p_force_po2_for_compressed, uint32_t p_limit_mipmap, const Ref &p_normal, Image::RoughnessChannel p_roughness_channel); void _save_editor_meta(const Dictionary &p_metadata, const String &p_to_path); Dictionary _load_editor_meta(const String &p_to_path) const; @@ -95,7 +95,7 @@ protected: static inline void _invert_y_channel(Ref &r_image); public: - static void save_to_ctex_format(Ref f, const Ref &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, float p_lossy_quality, const Image::BasisUniversalPackerParams &p_basisu_params, Image::BPTCFormat p_bptc_format); + static void save_to_ctex_format(Ref f, const Ref &p_image, CompressMode p_compress_mode, Image::UsedChannels p_channels, Image::CompressMode p_compress_format, Image::CompressProfile p_compress_profile, float p_lossy_quality, const Image::BasisUniversalPackerParams &p_basisu_params, Image::BPTCFormat p_bptc_format); static ResourceImporterTexture *get_singleton() { return singleton; } virtual String get_importer_name() const override; diff --git a/editor/scene/texture/texture_editor_plugin.cpp b/editor/scene/texture/texture_editor_plugin.cpp index 6f27c35722..9b2d80af98 100644 --- a/editor/scene/texture/texture_editor_plugin.cpp +++ b/editor/scene/texture/texture_editor_plugin.cpp @@ -195,8 +195,8 @@ void TexturePreview::_update_metadata_label_text() { if (format != Image::FORMAT_MAX) { // Avoid signed integer overflow that could occur with huge texture sizes by casting everything to uint64_t. uint64_t memory = uint64_t(resolution.x) * uint64_t(resolution.y) * uint64_t(Image::get_format_pixel_size(format)); - // Handle VRAM-compressed formats that are stored with 4 bpp. - memory >>= Image::get_format_pixel_rshift(format); + // Handle VRAM-compressed formats. + memory = Image::get_format_pixels_shifted(format, memory); float mipmaps_multiplier = 1.0; float mipmap_increase = 0.25; diff --git a/misc/extension_api_validation/4.7-stable/GH-115003.txt b/misc/extension_api_validation/4.7-stable/GH-115003.txt new file mode 100644 index 0000000000..d4dd11b6d1 --- /dev/null +++ b/misc/extension_api_validation/4.7-stable/GH-115003.txt @@ -0,0 +1,9 @@ +GH-115003 +--------- +Validate extension JSON: Error: Field 'classes/Image/methods/compress/arguments/2': default_value changed value in new API, from "0" to "1". +Validate extension JSON: Error: Field 'classes/Image/methods/compress/arguments/2': type changed value in new API, from "enum::Image.ASTCFormat" to "enum::Image.CompressProfile". +Validate extension JSON: Error: Field 'classes/Image/methods/compress_from_channels/arguments/2': default_value changed value in new API, from "0" to "1". +Validate extension JSON: Error: Field 'classes/Image/methods/compress_from_channels/arguments/2': type changed value in new API, from "enum::Image.ASTCFormat" to "enum::Image.CompressProfile". + +The ASTCFormat argument has been changed to a more abstract parameter that can be used by more compressors. +Compatibility methods have been registered. diff --git a/modules/astcenc/image_compress_astcenc.cpp b/modules/astcenc/image_compress_astcenc.cpp index c074f3ebb4..6c23b17f6e 100644 --- a/modules/astcenc/image_compress_astcenc.cpp +++ b/modules/astcenc/image_compress_astcenc.cpp @@ -36,7 +36,22 @@ #include #ifdef TOOLS_ENABLED -void _compress_astc(Image *r_img, Image::ASTCFormat p_format) { +Image::CompressProfile _pick_profile_from_channels(Image::UsedChannels p_channels) { + switch (p_channels) { + case Image::USED_CHANNELS_L: + case Image::USED_CHANNELS_R: + return Image::COMPRESS_PROFILE_MAX_COMPRESSION; + case Image::USED_CHANNELS_LA: + case Image::USED_CHANNELS_RG: + return Image::COMPRESS_PROFILE_COMPRESSED; + case Image::USED_CHANNELS_RGB: + case Image::USED_CHANNELS_RGBA: + default: + return Image::COMPRESS_PROFILE_MAX_QUALITY; + } +} + +void _compress_astc(Image *r_img, Image::UsedChannels p_channels, Image::CompressProfile p_profile) { const uint64_t start_time = OS::get_singleton()->get_ticks_msec(); if (r_img->is_compressed()) { @@ -58,23 +73,27 @@ void _compress_astc(Image *r_img, Image::ASTCFormat p_format) { const astcenc_profile profile = is_hdr ? ASTCENC_PRF_HDR : ASTCENC_PRF_LDR; Image::Format target_format = Image::FORMAT_MAX; - unsigned int block_x = 4; - unsigned int block_y = 4; + unsigned int block_x = 1, block_y = 1; + if (p_profile == Image::COMPRESS_PROFILE_AUTOMATIC) { + // Automatic profile will automatically pick one of the other profiles based on the amount of channels currently in use. + p_profile = _pick_profile_from_channels(p_channels); + } - if (p_format == Image::ASTCFormat::ASTC_FORMAT_4x4) { - if (is_hdr) { - target_format = Image::FORMAT_ASTC_4x4_HDR; - } else { - target_format = Image::FORMAT_ASTC_4x4; - } - } else if (p_format == Image::ASTCFormat::ASTC_FORMAT_8x8) { - if (is_hdr) { - target_format = Image::FORMAT_ASTC_8x8_HDR; - } else { - target_format = Image::FORMAT_ASTC_8x8; - } - block_x = 8; - block_y = 8; + switch (p_profile) { + case Image::COMPRESS_PROFILE_MAX_QUALITY: + target_format = is_hdr ? Image::FORMAT_ASTC_4x4_HDR : Image::FORMAT_ASTC_4x4; + block_x = block_y = 4; + break; + case Image::COMPRESS_PROFILE_COMPRESSED: + target_format = is_hdr ? Image::FORMAT_ASTC_6x6_HDR : Image::FORMAT_ASTC_6x6; + block_x = block_y = 6; + break; + case Image::COMPRESS_PROFILE_MAX_COMPRESSION: + target_format = is_hdr ? Image::FORMAT_ASTC_8x8_HDR : Image::FORMAT_ASTC_8x8; + block_x = block_y = 8; + break; + default: + break; } // Compress image data and (if required) mipmaps. @@ -195,6 +214,16 @@ void _decompress_astc(Image *r_img) { block_y = 4; is_hdr = true; } break; + case Image::FORMAT_ASTC_6x6: { + block_x = 6; + block_y = 6; + is_hdr = false; + } break; + case Image::FORMAT_ASTC_6x6_HDR: { + block_x = 6; + block_y = 6; + is_hdr = true; + } break; case Image::FORMAT_ASTC_8x8: { block_x = 8; block_y = 8; diff --git a/modules/astcenc/image_compress_astcenc.h b/modules/astcenc/image_compress_astcenc.h index 21e96c0763..d70463f2a2 100644 --- a/modules/astcenc/image_compress_astcenc.h +++ b/modules/astcenc/image_compress_astcenc.h @@ -33,7 +33,7 @@ #include "core/io/image.h" #ifdef TOOLS_ENABLED -void _compress_astc(Image *r_img, Image::ASTCFormat p_format); +void _compress_astc(Image *r_img, Image::UsedChannels p_channels, Image::CompressProfile p_profile); #endif void _decompress_astc(Image *r_img); diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp index f7adbe648c..51db6dbef4 100644 --- a/modules/cvtt/image_compress_cvtt.cpp +++ b/modules/cvtt/image_compress_cvtt.cpp @@ -199,7 +199,6 @@ void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels, Image:: int64_t target_size = Image::get_image_data_size(w, h, target_format, p_image->has_mipmaps()); int mm_count = p_image->has_mipmaps() ? Image::get_image_required_mipmaps(w, h, target_format) : 0; data.resize(target_size); - int shift = Image::get_format_pixel_rshift(target_format); uint8_t *wb = data.ptrw(); @@ -282,7 +281,7 @@ void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels, Image:: out_bytes += 16 * (bw / 4); } - dst_ofs += (MAX(4, bw) * MAX(4, bh)) >> shift; + dst_ofs += Image::get_format_pixels_shifted(target_format, MAX(4, bw) * MAX(4, bh)); } const CVTTCompressionRowTask *tasks_rb = tasks.ptr(); diff --git a/modules/ktx/texture_loader_ktx.cpp b/modules/ktx/texture_loader_ktx.cpp index 83eb4f1b2d..cd19ec1425 100644 --- a/modules/ktx/texture_loader_ktx.cpp +++ b/modules/ktx/texture_loader_ktx.cpp @@ -267,6 +267,12 @@ static Ref load_from_file_access(Ref f, Error *r_error) { case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: format = Image::FORMAT_ASTC_4x4_HDR; break; + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: + format = Image::FORMAT_ASTC_6x6; + break; + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: + format = Image::FORMAT_ASTC_6x6_HDR; + break; case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: format = Image::FORMAT_ASTC_8x8; break; @@ -487,6 +493,12 @@ static Ref load_from_file_access(Ref f, Error *r_error) { case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: format = Image::FORMAT_ASTC_4x4_HDR; break; + case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: + format = Image::FORMAT_ASTC_6x6; + break; + case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: + format = Image::FORMAT_ASTC_6x6_HDR; + break; case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: format = Image::FORMAT_ASTC_8x8; break; @@ -511,7 +523,6 @@ static Ref load_from_file_access(Ref f, Error *r_error) { // KTX use 4-bytes padding, don't use mipmaps if padding is effective // TODO: unpad dynamically int pixel_size = Image::get_format_pixel_size(format); - int pixel_rshift = Image::get_format_pixel_rshift(format); int block = Image::get_format_block_size(format); int minw, minh; Image::get_format_min_pixel_size(format, minw, minh); @@ -523,7 +534,7 @@ static Ref load_from_file_access(Ref f, Error *r_error) { size_t bh = h % block != 0 ? h + (block - h % block) : h; size_t s = bw * bh; s *= pixel_size; - s >>= pixel_rshift; + s = Image::get_format_pixels_shifted(format, s); if (mip_size != static_cast(s)) { if (!i) { ktxTexture_Destroy(ktx_texture); diff --git a/scene/resources/portable_compressed_texture.cpp b/scene/resources/portable_compressed_texture.cpp index 04eee9a079..6c4e70e984 100644 --- a/scene/resources/portable_compressed_texture.cpp +++ b/scene/resources/portable_compressed_texture.cpp @@ -47,7 +47,7 @@ static PortableCompressedTexture2D::CompressionMode get_expected_compression_mod return PortableCompressedTexture2D::COMPRESSION_MODE_ETC2; } else if (format >= Image::FORMAT_BPTC_RGBA && format <= Image::FORMAT_BPTC_RGBFU) { return PortableCompressedTexture2D::COMPRESSION_MODE_BPTC; - } else if (format >= Image::FORMAT_ASTC_4x4 && format <= Image::FORMAT_ASTC_8x8_HDR) { + } else if ((format >= Image::FORMAT_ASTC_4x4 && format <= Image::FORMAT_ASTC_8x8_HDR) || (format >= Image::FORMAT_ASTC_6x6 && format <= Image::FORMAT_ASTC_6x6_HDR)) { return PortableCompressedTexture2D::COMPRESSION_MODE_ASTC; } ERR_FAIL_V(PortableCompressedTexture2D::COMPRESSION_MODE_LOSSLESS); diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index c22f96eaca..6ff8802f94 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -1589,6 +1589,14 @@ RID TextureStorage::texture_create_from_native_handle(RSE::TextureType p_type, I format = RD::DATA_FORMAT_ASTC_4x4_SFLOAT_BLOCK; break; + case Image::FORMAT_ASTC_6x6: + format = RD::DATA_FORMAT_ASTC_6x6_UNORM_BLOCK; + break; + + case Image::FORMAT_ASTC_6x6_HDR: + format = RD::DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK; + break; + case Image::FORMAT_ASTC_8x8: format = RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK; break; @@ -2720,6 +2728,38 @@ Ref TextureStorage::_validate_texture_format(const Ref &p_image, T r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; } break; // astc 4x4 HDR + case Image::FORMAT_ASTC_6x6: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ASTC_6x6_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_ASTC_6x6_UNORM_BLOCK; + r_format.format_srgb = RD::DATA_FORMAT_ASTC_6x6_SRGB_BLOCK; + } else { + //not supported, reconvert + image->decompress(); + r_format.format = RD::DATA_FORMAT_R8G8B8A8_UNORM; + r_format.format_srgb = RD::DATA_FORMAT_R8G8B8A8_SRGB; + image->convert(Image::FORMAT_RGBA8); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; // astc 6x6 + case Image::FORMAT_ASTC_6x6_HDR: { + if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { + r_format.format = RD::DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK; + } else { + //not supported, reconvert + image->decompress(); + r_format.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; + image->convert(Image::FORMAT_RGBAH); + } + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + + } break; // astc 8x8 HDR case Image::FORMAT_ASTC_8x8: { if (RD::get_singleton()->texture_is_format_supported_for_usage(RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK, RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT)) { r_format.format = RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK; @@ -3209,6 +3249,31 @@ void TextureStorage::_texture_format_from_rd(RD::DataFormat p_rd_format, Texture r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; } break; // astc 4x4 + case RD::DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: { + r_format.image_format = Image::FORMAT_ASTC_6x6; + r_format.rd_format = RD::DATA_FORMAT_ASTC_6x6_UNORM_BLOCK; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case RD::DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: { + r_format.image_format = Image::FORMAT_ASTC_6x6; + r_format.rd_format = RD::DATA_FORMAT_ASTC_6x6_UNORM_BLOCK; + r_format.rd_format_srgb = RD::DATA_FORMAT_ASTC_6x6_SRGB_BLOCK; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; + case RD::DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK: { + r_format.image_format = Image::FORMAT_ASTC_6x6_HDR; + r_format.rd_format = RD::DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK; + r_format.swizzle_r = RD::TEXTURE_SWIZZLE_R; + r_format.swizzle_g = RD::TEXTURE_SWIZZLE_G; + r_format.swizzle_b = RD::TEXTURE_SWIZZLE_B; + r_format.swizzle_a = RD::TEXTURE_SWIZZLE_A; + } break; // astc 8x8 case RD::DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: { // Q: Do we do as we do below, just create the sRGB variant? r_format.image_format = Image::FORMAT_ASTC_8x8; diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 1cccaf4487..cdfa4d1b26 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -2122,7 +2122,6 @@ Error RenderingDevice::_texture_initialize(RID p_texture, uint32_t p_layer, cons get_compressed_image_format_block_dimensions(texture->format, block_w, block_h); uint32_t pixel_size = get_image_format_pixel_size(texture->format); - uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(texture->format); uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format); // The algorithm operates on two passes, one to figure out the total size the staging buffer will require to allocate and another one where the copy is actually performed. @@ -2180,11 +2179,10 @@ Error RenderingDevice::_texture_initialize(RID p_texture, uint32_t p_layer, cons } } - uint32_t pitch = (width * pixel_size * block_w) >> pixel_rshift; + uint32_t pitch = get_compressed_image_format_pixels_shifted(texture->format, width * pixel_size * block_w); uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP); pitch = STEPIFY(pitch, pitch_step); - uint32_t to_allocate = pitch * height; - to_allocate >>= pixel_rshift; + uint32_t to_allocate = get_compressed_image_format_pixels_shifted(texture->format, pitch * height); if (copy_pass) { const uint8_t *read_ptr_mipmap_layer = read_ptr_mipmap + (tight_mip_size / depth) * z; @@ -2282,7 +2280,6 @@ Error RenderingDevice::texture_update(RID p_texture, uint32_t p_layer, const Vec get_compressed_image_format_block_dimensions(texture->format, block_w, block_h); uint32_t pixel_size = get_image_format_pixel_size(texture->format); - uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(texture->format); uint32_t block_size = get_compressed_image_format_block_byte_size(texture->format); uint32_t region_size = texture_upload_region_size_px; @@ -2317,7 +2314,7 @@ Error RenderingDevice::texture_update(RID p_texture, uint32_t p_layer, const Vec uint32_t region_logic_w = MIN(region_size, logic_width - x); uint32_t region_logic_h = MIN(region_size, logic_height - y); - uint32_t region_pitch = (region_w * pixel_size * block_w) >> pixel_rshift; + uint32_t region_pitch = get_compressed_image_format_pixels_shifted(texture->format, region_w * pixel_size * block_w); uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP); region_pitch = STEPIFY(region_pitch, pitch_step); uint32_t to_allocate = region_pitch * region_h; @@ -2811,10 +2808,8 @@ Error RenderingDevice::texture_get_data_async(RID p_texture, uint32_t p_layer, c uint32_t block_w, block_h; get_compressed_image_format_block_dimensions(tex->format, block_w, block_h); - uint32_t pixel_size = get_image_format_pixel_size(tex->format); - uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(tex->format); - uint32_t w, h, d; + uint32_t pixel_size = get_image_format_pixel_size(tex->format); uint32_t required_align = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_TRANSFER_ALIGNMENT); uint32_t pitch_step = driver->api_trait_get(RDD::API_TRAIT_TEXTURE_DATA_ROW_PITCH_STEP); uint32_t region_size = texture_download_region_size_px; @@ -2837,7 +2832,7 @@ Error RenderingDevice::texture_get_data_async(RID p_texture, uint32_t p_layer, c uint32_t region_logic_w = MIN(region_size, logic_w - x); uint32_t region_logic_h = MIN(region_size, logic_h - y); - uint32_t region_pitch = (region_w * pixel_size * block_w) >> pixel_rshift; + uint32_t region_pitch = get_compressed_image_format_pixels_shifted(tex->format, region_w * pixel_size * block_w); region_pitch = STEPIFY(region_pitch, pitch_step); uint32_t to_allocate = region_pitch * region_h; diff --git a/servers/rendering/rendering_device_commons.cpp b/servers/rendering/rendering_device_commons.cpp index 66499d5a7c..ca2fd13b98 100644 --- a/servers/rendering/rendering_device_commons.cpp +++ b/servers/rendering/rendering_device_commons.cpp @@ -587,6 +587,12 @@ void RenderingDeviceCommons::get_compressed_image_format_block_dimensions(DataFo r_w = 4; r_h = 4; } break; + case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK: { + r_w = 6; + r_h = 6; + } break; case DATA_FORMAT_ASTC_5x4_UNORM_BLOCK: // Unsupported case DATA_FORMAT_ASTC_5x4_SRGB_BLOCK: case DATA_FORMAT_ASTC_5x4_SFLOAT_BLOCK: @@ -596,9 +602,6 @@ void RenderingDeviceCommons::get_compressed_image_format_block_dimensions(DataFo case DATA_FORMAT_ASTC_6x5_UNORM_BLOCK: case DATA_FORMAT_ASTC_6x5_SRGB_BLOCK: case DATA_FORMAT_ASTC_6x5_SFLOAT_BLOCK: - case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: - case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: - case DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK: case DATA_FORMAT_ASTC_8x5_UNORM_BLOCK: case DATA_FORMAT_ASTC_8x5_SRGB_BLOCK: case DATA_FORMAT_ASTC_8x5_SFLOAT_BLOCK: @@ -731,7 +734,7 @@ uint32_t RenderingDeviceCommons::get_compressed_image_format_block_byte_size(Dat return 1; } -uint32_t RenderingDeviceCommons::get_compressed_image_format_pixel_rshift(DataFormat p_format) { +uint32_t RenderingDeviceCommons::get_compressed_image_format_pixels_shifted(DataFormat p_format, uint32_t p_pixels) { switch (p_format) { case DATA_FORMAT_BC1_RGB_UNORM_BLOCK: // These formats are half byte size, so rshift is 1. case DATA_FORMAT_BC1_RGB_SRGB_BLOCK: @@ -745,17 +748,18 @@ uint32_t RenderingDeviceCommons::get_compressed_image_format_pixel_rshift(DataFo case DATA_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: case DATA_FORMAT_EAC_R11_UNORM_BLOCK: case DATA_FORMAT_EAC_R11_SNORM_BLOCK: - return 1; + return (p_pixels >> 1); + case DATA_FORMAT_ASTC_6x6_SRGB_BLOCK: + case DATA_FORMAT_ASTC_6x6_UNORM_BLOCK: + case DATA_FORMAT_ASTC_6x6_SFLOAT_BLOCK: + return (p_pixels * 4) / 9; case DATA_FORMAT_ASTC_8x8_SRGB_BLOCK: case DATA_FORMAT_ASTC_8x8_UNORM_BLOCK: - case DATA_FORMAT_ASTC_8x8_SFLOAT_BLOCK: { - return 2; - } - default: { - } + case DATA_FORMAT_ASTC_8x8_SFLOAT_BLOCK: + return (p_pixels >> 2); + default: + return p_pixels; } - - return 0; } uint32_t RenderingDeviceCommons::get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw, uint32_t *r_blockh, uint32_t *r_depth) { @@ -767,7 +771,6 @@ uint32_t RenderingDeviceCommons::get_image_format_required_size(DataFormat p_for uint32_t size = 0; uint32_t pixel_size = get_image_format_pixel_size(p_format); - uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(p_format); uint32_t blockw = 0; uint32_t blockh = 0; get_compressed_image_format_block_dimensions(p_format, blockw, blockh); @@ -779,7 +782,7 @@ uint32_t RenderingDeviceCommons::get_image_format_required_size(DataFormat p_for uint32_t s = bw * bh; s *= pixel_size; - s >>= pixel_rshift; + s = get_compressed_image_format_pixels_shifted(p_format, s); size += s * d; if (r_blockw) { *r_blockw = bw; diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h index 72b986fac5..a49dd00137 100644 --- a/servers/rendering/rendering_device_commons.h +++ b/servers/rendering/rendering_device_commons.h @@ -1078,7 +1078,7 @@ protected: static void get_compressed_image_format_block_dimensions(DataFormat p_format, uint32_t &r_w, uint32_t &r_h); uint32_t get_compressed_image_format_block_byte_size(DataFormat p_format) const; - static uint32_t get_compressed_image_format_pixel_rshift(DataFormat p_format); + static uint32_t get_compressed_image_format_pixels_shifted(DataFormat p_format, uint32_t p_pixels); static uint32_t get_image_format_required_size(DataFormat p_format, uint32_t p_width, uint32_t p_height, uint32_t p_depth, uint32_t p_mipmaps, uint32_t *r_blockw = nullptr, uint32_t *r_blockh = nullptr, uint32_t *r_depth = nullptr); static uint32_t get_image_required_mipmaps(uint32_t p_width, uint32_t p_height, uint32_t p_depth); static bool format_has_depth(DataFormat p_format);