Skip to content

Commit

Permalink
Misc improvements to Basis Universal.
Browse files Browse the repository at this point in the history
To increase efficiency enable compressed mip maps from Basis Universal.
To decrease corruption increase the quality.
To keep compatibility use the first mip of the previous internal Godot format.
  • Loading branch information
fire committed May 19, 2022
1 parent 920ca62 commit 2b7a458
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 47 deletions.
17 changes: 7 additions & 10 deletions editor/import/resource_importer_texture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,15 +309,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 @@ -374,7 +370,8 @@ 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_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();
}

Expand Down
70 changes: 37 additions & 33 deletions modules/basis_universal/register_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@

#include "core/os/os.h"
#include "servers/rendering_server.h"
#include <encoder/basisu_frontend.h>

#ifdef TOOLS_ENABLED
#include <encoder/basisu_comp.h>
#include <encoder/basisu_enc.h>
#endif

#include <transcoder/basisu_transcoder.h>
Expand All @@ -52,44 +54,43 @@ 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::basis_compressor_params params;
params.m_uastc = true;
params.m_max_endpoint_clusters = 512;
params.m_max_selector_clusters = 512;
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);
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;

Expand Down Expand Up @@ -222,12 +223,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 +243,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 @@ -653,7 +653,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 @@ -684,9 +684,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 @@ -745,6 +743,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

0 comments on commit 2b7a458

Please sign in to comment.