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

Add support for the low-level UASTC transcoder #8

Merged
merged 6 commits into from
Jan 28, 2022
Merged
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
11 changes: 10 additions & 1 deletion basis-universal-sys/generate_bindings.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ bindgen vendor/transcoding_wrapper.cpp -o src/transcoding_bindings.rs \
--whitelist-function basis_get_texture_type_name \
\
--whitelist-function basis_transcoder_format_is_uncompressed \
--whitelist-function basis_block_format_is_uncompressed \
--whitelist-function basis_get_uncompressed_bytes_per_pixel \
--whitelist-function basis_get_block_width \
--whitelist-function basis_get_block_height \
--whitelist-function basis_is_format_supported \
--whitelist-function basis_validate_output_buffer_size \
\
--whitelist-function low_level_uastc_transcoder_new \
--whitelist-function low_level_uastc_transcoder_delete \
\
--whitelist-function low_level_uastc_transcoder_transcode_slice \
\
--whitelist-function transcoder_new \
--whitelist-function transcoder_delete \
\
Expand All @@ -37,6 +43,9 @@ bindgen vendor/transcoding_wrapper.cpp -o src/transcoding_bindings.rs \
\
--whitelist-function basisu_transcoder_init \
\
--opaque-type LowLevelUastcTranscoder \
--opaque-type basist::block_format \
\
--opaque-type Transcoder \
--opaque-type basist::basisu_transcoder_state \
\
Expand Down Expand Up @@ -115,4 +124,4 @@ bindgen vendor/encoding_wrapper.cpp -o src/encoding_bindings.rs \
--opaque-type Compressor \
--opaque-type basisu::image \
\
-- -x c++ -std=c++14
-- -x c++ -std=c++14
50 changes: 50 additions & 0 deletions basis-universal-sys/src/transcoding_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,6 +881,9 @@ extern "C" {
tex_type: basist_transcoder_texture_format
) -> bool;
}
extern "C" {
pub fn basis_block_format_is_uncompressed(fmt: basist_block_format) -> bool;
}
extern "C" {
pub fn basis_get_uncompressed_bytes_per_pixel(fmt: basist_transcoder_texture_format) -> u32;
}
Expand Down Expand Up @@ -910,6 +913,53 @@ extern "C" {
#[repr(C)]
#[repr(align(8))]
#[derive(Debug, Copy, Clone)]
pub struct LowLevelUastcTranscoder {
pub _bindgen_opaque_blob: u64,
}
#[test]
fn bindgen_test_layout_LowLevelUastcTranscoder() {
assert_eq!(
::std::mem::size_of::<LowLevelUastcTranscoder>(),
8usize,
concat!("Size of: ", stringify!(LowLevelUastcTranscoder))
);
assert_eq!(
::std::mem::align_of::<LowLevelUastcTranscoder>(),
8usize,
concat!("Alignment of ", stringify!(LowLevelUastcTranscoder))
);
}
extern "C" {
pub fn low_level_uastc_transcoder_new() -> *mut LowLevelUastcTranscoder;
}
extern "C" {
pub fn low_level_uastc_transcoder_delete(transcoder: *mut LowLevelUastcTranscoder);
}
extern "C" {
pub fn low_level_uastc_transcoder_transcode_slice(
transcoder: *mut LowLevelUastcTranscoder,
pDst_blocks: *mut ::std::os::raw::c_void,
num_blocks_x: u32,
num_blocks_y: u32,
pImage_data: *const u8,
image_data_size: u32,
fmt: basist_block_format,
output_block_or_pixel_stride_in_bytes: u32,
bc1_allow_threecolor_blocks: bool,
has_alpha: bool,
orig_width: u32,
orig_height: u32,
output_row_pitch_in_blocks_or_pixels: u32,
pState: *mut basist_basisu_transcoder_state,
output_rows_in_pixels: u32,
channel0: ::std::os::raw::c_int,
channel1: ::std::os::raw::c_int,
decode_flags: u32,
) -> bool;
}
#[repr(C)]
#[repr(align(8))]
#[derive(Debug, Copy, Clone)]
pub struct Transcoder {
pub _bindgen_opaque_blob: [u64; 2usize],
}
Expand Down
61 changes: 60 additions & 1 deletion basis-universal-sys/vendor/transcoding_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,11 @@ extern "C" {
return basist::basis_transcoder_format_is_uncompressed(tex_type);
}

// Returns true if the block format is an uncompressed (raw pixel) format.
bool basis_block_format_is_uncompressed(basist::block_format fmt) {
return basist::basis_block_format_is_uncompressed(fmt);
}

// Returns the # of bytes per pixel for uncompressed formats, or 0 for block texture formats.
uint32_t basis_get_uncompressed_bytes_per_pixel(basist::transcoder_texture_format fmt) {
return basist::basis_get_uncompressed_bytes_per_pixel(fmt);
Expand Down Expand Up @@ -157,7 +162,61 @@ extern "C" {
// basisu_lowlevel_uastc_transcoder
//

// Not implemented
struct LowLevelUastcTranscoder {
basist::basisu_lowlevel_uastc_transcoder *pTranscoder;
};

LowLevelUastcTranscoder *low_level_uastc_transcoder_new() {
superdump marked this conversation as resolved.
Show resolved Hide resolved
LowLevelUastcTranscoder *transcoder = new LowLevelUastcTranscoder;
transcoder->pTranscoder = new basist::basisu_lowlevel_uastc_transcoder();
return transcoder;
}

void low_level_uastc_transcoder_delete(LowLevelUastcTranscoder *transcoder) {
delete transcoder->pTranscoder;
delete transcoder;
}

bool low_level_uastc_transcoder_transcode_slice(
LowLevelUastcTranscoder *transcoder,
void* pDst_blocks,
uint32_t num_blocks_x,
uint32_t num_blocks_y,
const uint8_t* pImage_data,
uint32_t image_data_size,
basist::block_format fmt,
uint32_t output_block_or_pixel_stride_in_bytes,
bool bc1_allow_threecolor_blocks,
bool has_alpha,
const uint32_t orig_width,
const uint32_t orig_height,
uint32_t output_row_pitch_in_blocks_or_pixels,
basist::basisu_transcoder_state* pState,
uint32_t output_rows_in_pixels,
int channel0,
int channel1,
uint32_t decode_flags
) {
return transcoder->pTranscoder->transcode_slice(
pDst_blocks,
num_blocks_x,
num_blocks_y,
pImage_data,
image_data_size,
fmt,
output_block_or_pixel_stride_in_bytes,
bc1_allow_threecolor_blocks,
has_alpha,
orig_width,
orig_height,
output_row_pitch_in_blocks_or_pixels,
pState,
output_rows_in_pixels,
channel0,
channel1,
decode_flags
);
}


//
Expand Down
196 changes: 195 additions & 1 deletion basis-universal/src/transcoding/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ impl TranscoderTextureFormat {
unsafe { sys::basis_transcoder_format_has_alpha(self.into()) }
}

/// Returns true if the transcoder texture type is an uncompressed (raw pixel) format.
/// Returns true if the transcoder texture type is a compressed format.
pub fn is_compressed(self) -> bool {
unsafe { !sys::basis_transcoder_format_is_uncompressed(self.into()) }
}
Expand Down Expand Up @@ -324,3 +324,197 @@ bitflags::bitflags! {
const HIGH_QULITY = sys::basist_basisu_decode_flags_cDecodeFlagsHighQuality;
}
}

/// The block format to transcode universal texture data into
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, PartialEq)]
#[repr(i32)]
pub enum TranscoderBlockFormat {
/// ETC1S RGB
ETC1 = sys::basist_block_format_cETC1,
/// full ETC2 EAC RGBA8 block
ETC2_RGBA = sys::basist_block_format_cETC2_RGBA,
/// DXT1 RGB
BC1 = sys::basist_block_format_cBC1,
/// BC4 block followed by a four color BC1 block
BC3 = sys::basist_block_format_cBC3,
/// DXT5A (alpha block only)
BC4 = sys::basist_block_format_cBC4,
/// two BC4 blocks
BC5 = sys::basist_block_format_cBC5,
/// opaque-only PVRTC1 4bpp
PVRTC1_4_RGB = sys::basist_block_format_cPVRTC1_4_RGB,
/// PVRTC1 4bpp RGBA
PVRTC1_4_RGBA = sys::basist_block_format_cPVRTC1_4_RGBA,
/// Full BC7 block, any mode
BC7 = sys::basist_block_format_cBC7,
/// RGB BC7 mode 5 color (writes an opaque mode 5 block)
BC7_M5_COLOR = sys::basist_block_format_cBC7_M5_COLOR,
/// alpha portion of BC7 mode 5 (cBC7_M5_COLOR output data must have been written to the output buffer first to set the mode/rot fields etc.)
BC7_M5_ALPHA = sys::basist_block_format_cBC7_M5_ALPHA,
/// alpha block of ETC2 EAC (first 8 bytes of the 16-bit ETC2 EAC RGBA format)
ETC2_EAC_A8 = sys::basist_block_format_cETC2_EAC_A8,
/// ASTC 4x4 (either color-only or color+alpha). Note that the transcoder always currently assumes sRGB is not enabled when outputting ASTC
/// data. If you use a sRGB ASTC format you'll get ~1 LSB of additional error, because of the different way ASTC decoders scale 8-bit endpoints to 16-bits during unpacking.
ASTC_4x4 = sys::basist_block_format_cASTC_4x4,

ATC_RGB = sys::basist_block_format_cATC_RGB,
ATC_RGBA_INTERPOLATED_ALPHA = sys::basist_block_format_cATC_RGBA_INTERPOLATED_ALPHA,
/// Opaque-only, has oddball 8x4 pixel block size
FXT1_RGB = sys::basist_block_format_cFXT1_RGB,

PVRTC2_4_RGB = sys::basist_block_format_cPVRTC2_4_RGB,
PVRTC2_4_RGBA = sys::basist_block_format_cPVRTC2_4_RGBA,

ETC2_EAC_R11 = sys::basist_block_format_cETC2_EAC_R11,
ETC2_EAC_RG11 = sys::basist_block_format_cETC2_EAC_RG11,

/// Used internally: Write 16-bit endpoint and selector indices directly to output (output block must be at least 32-bits)
Indices = sys::basist_block_format_cIndices,

/// Writes RGB components to 32bpp output pixels
RGB32 = sys::basist_block_format_cRGB32,
/// Writes RGB255 components to 32bpp output pixels
RGBA32 = sys::basist_block_format_cRGBA32,
/// Writes alpha component to 32bpp output pixels
A32 = sys::basist_block_format_cA32,

RGB565 = sys::basist_block_format_cRGB565,
BGR565 = sys::basist_block_format_cBGR565,

RGBA4444_COLOR = sys::basist_block_format_cRGBA4444_COLOR,
RGBA4444_ALPHA = sys::basist_block_format_cRGBA4444_ALPHA,
RGBA4444_COLOR_OPAQUE = sys::basist_block_format_cRGBA4444_COLOR_OPAQUE,
RGBA4444 = sys::basist_block_format_cRGBA4444,
}

impl Into<sys::basist_block_format> for TranscoderBlockFormat {
fn into(self) -> sys::basist_block_format {
self as sys::basist_block_format
}
}

impl From<sys::basist_block_format> for TranscoderBlockFormat {
fn from(value: sys::basist_block_format) -> Self {
unsafe { std::mem::transmute(value as i32) }
}
}

impl TranscoderBlockFormat {
/// For compressed texture formats, this returns the # of bytes per block. For uncompressed, it returns the # of bytes per pixel.
pub fn bytes_per_block_or_pixel(self) -> u32 {
match self {
TranscoderBlockFormat::ETC1 => 8,
aclysma marked this conversation as resolved.
Show resolved Hide resolved
TranscoderBlockFormat::ETC2_RGBA => 16,
TranscoderBlockFormat::BC1 => 8,
TranscoderBlockFormat::BC3 => 16,
TranscoderBlockFormat::BC4 => 8,
TranscoderBlockFormat::BC5 => 16,
TranscoderBlockFormat::PVRTC1_4_RGB => 8,
TranscoderBlockFormat::PVRTC1_4_RGBA => 8,
TranscoderBlockFormat::BC7 => 16,
TranscoderBlockFormat::BC7_M5_COLOR => 16,
TranscoderBlockFormat::BC7_M5_ALPHA => 16,
TranscoderBlockFormat::ETC2_EAC_A8 => 8,
TranscoderBlockFormat::ASTC_4x4 => 16,
TranscoderBlockFormat::ATC_RGB => 8,
TranscoderBlockFormat::ATC_RGBA_INTERPOLATED_ALPHA => 16,
TranscoderBlockFormat::FXT1_RGB => 8,
TranscoderBlockFormat::PVRTC2_4_RGB => 8,
TranscoderBlockFormat::PVRTC2_4_RGBA => 8,
TranscoderBlockFormat::ETC2_EAC_R11 => 8,
TranscoderBlockFormat::ETC2_EAC_RG11 => 16,
TranscoderBlockFormat::Indices => 2,
TranscoderBlockFormat::RGB32 => 4,
TranscoderBlockFormat::RGBA32 => 4,
TranscoderBlockFormat::A32 => 4,
TranscoderBlockFormat::RGB565 => 2,
TranscoderBlockFormat::BGR565 => 2,
TranscoderBlockFormat::RGBA4444_COLOR => 2,
TranscoderBlockFormat::RGBA4444_ALPHA => 2,
TranscoderBlockFormat::RGBA4444_COLOR_OPAQUE => 2,
TranscoderBlockFormat::RGBA4444 => 2,
}
}

/// Returns format's name in ASCII
pub fn format_name(self) -> &'static str {
unsafe {
let value = sys::basis_get_block_format_name(self.into());
CStr::from_ptr(value).to_str().unwrap()
}
}

/// Returns true if the block format is a compressed format.
pub fn is_compressed(self) -> bool {
unsafe { !sys::basis_block_format_is_uncompressed(self.into()) }
}

/// Returns the block width for the specified texture format, which is currently either 4 or 8 for FXT1.
pub fn block_width(self) -> u32 {
match self {
TranscoderBlockFormat::FXT1_RGB => 8,
_ => 4,
}
}

/// Returns the block height for the specified texture format, which is currently always 4.
pub fn block_height(self) -> u32 {
4
}

/// Calculate the minimum output buffer required to store transcoded data in blocks for
/// compressed formats and pixels for uncompressed formats
pub fn calculate_minimum_output_buffer_blocks_or_pixels(
self,
original_width: u32,
original_height: u32,
total_slice_blocks: u32,
output_row_pitch_in_blocks_or_pixels: Option<u32>,
output_rows_in_pixels: Option<u32>,
) -> u32 {
// Default of 0 is fine for these values
let mut output_row_pitch_in_blocks_or_pixels =
output_row_pitch_in_blocks_or_pixels.unwrap_or(0);
let mut output_rows_in_pixels = output_rows_in_pixels.unwrap_or(0);

// Derived from implementation of basis_validate_output_buffer_size

if !self.is_compressed() {
// Assume the output buffer is orig_width by orig_height
if output_row_pitch_in_blocks_or_pixels == 0 {
output_row_pitch_in_blocks_or_pixels = original_width;
}

if output_rows_in_pixels == 0 {
output_rows_in_pixels = original_height;
}

output_rows_in_pixels * output_row_pitch_in_blocks_or_pixels
} else if self == TranscoderBlockFormat::FXT1_RGB {
let num_blocks_fxt1_x = (original_width + 7) / 8;
let num_blocks_fxt1_y = (original_height + 3) / 4;
num_blocks_fxt1_x * num_blocks_fxt1_y
} else {
total_slice_blocks
}
}

/// Calculate the minimum output buffer required to store transcoded data in bytes
pub fn calculate_minimum_output_buffer_bytes(
self,
original_width: u32,
original_height: u32,
total_slice_blocks: u32,
output_row_pitch_in_blocks_or_pixels: Option<u32>,
output_rows_in_pixels: Option<u32>,
) -> u32 {
self.calculate_minimum_output_buffer_blocks_or_pixels(
original_width,
original_height,
total_slice_blocks,
output_row_pitch_in_blocks_or_pixels,
output_rows_in_pixels,
) * self.bytes_per_block_or_pixel()
}
}
Loading