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 Mar 26, 2022
1 parent fec2486 commit 8916a04
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 @@ -303,15 +303,11 @@ void ResourceImporterTexture::save_to_ctex_format(FileAccess *f, const Ref<Image
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 @@ -368,7 +364,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 @@ -223,12 +224,16 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {

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 @@ -239,22 +244,21 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {

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 %i\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 @@ -347,7 +347,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(FileAccess *f, int p_size_l
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 @@ -378,9 +378,7 @@ Ref<Image> CompressedTexture2D::load_image_from_file(FileAccess *f, int p_size_l
}

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 @@ -439,6 +437,32 @@ Ref<Image> CompressedTexture2D::load_image_from_file(FileAccess *f, int p_size_l
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 8916a04

Please sign in to comment.