Browse Source

Improve memory usage for image import and PortableCompressedTexture2D

When importing images, we store a compressed version of the image to a .ctex file with ResourceImporterTexture::save_to_ctex_format.  When importing many large images at once, this can use a large amount of memory, especially when the .ctex file uses WebP format.

This change is for ResourceImporterTexture::save_to_ctex_format to use the original Image object instead of p_image->get_image_from_mipmap(0), to avoid creating a copy of the full uncompressed image when looping through the base Image and mipmaps.  This reduces the import memory usage for large images by around 10% when using WebP, and 35-40% when Project Settings/Rendering/Textures/Lossless Compression/Force PNG is enabled, may vary depending on the image and number of import threads running.  Same change applied to PortableCompressedTexture2D::create_from_image, which has similar logic.

This helps with #92084, but does not fully resolve the issue on its own, as compressing with WebP on many threads can still use a large amount of memory - this just lowers that amount, and makes it more likely that enabling "Force PNG" will reduce memory usage enough to import the files.
aaronp64 1 year ago
parent
commit
f81e0fcbf4

+ 3 - 3
editor/import/resource_importer_texture.cpp

@@ -269,9 +269,9 @@ void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<I
 			for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
 				Vector<uint8_t> data;
 				if (use_webp) {
-					data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i));
+					data = Image::webp_lossless_packer(i ? p_image->get_image_from_mipmap(i) : p_image);
 				} else {
-					data = Image::png_packer(p_image->get_image_from_mipmap(i));
+					data = Image::png_packer(i ? p_image->get_image_from_mipmap(i) : p_image);
 				}
 				int data_len = data.size();
 				f->store_32(data_len);
@@ -289,7 +289,7 @@ void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<I
 			f->store_32(p_image->get_format());
 
 			for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
-				Vector<uint8_t> data = Image::webp_lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality);
+				Vector<uint8_t> data = Image::webp_lossy_packer(i ? p_image->get_image_from_mipmap(i) : p_image, p_lossy_quality);
 				int data_len = data.size();
 				f->store_32(data_len);
 

+ 3 - 3
scene/resources/portable_compressed_texture.cpp

@@ -153,14 +153,14 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C
 			for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
 				Vector<uint8_t> data;
 				if (p_compression_mode == COMPRESSION_MODE_LOSSY) {
-					data = Image::webp_lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality);
+					data = Image::webp_lossy_packer(i ? p_image->get_image_from_mipmap(i) : p_image, p_lossy_quality);
 					encode_uint16(DATA_FORMAT_WEBP, buffer.ptrw() + 2);
 				} else {
 					if (use_webp) {
-						data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i));
+						data = Image::webp_lossless_packer(i ? p_image->get_image_from_mipmap(i) : p_image);
 						encode_uint16(DATA_FORMAT_WEBP, buffer.ptrw() + 2);
 					} else {
-						data = Image::png_packer(p_image->get_image_from_mipmap(i));
+						data = Image::png_packer(i ? p_image->get_image_from_mipmap(i) : p_image);
 						encode_uint16(DATA_FORMAT_PNG, buffer.ptrw() + 2);
 					}
 				}