diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp index 5364b53b57ea..7592e3568542 100644 --- a/editor/import/resource_importer_texture.cpp +++ b/editor/import/resource_importer_texture.cpp @@ -309,15 +309,11 @@ void ResourceImporterTexture::save_to_ctex_format(Ref f, const Refstore_16(p_image->get_height()); f->store_32(p_image->get_mipmap_count()); f->store_32(p_image->get_format()); - - for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) { - Vector data = Image::basis_universal_packer(p_image->get_image_from_mipmap(i), p_channels); - int data_len = data.size(); - f->store_32(data_len); - - const uint8_t *r = data.ptr(); - f->store_buffer(r, data_len); - } + Vector data = Image::basis_universal_packer(p_image, p_channels); + int data_len = data.size(); + f->store_32(data_len); + const uint8_t *r = data.ptr(); + f->store_buffer(r, data_len); } break; } } @@ -374,7 +370,8 @@ void ResourceImporterTexture::_save_ctex(const Ref &p_image, const String Ref image = p_image->duplicate(); - if (((p_compress_mode == COMPRESS_BASIS_UNIVERSAL) || (p_compress_mode == COMPRESS_VRAM_COMPRESSED && p_force_po2_for_compressed)) && p_mipmaps) { + if ((((p_compress_mode == COMPRESS_BASIS_UNIVERSAL) && p_force_po2_for_compressed) || (p_compress_mode == COMPRESS_VRAM_COMPRESSED && p_force_po2_for_compressed)) && + p_mipmaps) { image->resize_to_po2(); } diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp index e80d453df7fc..241a1608dcbd 100644 --- a/modules/basis_universal/register_types.cpp +++ b/modules/basis_universal/register_types.cpp @@ -32,9 +32,11 @@ #include "core/os/os.h" #include "servers/rendering_server.h" +#include #ifdef TOOLS_ENABLED #include +#include #endif #include @@ -52,44 +54,43 @@ enum BasisDecompressFormat { #ifdef TOOLS_ENABLED static Vector basis_universal_packer(const Ref &p_image, Image::UsedChannels p_channels) { Vector budata; - { + basisu::basis_compressor_params params; Ref image = p_image->duplicate(); - - // unfortunately, basis universal does not support compressing supplied mipmaps, - // so for the time being, only compressing individual images will have to do. - - if (image->has_mipmaps()) { - image->clear_mipmaps(); - } if (image->get_format() != Image::FORMAT_RGBA8) { image->convert(Image::FORMAT_RGBA8); } - - basisu::image buimg(image->get_width(), image->get_height()); - + Ref image_single = image->duplicate(); { - Vector vec = image->get_data(); + if (image_single->has_mipmaps()) { + image_single->clear_mipmaps(); + } + basisu::image buimg(image_single->get_width(), image_single->get_height()); + Vector vec = image_single->get_data(); const uint8_t *r = vec.ptr(); - memcpy(buimg.get_ptr(), r, vec.size()); + params.m_source_images.push_back(buimg); } - - basisu::basis_compressor_params params; - params.m_uastc = true; - params.m_max_endpoint_clusters = 512; - params.m_max_selector_clusters = 512; + basisu::vector source_images; + for (int32_t mipmap_i = 1; mipmap_i < image->get_mipmap_count(); mipmap_i++) { + Ref mip = image->get_image_from_mipmap(mipmap_i); + basisu::image buimg(mip->get_width(), mip->get_height()); + Vector vec = mip->get_data(); + const uint8_t *r = vec.ptr(); + memcpy(buimg.get_ptr(), r, vec.size()); + source_images.push_back(buimg); + } + params.m_source_mipmap_images.push_back(source_images); + params.m_quality_level = basisu::BASISU_QUALITY_MIN; + params.m_mip_fast = false; params.m_multithreading = true; - //params.m_quality_level = 0; - //params.m_disable_hierarchical_endpoint_codebooks = true; - //params.m_no_selector_rdo = true; + params.m_uastc = true; + params.m_rdo_uastc = true; + params.m_rdo_uastc_multithreading = true; basisu::job_pool jpool(OS::get_singleton()->get_processor_count()); params.m_pJob_pool = &jpool; - params.m_mip_gen = false; //sorry, please some day support provided mipmaps. - params.m_source_images.push_back(buimg); - BasisDecompressFormat decompress_format = BASIS_DECOMPRESS_RG; params.m_check_for_alpha = false; @@ -222,12 +223,16 @@ static Ref basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size ERR_FAIL_COND_V(!tr.validate_header(ptr, size), image); - basist::basisu_image_info info; - tr.get_image_info(ptr, size, info, 0); + basist::basisu_file_info info; + tr.get_file_info(ptr, size, info); + basist::basisu_image_info image_info; + tr.get_image_info(ptr, size, image_info, 0); int block_size = basist::basis_get_bytes_per_block_or_pixel(format); Vector gpudata; - gpudata.resize(info.m_total_blocks * block_size); + ERR_FAIL_INDEX_V(0, info.m_image_mipmap_levels.size(), Ref()); + uint32_t total_mip_levels = info.m_image_mipmap_levels[0]; + gpudata.resize(Image::get_image_data_size(image_info.m_width, image_info.m_height, imgfmt, total_mip_levels > 1)); { uint8_t *w = gpudata.ptrw(); @@ -238,11 +243,11 @@ static Ref basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size int ofs = 0; tr.start_transcoding(ptr, size); - for (uint32_t i = 0; i < info.m_total_levels; i++) { + for (uint32_t i = 0; i < total_mip_levels; i++) { basist::basisu_image_level_info level; tr.get_image_level_info(ptr, size, level, 0, i); - bool ret = tr.transcode_image_level(ptr, size, 0, i, dst + ofs, level.m_total_blocks - i, format); + bool ret = tr.transcode_image_level(ptr, size, 0, i, dst + ofs, level.m_total_blocks, format); if (!ret) { printf("failed! on level %u\n", i); break; @@ -250,10 +255,9 @@ static Ref basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size ofs += level.m_total_blocks * block_size; }; - }; - - image.instantiate(); - image->create(info.m_width, info.m_height, info.m_total_levels > 1, imgfmt, gpudata); + image.instantiate(); + image->create(image_info.m_width, image_info.m_height, total_mip_levels > 1, imgfmt, gpudata); + } return image; } diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 9442a58ac1d6..e281a9c87cb7 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -653,7 +653,7 @@ Ref CompressedTexture2D::load_image_from_file(Ref f, int p_si uint32_t mipmaps = f->get_32(); Image::Format format = Image::Format(f->get_32()); - if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP || data_format == DATA_FORMAT_BASIS_UNIVERSAL) { + if (data_format == DATA_FORMAT_PNG || data_format == DATA_FORMAT_WEBP) { //look for a PNG or WEBP file inside int sw = w; @@ -684,9 +684,7 @@ Ref CompressedTexture2D::load_image_from_file(Ref f, int p_si } Ref img; - if (data_format == DATA_FORMAT_BASIS_UNIVERSAL && Image::basis_universal_unpacker) { - img = Image::basis_universal_unpacker(pv); - } else if (data_format == DATA_FORMAT_PNG && Image::png_unpacker) { + if (data_format == DATA_FORMAT_PNG && Image::png_unpacker) { img = Image::png_unpacker(pv); } else if (data_format == DATA_FORMAT_WEBP && Image::webp_unpacker) { img = Image::webp_unpacker(pv); @@ -745,6 +743,32 @@ Ref CompressedTexture2D::load_image_from_file(Ref f, int p_si return image; } + } else if (data_format == DATA_FORMAT_BASIS_UNIVERSAL) { + int sw = w; + int sh = h; + uint32_t size = f->get_32(); + if (p_size_limit > 0 && (sw > p_size_limit || sh > p_size_limit)) { + //can't load this due to size limit + sw = MAX(sw >> 1, 1); + sh = MAX(sh >> 1, 1); + f->seek(f->get_position() + size); + return Ref(); + } + Vector pv; + pv.resize(size); + { + uint8_t *wr = pv.ptrw(); + f->get_buffer(wr, size); + } + Ref img; + img = Image::basis_universal_unpacker(pv); + if (img.is_null() || img->is_empty()) { + ERR_FAIL_COND_V(img.is_null() || img->is_empty(), Ref()); + } + format = img->get_format(); + sw = MAX(sw >> 1, 1); + sh = MAX(sh >> 1, 1); + return img; } else if (data_format == DATA_FORMAT_IMAGE) { int size = Image::get_image_data_size(w, h, format, mipmaps ? true : false);