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 1 commit
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
8 changes: 8 additions & 0 deletions basis-universal-sys/generate_bindings.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ bindgen vendor/transcoding_wrapper.cpp -o src/transcoding_bindings.rs \
--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 +42,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
47 changes: 47 additions & 0 deletions basis-universal-sys/src/transcoding_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,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_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;
}
extern "C" {
pub fn low_level_uastc_transcoder_delete(transcoder: *mut LowLevelUastcTranscoder);
}
#[repr(C)]
#[repr(align(8))]
#[derive(Debug, Copy, Clone)]
pub struct Transcoder {
pub _bindgen_opaque_blob: [u64; 2usize],
}
Expand Down
27 changes: 26 additions & 1 deletion basis-universal-sys/vendor/transcoding_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,32 @@ 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;
};

bool low_level_uastc_transcoder_transcode_slice(LowLevelUastcTranscoder *transcoder, void* pDst_blocks,
superdump marked this conversation as resolved.
Show resolved Hide resolved
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);
}

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


//
Expand Down
126 changes: 126 additions & 0 deletions basis-universal/src/transcoding/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,3 +324,129 @@ 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 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
}
}
87 changes: 87 additions & 0 deletions basis-universal/src/transcoding/transcoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,90 @@ impl Drop for Transcoder {
}
}
}

pub struct LowLevelUastcTranscoder(*mut sys::LowLevelUastcTranscoder);

impl Default for LowLevelUastcTranscoder {
fn default() -> Self {
Self::new()
}
}

#[derive(Debug)]
pub struct SliceParametersUastc {
pub num_blocks_x: u32,
pub num_blocks_y: u32,
pub has_alpha: bool,
pub original_width: u32,
pub original_height: u32,
}

impl LowLevelUastcTranscoder {
/// Create a LowLevelUastcTranscoder
pub fn new() -> LowLevelUastcTranscoder {
transcoder_init();
unsafe { LowLevelUastcTranscoder(sys::low_level_uastc_transcoder_new()) }
}

pub fn transcode_slice(
&self,
data: &[u8],
slice_parameters: SliceParametersUastc,
decode_flags: DecodeFlags,
transcode_block_format: TranscoderBlockFormat,
) -> Result<Vec<u8>, TranscodeError> {
let bc1_allow_threecolor_blocks = false;
let transcoder_state = std::ptr::null_mut();
let channel0 = 0;
let channel1 = 3;

let output_block_or_pixel_stride_in_bytes =
transcode_block_format.bytes_per_block_or_pixel();
let output_row_pitch_in_blocks_or_pixels =
(slice_parameters.original_width + transcode_block_format.block_width() - 1)
/ transcode_block_format.block_width();
let output_rows_in_pixels = slice_parameters.original_height;

let output_size_bytes = (slice_parameters.num_blocks_x
* slice_parameters.num_blocks_y
* output_block_or_pixel_stride_in_bytes) as usize;
aclysma marked this conversation as resolved.
Show resolved Hide resolved
let mut output = vec![0_u8; output_size_bytes];
let success = unsafe {
sys::low_level_uastc_transcoder_transcode_slice(
self.0,
output.as_mut_ptr() as _,
slice_parameters.num_blocks_x,
slice_parameters.num_blocks_y,
data.as_ptr() as _,
data.len() as u32,
transcode_block_format.into(),
output_block_or_pixel_stride_in_bytes,
bc1_allow_threecolor_blocks,
slice_parameters.has_alpha,
slice_parameters.original_width,
slice_parameters.original_height,
output_row_pitch_in_blocks_or_pixels,
transcoder_state,
output_rows_in_pixels,
channel0,
channel1,
decode_flags.bits(),
)
};

if success {
Ok(output)
} else {
Err(TranscodeError::TranscodeFailed)
}
}
}

impl Drop for LowLevelUastcTranscoder {
fn drop(&mut self) {
unsafe {
sys::low_level_uastc_transcoder_delete(self.0);
}
}
}