Skip to content

Commit 462fd4e

Browse files
authored
Support BGRA images in Vello Classic (#1173)
This is possible because of linebender/peniko#120. --------- Signed-off-by: sagudev <[email protected]>
1 parent bf4962a commit 462fd4e

File tree

5 files changed

+71
-14
lines changed

5 files changed

+71
-14
lines changed

vello/src/render.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,6 @@ impl Render {
152152
ImageProxy::new(images.width, images.height, ImageFormat::Rgba8)
153153
};
154154
for image in images.images {
155-
if image.0.format != peniko::ImageFormat::Rgba8 {
156-
unimplemented!("Unsupported image format: {:?}", image.0.format);
157-
}
158155
if image.0.alpha_type != peniko::ImageAlphaType::Alpha {
159156
unimplemented!("Unsupported image alpha type: {:?}", image.0.alpha_type);
160157
}

vello_encoding/src/encoding.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -432,9 +432,6 @@ impl Encoding {
432432
/// Encodes an image brush.
433433
pub fn encode_image<'b>(&mut self, brush: impl Into<ImageBrushRef<'b>>, alpha: f32) {
434434
let brush = brush.into();
435-
if brush.image.format != peniko::ImageFormat::Rgba8 {
436-
unimplemented!("Unsupported image format: {:?}", brush.image.format);
437-
}
438435
if brush.image.alpha_type != peniko::ImageAlphaType::Alpha {
439436
unimplemented!("Unsupported image alpha type: {:?}", brush.image.alpha_type);
440437
}
@@ -457,10 +454,11 @@ impl Encoding {
457454
.extend_from_slice(bytemuck::cast_slice(bytemuck::bytes_of(&DrawImage {
458455
xy: 0,
459456
width_height: (brush.image.width << 16) | (brush.image.height & 0xFFFF),
460-
sample_alpha: ((quality as u32) << 12)
457+
sample_alpha: ((brush.image.format as u32) << 14
458+
| (quality as u32) << 12
461459
| ((x_extend as u32) << 10)
462460
| ((y_extend as u32) << 8)
463-
| alpha as u32,
461+
| alpha as u32),
464462
})));
465463
}
466464

vello_shaders/shader/fine.wgsl

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -813,15 +813,16 @@ fn read_image(cmd_ix: u32) -> CmdImage {
813813
let width_height = info[info_offset + 7u];
814814
let sample_alpha = info[info_offset + 8u];
815815
let alpha = f32(sample_alpha & 0xFFu) / 255.0;
816-
let quality = sample_alpha >> 12u;
816+
let format = sample_alpha >> 14u;
817+
let quality = (sample_alpha >> 12u) & 0x3u;
817818
let x_extend = (sample_alpha >> 10u) & 0x3u;
818819
let y_extend = (sample_alpha >> 8u) & 0x3u;
819820
// The following are not intended to be bitcasts
820821
let x = f32(xy >> 16u);
821822
let y = f32(xy & 0xffffu);
822823
let width = f32(width_height >> 16u);
823824
let height = f32(width_height & 0xffffu);
824-
return CmdImage(matrx, xlat, vec2(x, y), vec2(width, height), x_extend, y_extend, quality, alpha);
825+
return CmdImage(matrx, xlat, vec2(x, y), vec2(width, height), format, x_extend, y_extend, quality, alpha);
825826
}
826827

827828
fn read_end_clip(cmd_ix: u32) -> CmdEndClip {
@@ -830,6 +831,21 @@ fn read_end_clip(cmd_ix: u32) -> CmdEndClip {
830831
return CmdEndClip(blend, alpha);
831832
}
832833

834+
const PIXEL_FORMAT_RGBA: u32 = 0u;
835+
const PIXEL_FORMAT_BGRA: u32 = 1u;
836+
// Normalises subpixel order loaded from an image, based on the image's format.
837+
fn pixel_format(pixel: vec4f, format: u32) -> vec4f {
838+
switch format {
839+
case PIXEL_FORMAT_BGRA: {
840+
// The conversion from RGBA to BGRA is its own inverse.
841+
return pixel.bgra;
842+
}
843+
case PIXEL_FORMAT_RGBA, default: {
844+
return pixel;
845+
}
846+
}
847+
}
848+
833849
const EXTEND_PAD: u32 = 0u;
834850
const EXTEND_REPEAT: u32 = 1u;
835851
const EXTEND_REFLECT: u32 = 2u;
@@ -1198,13 +1214,13 @@ fn main(
11981214
let atlas_uv_clamped = clamp(atlas_uv, image.atlas_offset, atlas_max);
11991215
// Nearest neighbor sampling
12001216
let fg_rgba = premul_alpha(textureLoad(image_atlas, vec2<i32>(atlas_uv_clamped), 0));
1201-
let fg_i = fg_rgba * area[i] * image.alpha;
1217+
let fg_i = pixel_format(fg_rgba * area[i] * image.alpha, image.format);
12021218
rgba[i] = rgba[i] * (1.0 - fg_i.a) + fg_i;
12031219
}
12041220
}
12051221
}
12061222
case IMAGE_QUALITY_MEDIUM, default: {
1207-
// We don't have an implementation for `IMAGE_QUALITY_HIGH` yet, just use the same as medium
1223+
// We don't have an implementation for `IMAGE_QUALITY_HIGH` yet, just use the same as medium
12081224
for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) {
12091225
// We only need to load from the textures if the value will be used.
12101226
if area[i] != 0.0 {
@@ -1225,7 +1241,7 @@ fn main(
12251241
let d = premul_alpha(textureLoad(image_atlas, vec2<i32>(uv_quad.zw), 0));
12261242
// Bilinear sampling
12271243
let fg_rgba = mix(mix(a, b, uv_frac.y), mix(c, d, uv_frac.y), uv_frac.x);
1228-
let fg_i = fg_rgba * area[i] * image.alpha;
1244+
let fg_i = pixel_format(fg_rgba * area[i] * image.alpha, image.format);
12291245
rgba[i] = rgba[i] * (1.0 - fg_i.a) + fg_i;
12301246
}
12311247
}

vello_shaders/shader/shared/ptcl.wgsl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ struct CmdColor {
4949
struct CmdBlurRect {
5050
// Solid fill color.
5151
rgba_color: u32,
52-
52+
5353
// 2x2 transformation matrix (inverse).
5454
matrx: vec4<f32>,
5555
// 2D translation (inverse)
@@ -97,6 +97,7 @@ struct CmdImage {
9797
xlat: vec2<f32>,
9898
atlas_offset: vec2<f32>,
9999
extents: vec2<f32>,
100+
format: u32,
100101
x_extend_mode: u32,
101102
y_extend_mode: u32,
102103
quality: u32,

vello_tests/tests/property.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use vello::Scene;
1515
use vello::kurbo::{Affine, Rect};
1616
use vello::peniko::{Brush, Color, ImageFormat, color::palette};
17+
use vello::peniko::{ImageAlphaType, ImageData, ImageSampler};
1718
use vello_tests::TestParams;
1819

1920
fn simple_square(use_cpu: bool) {
@@ -101,3 +102,47 @@ fn empty_scene_gpu() {
101102
fn empty_scene_cpu() {
102103
empty_scene(true);
103104
}
105+
106+
#[test]
107+
#[cfg_attr(skip_gpu_tests, ignore)]
108+
fn bgra_image() {
109+
let mut scene = Scene::new();
110+
let colors = [
111+
palette::css::RED,
112+
palette::css::BLUE,
113+
palette::css::LIME,
114+
palette::css::WHITE,
115+
];
116+
let blob: Vec<u8> = colors
117+
.iter()
118+
.flat_map(|c| {
119+
let [r, g, b, a] = c.to_rgba8().to_u8_array();
120+
[b, g, r, a]
121+
})
122+
.collect();
123+
let image = vello::peniko::ImageBrush {
124+
image: ImageData {
125+
data: blob.into(),
126+
format: ImageFormat::Bgra8,
127+
width: 2,
128+
height: 2,
129+
alpha_type: ImageAlphaType::Alpha,
130+
},
131+
sampler: ImageSampler {
132+
quality: vello::peniko::ImageQuality::Low,
133+
..Default::default()
134+
},
135+
};
136+
scene.draw_image(&image, Affine::IDENTITY);
137+
let scene_image =
138+
vello_tests::render_then_debug_sync(&scene, &TestParams::new("bgra", 2, 2)).unwrap();
139+
assert_eq!(scene_image.format, ImageFormat::Rgba8);
140+
for (i, pixel) in scene_image.data.data().chunks_exact(4).enumerate() {
141+
let &[r, g, b, a] = pixel else { unreachable!() };
142+
let image_color = Color::from_rgba8(r, g, b, a);
143+
let color = colors[i];
144+
if image_color.premultiply().difference(color.premultiply()) > 1e-4 {
145+
panic!("Got {image_color:?}, expected color {color:?}");
146+
}
147+
}
148+
}

0 commit comments

Comments
 (0)