Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Directly compress mip maps from Basis Universal #59540

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions editor/import/resource_importer_texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,15 +315,11 @@ void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<I
f->store_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<uint8_t> 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<uint8_t> 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;
}
}
Expand Down Expand Up @@ -380,7 +376,7 @@ void ResourceImporterTexture::_save_ctex(const Ref<Image> &p_image, const String

Ref<Image> 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_force_po2_for_compressed && p_mipmaps && ((p_compress_mode == COMPRESS_BASIS_UNIVERSAL) || (p_compress_mode == COMPRESS_VRAM_COMPRESSED))) {
image->resize_to_po2();
}

Expand Down
72 changes: 41 additions & 31 deletions modules/basis_universal/register_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,44 +52,51 @@ enum BasisDecompressFormat {
#ifdef TOOLS_ENABLED
static Vector<uint8_t> basis_universal_packer(const Ref<Image> &p_image, Image::UsedChannels p_channels) {
Vector<uint8_t> budata;

{
basisu::basis_compressor_params params;
Ref<Image> 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> image_single = image->duplicate();
{
Vector<uint8_t> 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<uint8_t> 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::vector<basisu::image> source_images;
for (int32_t mipmap_i = 1; mipmap_i < image->get_mipmap_count(); mipmap_i++) {
Ref<Image> mip = image->get_image_from_mipmap(mipmap_i);
basisu::image buimg(mip->get_width(), mip->get_height());
Vector<uint8_t> 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);

basisu::basis_compressor_params params;
params.m_uastc = true;
params.m_max_endpoint_clusters = 512;
params.m_max_selector_clusters = 512;
params.m_quality_level = basisu::BASISU_QUALITY_MIN;

params.m_pack_uastc_flags &= ~basisu::cPackUASTCLevelMask;

static const uint32_t s_level_flags[basisu::TOTAL_PACK_UASTC_LEVELS] = { basisu::cPackUASTCLevelFastest, basisu::cPackUASTCLevelFaster, basisu::cPackUASTCLevelDefault, basisu::cPackUASTCLevelSlower, basisu::cPackUASTCLevelVerySlow };
params.m_pack_uastc_flags |= s_level_flags[0];
params.m_rdo_uastc = 0.0f;
params.m_rdo_uastc_quality_scalar = 0.0f;
params.m_rdo_uastc_dict_size = 1024;

params.m_mip_fast = true;
params.m_multithreading = true;
//params.m_quality_level = 0;
//params.m_disable_hierarchical_endpoint_codebooks = true;
//params.m_no_selector_rdo = 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;

Expand Down Expand Up @@ -222,12 +229,16 @@ static Ref<Image> 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<uint8_t> gpudata;
gpudata.resize(info.m_total_blocks * block_size);
ERR_FAIL_INDEX_V(0, info.m_image_mipmap_levels.size(), Ref<Image>());
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();
Expand All @@ -238,22 +249,21 @@ static Ref<Image> 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;
};

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;
}
Expand Down
32 changes: 28 additions & 4 deletions scene/resources/texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> 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;
Expand Down Expand Up @@ -682,9 +682,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> f, int p_si
}

Ref<Image> 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);
Expand Down Expand Up @@ -743,6 +741,32 @@ Ref<Image> CompressedTexture2D::load_image_from_file(Ref<FileAccess> 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<Image>();
}
Vector<uint8_t> pv;
pv.resize(size);
{
uint8_t *wr = pv.ptrw();
f->get_buffer(wr, size);
}
Ref<Image> 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<Image>());
}
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);

Expand Down