Skip to content
Open
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
18 changes: 18 additions & 0 deletions pixel_bridge/build_defs.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"""Build definitions for pixel bridge."""

# Platforms where Rust decoding is unavailable.
UNSUPPORTED_PLATFORMS_RUST = (
"//tools/cc_target_os:chromiumos",
"//tools/cc_target_os:darwin",
"//tools/cc_target_os:fuchsia",
"//tools/cc_target_os:android",
"//tools/cc_target_os:wasm",
"//tools/cc_target_os:hercules_embedded",
"//tools/cc_target_os:platform_ios",
"//tools/cc_target_os:platform_tvos",
"//tools/cc_target_os:platform_visionos",
"//tools/cc_target_os:platform_watchos",
"//tools/cc_target_os:mpu64",
"//tools/cc_target_os:nestcam_ambarella",
"//tools/cc_target_os:windows",
)
39 changes: 31 additions & 8 deletions pixel_bridge/rust/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,14 @@ pub enum PixelType {
F32,
}

impl From<RustColorType> for PixelType {
fn from(value: RustColorType) -> Self {
// We deliberately do not implement the `From` trait here.
// Crubit automatically generates C++ bindings for all `From` implementations targeting FFI types.
// Exporting this to C++ forces LLVM to expose an exhaustive switch jump table across FFI.
// In massive ML binaries, this FFI exposure causes the `.rodata` jump table to exceed the 2GB FFI
// offset distance to the `.text` segment, triggering `relocation R_X86_64_PC32 out of range`.
// By using a private inherent method, Crubit ignores it.
impl PixelType {
fn from_rust_color_type(value: RustColorType) -> Self {
match value {
RustColorType::L8 | RustColorType::La8 | RustColorType::Rgb8 | RustColorType::Rgba8 => {
PixelType::U8
Expand Down Expand Up @@ -202,8 +208,14 @@ pub struct Strides {
pub channels: usize,
}

impl From<RustColorType> for ColorType {
fn from(value: RustColorType) -> Self {
// We deliberately do not implement the `From` trait here.
// Crubit automatically generates C++ bindings for all `From` implementations targeting FFI types.
// Exporting this to C++ forces LLVM to expose an exhaustive switch jump table across FFI.
// In massive ML binaries, this FFI exposure causes the `.rodata` jump table to exceed the 2GB FFI
// offset distance to the `.text` segment, triggering `relocation R_X86_64_PC32 out of range`.
// By using a private inherent method, Crubit ignores it.
impl ColorType {
fn from_rust_color_type(value: RustColorType) -> Self {
match value {
RustColorType::L8 | RustColorType::L16 => ColorType::L,
RustColorType::La8 | RustColorType::La16 => ColorType::La,
Expand Down Expand Up @@ -286,17 +298,24 @@ impl Frames {
}

fn format_panic(err: Box<dyn std::any::Any + Send>) -> String {
let backtrace = std::backtrace::Backtrace::capture();
let msg = if let Some(msg) = err.downcast_ref::<&str>() {
*msg
} else if let Some(msg) = err.downcast_ref::<String>() {
msg.as_str()
} else {
"Unknown panic payload"
};

// Capturing backtraces under TSAN can cause deadlocks.
let backtrace = if std::env::var("RUST_BACKTRACE").is_ok() {
format!("\nBacktrace:\n{}", std::backtrace::Backtrace::capture())
} else {
String::new()
};

// This error message needs to start with "Rust panic caught", as
// that is how we identify it on the C++ side.
format!("Rust panic caught: {}\nBacktrace:\n{}", msg, backtrace)
format!("Rust panic caught: {}{}", msg, backtrace)
}

fn run_catching_panics<F, T>(f: F) -> Result<T, String>
Expand Down Expand Up @@ -454,12 +473,16 @@ impl ImageDecoder {

/// Returns the color type of the image data produced by this decoder.
pub fn color_type(&self) -> ColorType {
self.inner.as_ref().map_or(Default::default(), |inner| ColorType::from(inner.color_type()))
self.inner
.as_ref()
.map_or(Default::default(), |inner| ColorType::from_rust_color_type(inner.color_type()))
}

/// Returns the PixelType of the image data produced by this decoder.
pub fn pixel_type(&self) -> PixelType {
self.inner.as_ref().map_or(Default::default(), |inner| PixelType::from(inner.color_type()))
self.inner
.as_ref()
.map_or(Default::default(), |inner| PixelType::from_rust_color_type(inner.color_type()))
}

/// Returns the format of the image.
Expand Down
18 changes: 12 additions & 6 deletions pixel_bridge/rust/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,15 @@ pub enum Format {
Ico,
}

impl From<Format> for ImageFormat {
fn from(value: Format) -> ImageFormat {
match value {
// We deliberately do not implement the `From` trait here.
// Crubit automatically generates C++ bindings for all `From` implementations targeting FFI types.
// Exporting this to C++ forces LLVM to expose an exhaustive switch jump table across FFI.
// In massive ML binaries, this FFI exposure causes the `.rodata` jump table to exceed the 2GB FFI
// offset distance to the `.text` segment, triggering `relocation R_X86_64_PC32 out of range`.
// By using a private inherent method, Crubit ignores it.
impl Format {
fn into_image_format(self) -> ImageFormat {
match self {
Format::Png => ImageFormat::Png,
Format::Jpeg => ImageFormat::Jpeg,
Format::Gif => ImageFormat::Gif,
Expand Down Expand Up @@ -94,7 +100,7 @@ impl ImageReader {
let Some(ref mut inner) = self.inner else {
return;
};
inner.set_format(format.into())
inner.set_format(format.into_image_format())
}

/// Read the image.
Expand All @@ -116,8 +122,8 @@ impl ImageReader {
};
// Delegate to non-inlined helper functions to reduce the stack frame size by 4k.
match inner.format() {
Some(ImageFormat::Png) => png(inner),
Some(ImageFormat::Jpeg) => jpeg(inner),
Some(ImageFormat::Png) => png(inner, self.png_ignore_checksums),
Some(ImageFormat::Jpeg) => jpeg(inner, self.jpeg_strict_mode),
Some(ImageFormat::WebP) => webp(inner),
Some(ImageFormat::Gif) => gif(inner),
Some(ImageFormat::Tiff) => tiff(inner),
Expand Down
Loading