Skip to content

Commit 6503dee

Browse files
committed
BasisU: Use KTX2 format and add import options to configure encoder
1 parent 80a3d20 commit 6503dee

17 files changed

+193
-61
lines changed

core/io/image.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ void (*Image::_image_decompress_astc)(Image *) = nullptr;
104104
Vector<uint8_t> (*Image::webp_lossy_packer)(const Ref<Image> &, float) = nullptr;
105105
Vector<uint8_t> (*Image::webp_lossless_packer)(const Ref<Image> &) = nullptr;
106106
Vector<uint8_t> (*Image::png_packer)(const Ref<Image> &) = nullptr;
107-
Vector<uint8_t> (*Image::basis_universal_packer)(const Ref<Image> &, Image::UsedChannels) = nullptr;
107+
Vector<uint8_t> (*Image::basis_universal_packer)(const Ref<Image> &p_image, Image::UsedChannels p_channels, const BasisUniversalPackerParams &p_basisu_params) = nullptr;
108108

109109
Ref<Image> (*Image::webp_unpacker)(const Vector<uint8_t> &) = nullptr;
110110
Ref<Image> (*Image::png_unpacker)(const Vector<uint8_t> &) = nullptr;

core/io/image.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ class Image : public Resource {
182182
ALPHA_BLEND
183183
};
184184

185+
struct BasisUniversalPackerParams {
186+
int uastc_level = 0;
187+
float rdo_quality_loss = 0;
188+
};
189+
185190
// External saver function pointers.
186191

187192
static inline SavePNGFunc save_png_func = nullptr;
@@ -231,7 +236,7 @@ class Image : public Resource {
231236
static Vector<uint8_t> (*webp_lossy_packer)(const Ref<Image> &p_image, float p_quality);
232237
static Vector<uint8_t> (*webp_lossless_packer)(const Ref<Image> &p_image);
233238
static Vector<uint8_t> (*png_packer)(const Ref<Image> &p_image);
234-
static Vector<uint8_t> (*basis_universal_packer)(const Ref<Image> &p_image, UsedChannels p_channels);
239+
static Vector<uint8_t> (*basis_universal_packer)(const Ref<Image> &p_image, Image::UsedChannels p_channels, const BasisUniversalPackerParams &p_basisu_params);
235240

236241
static Ref<Image> (*webp_unpacker)(const Vector<uint8_t> &p_buffer);
237242
static Ref<Image> (*png_unpacker)(const Vector<uint8_t> &p_buffer);

doc/classes/PortableCompressedTexture2D.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@
4343
Return whether the flag is overridden for all textures of this type.
4444
</description>
4545
</method>
46+
<method name="set_basisu_compressor_params">
47+
<return type="void" />
48+
<param index="0" name="uastc_level" type="int" />
49+
<param index="1" name="rdo_quality_loss" type="float" />
50+
<description>
51+
Sets the compressor parameters for Basis Universal compression. See also the settings in [ResourceImporterTexture].
52+
[b]Note:[/b] This must be set before [method create_from_image] to take effect.
53+
</description>
54+
</method>
4655
<method name="set_keep_all_compressed_buffers" qualifiers="static">
4756
<return type="void" />
4857
<param index="0" name="keep" type="bool" />
@@ -55,6 +64,7 @@
5564
<member name="keep_compressed_buffer" type="bool" setter="set_keep_compressed_buffer" getter="is_keeping_compressed_buffer" default="false">
5665
When running on the editor, this class will keep the source compressed data in memory. Otherwise, the source compressed data is lost after loading and the resource can't be re saved.
5766
This flag allows to keep the compressed data in memory if you intend it to persist after loading.
67+
[b]Note:[/b] This must be set before [method create_from_image] to take effect.
5868
</member>
5969
<member name="resource_local_to_scene" type="bool" setter="set_local_to_scene" getter="is_local_to_scene" overrides="Resource" default="false" />
6070
<member name="size_override" type="Vector2" setter="set_size_override" getter="get_size_override" default="Vector2(0, 0)">

doc/classes/ProjectSettings.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3257,6 +3257,16 @@
32573257
<member name="rendering/shading/overrides/force_vertex_shading" type="bool" setter="" getter="" default="false">
32583258
If [code]true[/code], forces vertex shading for all rendering. This can increase performance a lot, but also reduces quality immensely. Can be used to optimize performance on low-end mobile devices.
32593259
</member>
3260+
<member name="rendering/textures/basis_universal/rdo_dict_size" type="int" setter="" getter="" default="1024">
3261+
The dictionary size for Rate-Distortion Optimization (RDO) when importing textures as basis universal and when RDO is enabled, ranging from [code]64[/code] to [code]65536[/code]. Higher values reduce the file sizes further, but significantly make encoding times longer.
3262+
</member>
3263+
<member name="rendering/textures/basis_universal/zstd_supercompression" type="bool" setter="" getter="" default="true">
3264+
If [code]true[/code], enables Zstandard supercompression to reduce file size when importing textures as basis universal.
3265+
[b]Note:[/b] Basis Universal textures need to be compressed to gain the benefit of smaller file sizes, otherwise they are as large as VRAM-compressed textures.
3266+
</member>
3267+
<member name="rendering/textures/basis_universal/zstd_supercompression_level" type="int" setter="" getter="" default="6">
3268+
Specify the compression level for basis universal zstd supercompression, ranging from [code]1[/code] to [code]22[/code].
3269+
</member>
32603270
<member name="rendering/textures/canvas_textures/default_texture_filter" type="int" setter="" getter="" default="1">
32613271
The default texture filtering mode to use for [CanvasItem]s built-in texture. In shaders, this texture is accessed as [code]TEXTURE[/code].
32623272
[b]Note:[/b] For pixel art aesthetics, see also [member rendering/2d/snap/snap_2d_vertices_to_pixel] and [member rendering/2d/snap/snap_2d_transforms_to_pixel].

doc/classes/ResourceImporterLayeredTexture.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@
4040
[b]Basis Universal:[/b] Reduced quality, low memory usage, lowest size on disk, slow import. Only use for textures in 3D scenes, not for 2D elements.
4141
See [url=$DOCS_URL/tutorials/assets_pipeline/importing_images.html#compress-mode]Compress mode[/url] in the manual for more details.
4242
</member>
43+
<member name="compress/rdo_quality_loss" type="float" setter="" getter="" default="0.0">
44+
If greater than or equal to [code]0.01[/code], enables Rate-Distortion Optimization (RDO) to reduce file size. Higher values result in smaller file sizes but lower quality.
45+
[b]Note:[/b] Enabling RDO significantly significantly makes encoding times longer, especially when [member ProjectSettings.rendering/textures/basis_universal/rdo_dict_size] is high.
46+
See also [member ProjectSettings.rendering/textures/basis_universal/rdo_dict_size] and [member ProjectSettings.rendering/textures/basis_universal/zstd_supercompression_level] if you want to reduce the file size further.
47+
</member>
48+
<member name="compress/uastc_level" type="int" setter="" getter="" default="0">
49+
The UASTC encoding level. Higher values result in better quality but make encoding times longer.
50+
</member>
4351
<member name="mipmaps/generate" type="bool" setter="" getter="" default="true">
4452
If [code]true[/code], smaller versions of the texture are generated on import. For example, a 64×64 texture will generate 6 mipmaps (32×32, 16×16, 8×8, 4×4, 2×2, 1×1). This has several benefits:
4553
- Textures will not become grainy in the distance (in 3D), or if scaled down due to [Camera2D] zoom or [CanvasItem] scale (in 2D).

doc/classes/ResourceImporterTexture.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@
4343
When using a texture as normal map, only the red and green channels are required. Given regular texture compression algorithms produce artifacts that don't look that nice in normal maps, the RGTC compression format is the best fit for this data. Forcing this option to Enable will make Godot import the image as RGTC compressed. By default, it's set to Detect. This means that if the texture is ever detected to be used as a normal map, it will be changed to Enable and reimported automatically.
4444
Note that RGTC compression affects the resulting normal map image. You will have to adjust custom shaders that use the normal map's blue channel to take this into account. Built-in material shaders already ignore the blue channel in a normal map (regardless of the actual normal map's contents).
4545
</member>
46+
<member name="compress/rdo_quality_loss" type="float" setter="" getter="" default="0.0">
47+
If greater than or equal to [code]0.01[/code], enables Rate-Distortion Optimization (RDO) to reduce file size. Higher values result in smaller file sizes but lower quality.
48+
[b]Note:[/b] Enabling RDO significantly significantly makes encoding times longer, especially when [member ProjectSettings.rendering/textures/basis_universal/rdo_dict_size] is high.
49+
See also [member ProjectSettings.rendering/textures/basis_universal/rdo_dict_size] and [member ProjectSettings.rendering/textures/basis_universal/zstd_supercompression_level] if you want to reduce the file size further.
50+
</member>
51+
<member name="compress/uastc_level" type="int" setter="" getter="" default="0">
52+
The UASTC encoding level. Higher values result in better quality but make encoding times longer.
53+
</member>
4654
<member name="detect_3d/compress_to" type="int" setter="" getter="" default="1">
4755
This changes the [member compress/mode] option that is used when a texture is detected as being used in 3D.
4856
Changing this import option only has an effect if a texture is detected as being used in 3D. Changing this to [b]Disabled[/b] then reimporting will not change the existing compress mode on a texture (if it's detected to be used in 3D), but choosing [b]VRAM Compressed[/b] or [b]Basis Universal[/b] will.

editor/editor_property_name_processor.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
261261
capitalize_string_remaps["pvs"] = "PVS";
262262
capitalize_string_remaps["rcedit"] = "rcedit";
263263
capitalize_string_remaps["rcodesign"] = "rcodesign";
264+
capitalize_string_remaps["rdo"] = "RDO";
264265
capitalize_string_remaps["rgb"] = "RGB";
265266
capitalize_string_remaps["rid"] = "RID";
266267
capitalize_string_remaps["rmb"] = "RMB";
@@ -289,6 +290,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
289290
capitalize_string_remaps["textfile"] = "TextFile";
290291
capitalize_string_remaps["tls"] = "TLS";
291292
capitalize_string_remaps["tv"] = "TV";
293+
capitalize_string_remaps["uastc"] = "UASTC";
292294
capitalize_string_remaps["ui"] = "UI";
293295
capitalize_string_remaps["uri"] = "URI";
294296
capitalize_string_remaps["url"] = "URL";

editor/import/resource_importer_layered_texture.cpp

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,10 @@ bool ResourceImporterLayeredTexture::get_option_visibility(const String &p_path,
125125
if ((p_option == "compress/high_quality" || p_option == "compress/hdr_compression") && p_options.has("compress/mode")) {
126126
return int(p_options["compress/mode"]) == COMPRESS_VRAM_COMPRESSED;
127127
}
128+
if (p_option == "compress/uastc_level" || p_option == "compress/rdo_quality_loss") {
129+
return int(p_options["compress/mode"]) == COMPRESS_BASIS_UNIVERSAL;
130+
}
131+
128132
return true;
129133
}
130134

@@ -140,6 +144,11 @@ void ResourceImporterLayeredTexture::get_import_options(const String &p_path, Li
140144
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));
141145
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress/high_quality"), false));
142146
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/lossy_quality", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.7));
147+
148+
Image::BasisUniversalPackerParams basisu_params;
149+
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/uastc_level", PROPERTY_HINT_ENUM, "Fastest,Faster,Medium,Slower,Slowest"), basisu_params.uastc_level));
150+
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "compress/rdo_quality_loss", PROPERTY_HINT_RANGE, "0,10,0.001,or_greater"), basisu_params.rdo_quality_loss));
151+
143152
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/hdr_compression", PROPERTY_HINT_ENUM, "Disabled,Opaque Only,Always"), 1));
144153
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "compress/channel_pack", PROPERTY_HINT_ENUM, "sRGB Friendly,Optimized,Normal Map (RG Channels)"), 0));
145154
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "mipmaps/generate"), true));
@@ -158,7 +167,7 @@ void ResourceImporterLayeredTexture::get_import_options(const String &p_path, Li
158167
}
159168
}
160169

161-
void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, const String &p_to_path, int p_compress_mode, float p_lossy, Image::CompressMode p_vram_compression, Image::CompressSource p_csource, Image::UsedChannels used_channels, bool p_mipmaps, bool p_force_po2) {
170+
void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> 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) {
162171
Vector<Ref<Image>> mipmap_images; //for 3D
163172

164173
if (mode == MODE_3D) {
@@ -278,11 +287,11 @@ void ResourceImporterLayeredTexture::_save_tex(Vector<Ref<Image>> p_images, cons
278287
}
279288

280289
for (int i = 0; i < p_images.size(); i++) {
281-
ResourceImporterTexture::save_to_ctex_format(f, p_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy);
290+
ResourceImporterTexture::save_to_ctex_format(f, p_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy, p_basisu_params);
282291
}
283292

284293
for (int i = 0; i < mipmap_images.size(); i++) {
285-
ResourceImporterTexture::save_to_ctex_format(f, mipmap_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy);
294+
ResourceImporterTexture::save_to_ctex_format(f, mipmap_images[i], ResourceImporterTexture::CompressMode(p_compress_mode), used_channels, p_vram_compression, p_lossy, p_basisu_params);
286295
}
287296
}
288297

@@ -375,6 +384,13 @@ Error ResourceImporterLayeredTexture::import(ResourceUID::ID p_source_id, const
375384
slices.push_back(slice);
376385
}
377386
}
387+
388+
const Image::BasisUniversalPackerParams basisu_params = {
389+
p_options["compress/uastc_level"],
390+
p_options["compress/rdo_quality_loss"],
391+
392+
};
393+
378394
Array formats_imported;
379395
Ref<LayeredTextureImport> texture_import;
380396
texture_import.instantiate();
@@ -392,6 +408,8 @@ Error ResourceImporterLayeredTexture::import(ResourceUID::ID p_source_id, const
392408
texture_import->used_channels = used_channels;
393409
texture_import->high_quality = high_quality;
394410

411+
texture_import->basisu_params = basisu_params;
412+
395413
_check_compress_ctex(p_source_file, texture_import);
396414
if (r_metadata) {
397415
Dictionary meta;
@@ -486,7 +504,8 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source
486504
ERR_FAIL_NULL(r_texture_import->csource);
487505
if (r_texture_import->compress_mode != COMPRESS_VRAM_COMPRESSED) {
488506
// Import normally.
489-
_save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, Image::COMPRESS_S3TC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false);
507+
_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,
508+
Image::COMPRESS_S3TC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false);
490509
return;
491510
}
492511
// Must import in all formats, in order of priority (so platform chooses the best supported one. IE, etc2 over etc).
@@ -541,7 +560,8 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source
541560
}
542561

543562
if (use_uncompressed) {
544-
_save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + extension, COMPRESS_VRAM_UNCOMPRESSED, r_texture_import->lossy, Image::COMPRESS_S3TC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false);
563+
_save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + extension, COMPRESS_VRAM_UNCOMPRESSED, r_texture_import->lossy, r_texture_import->basisu_params,
564+
Image::COMPRESS_S3TC /* IGNORED */, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, false);
545565
} else {
546566
if (can_s3tc_bptc) {
547567
Image::CompressMode image_compress_mode;
@@ -553,7 +573,7 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source
553573
image_compress_mode = Image::COMPRESS_S3TC;
554574
image_compress_format = "s3tc";
555575
}
556-
_save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + image_compress_format + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, image_compress_mode, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true);
576+
_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);
557577
r_texture_import->platform_variants->push_back(image_compress_format);
558578
}
559579

@@ -567,7 +587,7 @@ void ResourceImporterLayeredTexture::_check_compress_ctex(const String &p_source
567587
image_compress_mode = Image::COMPRESS_ETC2;
568588
image_compress_format = "etc2";
569589
}
570-
_save_tex(*r_texture_import->slices, r_texture_import->save_path + "." + image_compress_format + "." + extension, r_texture_import->compress_mode, r_texture_import->lossy, image_compress_mode, *r_texture_import->csource, r_texture_import->used_channels, r_texture_import->mipmaps, true);
590+
_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);
571591
r_texture_import->platform_variants->push_back(image_compress_format);
572592
}
573593
}

editor/import/resource_importer_layered_texture.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ class LayeredTextureImport : public RefCounted {
4949
Vector<Ref<Image>> *slices = nullptr;
5050
int compress_mode = 0;
5151
float lossy = 1.0;
52+
53+
Image::BasisUniversalPackerParams basisu_params;
54+
5255
int hdr_compression = 0;
5356
bool mipmaps = true;
5457
bool high_quality = false;
@@ -108,7 +111,7 @@ class ResourceImporterLayeredTexture : public ResourceImporter {
108111
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
109112
virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
110113

111-
void _save_tex(Vector<Ref<Image>> p_images, const String &p_to_path, int p_compress_mode, float p_lossy, Image::CompressMode p_vram_compression, Image::CompressSource p_csource, Image::UsedChannels used_channels, bool p_mipmaps, bool p_force_po2);
114+
void _save_tex(Vector<Ref<Image>> 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);
112115

113116
virtual Error import(ResourceUID::ID p_source_id, const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
114117

0 commit comments

Comments
 (0)