diff options
author | Juan Linietsky <reduzio@gmail.com> | 2022-09-05 21:11:34 +0200 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2022-12-20 11:26:30 +0100 |
commit | 71d21c7ccb9a78f573d674e717906012c7a5eb39 (patch) | |
tree | 9d50d510979d43b990d7c8783839d6975672b467 /core/io | |
parent | 00fa4e23e4b967291034ea7bb018dea638b37e8f (diff) |
Implement basic ASTC support
Implements basic ASTC support:
* Only 4x4 and 8x8 block sizes.
* Other block sizes are too complex to handle for Godot image compression handling. May be implemented sometime in the future.
The need for ASTC is mostly for the following use cases:
* Implement a high quality compression option for textures on mobile and M1 Apple hardware.
* For this, the 4x4 is sufficient, since it uses the same size as BPTC.
ASTC supports a lot of block sizes, but the benefit of supporting most of them is slim, while the implementation complexity in Godot is very high.
Supporting only 4x4 (and 8x8) solves the real problem, which is lack of a BPTC alternative on hardware where it's missing.
Note: This does not yet support encoding on import, an ASTC encoder will need to be added.
Diffstat (limited to 'core/io')
-rw-r--r-- | core/io/image.cpp | 56 | ||||
-rw-r--r-- | core/io/image.h | 17 |
2 files changed, 65 insertions, 8 deletions
diff --git a/core/io/image.cpp b/core/io/image.cpp index dee751eec5..667bb893f5 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -173,6 +173,14 @@ int Image::get_format_pixel_size(Format p_format) { return 1; case FORMAT_DXT5_RA_AS_RG: return 1; + case FORMAT_ASTC_4x4: + return 1; + case FORMAT_ASTC_4x4_HDR: + return 1; + case FORMAT_ASTC_8x8: + return 1; + case FORMAT_ASTC_8x8_HDR: + return 1; case FORMAT_MAX: { } } @@ -213,7 +221,18 @@ void Image::get_format_min_pixel_size(Format p_format, int &r_w, int &r_h) { r_h = 4; } break; + case FORMAT_ASTC_4x4: + case FORMAT_ASTC_4x4_HDR: { + r_w = 4; + r_h = 4; + + } break; + case FORMAT_ASTC_8x8: + case FORMAT_ASTC_8x8_HDR: { + r_w = 8; + r_h = 8; + } break; default: { r_w = 1; r_h = 1; @@ -222,7 +241,9 @@ 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_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) { + 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; @@ -260,6 +281,14 @@ int Image::get_format_block_size(Format p_format) { { return 4; } + case FORMAT_ASTC_4x4: + case FORMAT_ASTC_4x4_HDR: { + return 4; + } + case FORMAT_ASTC_8x8: + case FORMAT_ASTC_8x8_HDR: { + return 8; + } default: { } } @@ -2515,19 +2544,21 @@ 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) { + _image_decompress_astc(this); } else { return ERR_UNAVAILABLE; } return OK; } -Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_lossy_quality) { +Error Image::compress(CompressMode p_mode, CompressSource p_source, float p_lossy_quality, ASTCFormat p_astc_format) { 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_lossy_quality); + return compress_from_channels(p_mode, detect_used_channels(p_source), p_lossy_quality, p_astc_format); } -Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality) { +Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality, ASTCFormat p_astc_format) { switch (p_mode) { case COMPRESS_S3TC: { ERR_FAIL_COND_V(!_image_compress_bc_func, ERR_UNAVAILABLE); @@ -2545,6 +2576,10 @@ Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE); _image_compress_bptc_func(this, p_lossy_quality, p_channels); } break; + case COMPRESS_ASTC: { + ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE); + _image_compress_astc_func(this, p_lossy_quality, p_astc_format); + } break; case COMPRESS_MAX: { ERR_FAIL_V(ERR_INVALID_PARAMETER); } break; @@ -2895,10 +2930,12 @@ void (*Image::_image_compress_bc_func)(Image *, float, Image::UsedChannels) = nu void (*Image::_image_compress_bptc_func)(Image *, float, Image::UsedChannels) = nullptr; void (*Image::_image_compress_etc1_func)(Image *, float) = nullptr; void (*Image::_image_compress_etc2_func)(Image *, float, Image::UsedChannels) = nullptr; +void (*Image::_image_compress_astc_func)(Image *, float, Image::ASTCFormat) = nullptr; void (*Image::_image_decompress_bc)(Image *) = nullptr; void (*Image::_image_decompress_bptc)(Image *) = nullptr; void (*Image::_image_decompress_etc1)(Image *) = nullptr; void (*Image::_image_decompress_etc2)(Image *) = nullptr; +void (*Image::_image_decompress_astc)(Image *) = nullptr; Vector<uint8_t> (*Image::webp_lossy_packer)(const Ref<Image> &, float) = nullptr; Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr; @@ -3314,8 +3351,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", "lossy_quality"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(0.7)); - ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "lossy_quality"), &Image::compress_from_channels, DEFVAL(0.7)); + ClassDB::bind_method(D_METHOD("compress", "mode", "source", "lossy_quality", "astc_format"), &Image::compress, DEFVAL(COMPRESS_SOURCE_GENERIC), DEFVAL(0.7), DEFVAL(ASTC_FORMAT_4x4)); + ClassDB::bind_method(D_METHOD("compress_from_channels", "mode", "channels", "lossy_quality", "astc_format"), &Image::compress_from_channels, DEFVAL(0.7), DEFVAL(ASTC_FORMAT_4x4)); ClassDB::bind_method(D_METHOD("decompress"), &Image::decompress); ClassDB::bind_method(D_METHOD("is_compressed"), &Image::is_compressed); @@ -3399,6 +3436,10 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(FORMAT_ETC2_RGB8A1); BIND_ENUM_CONSTANT(FORMAT_ETC2_RA_AS_RG); BIND_ENUM_CONSTANT(FORMAT_DXT5_RA_AS_RG); + BIND_ENUM_CONSTANT(FORMAT_ASTC_4x4); + BIND_ENUM_CONSTANT(FORMAT_ASTC_4x4_HDR); + BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8); + BIND_ENUM_CONSTANT(FORMAT_ASTC_8x8_HDR); BIND_ENUM_CONSTANT(FORMAT_MAX); BIND_ENUM_CONSTANT(INTERPOLATE_NEAREST); @@ -3426,6 +3467,9 @@ void Image::_bind_methods() { BIND_ENUM_CONSTANT(COMPRESS_SOURCE_GENERIC); BIND_ENUM_CONSTANT(COMPRESS_SOURCE_SRGB); BIND_ENUM_CONSTANT(COMPRESS_SOURCE_NORMAL); + + BIND_ENUM_CONSTANT(ASTC_FORMAT_4x4); + BIND_ENUM_CONSTANT(ASTC_FORMAT_8x8); } void Image::set_compress_bc_func(void (*p_compress_func)(Image *, float, UsedChannels)) { diff --git a/core/io/image.h b/core/io/image.h index fd264a7a38..0e37e78c76 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -109,6 +109,10 @@ public: FORMAT_ETC2_RGB8A1, FORMAT_ETC2_RA_AS_RG, //used to make basis universal happy FORMAT_DXT5_RA_AS_RG, //used to make basis universal happy + FORMAT_ASTC_4x4, + FORMAT_ASTC_4x4_HDR, + FORMAT_ASTC_8x8, + FORMAT_ASTC_8x8_HDR, FORMAT_MAX }; @@ -134,6 +138,11 @@ public: }; //some functions provided by something else + enum ASTCFormat { + ASTC_FORMAT_4x4, + ASTC_FORMAT_8x8, + }; + static ImageMemLoadFunc _png_mem_loader_func; static ImageMemLoadFunc _jpg_mem_loader_func; static ImageMemLoadFunc _webp_mem_loader_func; @@ -144,11 +153,13 @@ public: static void (*_image_compress_bptc_func)(Image *, float p_lossy_quality, UsedChannels p_channels); static void (*_image_compress_etc1_func)(Image *, float); static void (*_image_compress_etc2_func)(Image *, float, UsedChannels p_channels); + static void (*_image_compress_astc_func)(Image *, float, ASTCFormat p_format); static void (*_image_decompress_bc)(Image *); static void (*_image_decompress_bptc)(Image *); static void (*_image_decompress_etc1)(Image *); static void (*_image_decompress_etc2)(Image *); + static void (*_image_decompress_astc)(Image *); static Vector<uint8_t> (*webp_lossy_packer)(const Ref<Image> &p_image, float p_quality); static Vector<uint8_t> (*webp_lossless_packer)(const Ref<Image> &p_image); @@ -351,6 +362,7 @@ public: COMPRESS_ETC, COMPRESS_ETC2, COMPRESS_BPTC, + COMPRESS_ASTC, COMPRESS_MAX, }; enum CompressSource { @@ -360,8 +372,8 @@ public: COMPRESS_SOURCE_MAX, }; - Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, float p_lossy_quality = 0.7); - Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality = 0.7); + Error compress(CompressMode p_mode, CompressSource p_source = COMPRESS_SOURCE_GENERIC, float p_lossy_quality = 0.7, ASTCFormat p_astc_format = ASTC_FORMAT_4x4); + Error compress_from_channels(CompressMode p_mode, UsedChannels p_channels, float p_lossy_quality = 0.7, ASTCFormat p_astc_format = ASTC_FORMAT_4x4); Error decompress(); bool is_compressed() const; @@ -432,5 +444,6 @@ VARIANT_ENUM_CAST(Image::CompressSource) VARIANT_ENUM_CAST(Image::UsedChannels) VARIANT_ENUM_CAST(Image::AlphaMode) VARIANT_ENUM_CAST(Image::RoughnessChannel) +VARIANT_ENUM_CAST(Image::ASTCFormat) #endif // IMAGE_H |