Skip to content
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
3 changes: 0 additions & 3 deletions vello/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,6 @@ impl Render {
ImageProxy::new(images.width, images.height, ImageFormat::Rgba8)
};
for image in images.images {
if image.0.format != peniko::ImageFormat::Rgba8 {
unimplemented!("Unsupported image format: {:?}", image.0.format);
}
if image.0.alpha_type != peniko::ImageAlphaType::Alpha {
unimplemented!("Unsupported image alpha type: {:?}", image.0.alpha_type);
}
Expand Down
8 changes: 3 additions & 5 deletions vello_encoding/src/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,9 +432,6 @@ impl Encoding {
/// Encodes an image brush.
pub fn encode_image<'b>(&mut self, brush: impl Into<ImageBrushRef<'b>>, alpha: f32) {
let brush = brush.into();
if brush.image.format != peniko::ImageFormat::Rgba8 {
unimplemented!("Unsupported image format: {:?}", brush.image.format);
}
if brush.image.alpha_type != peniko::ImageAlphaType::Alpha {
unimplemented!("Unsupported image alpha type: {:?}", brush.image.alpha_type);
}
Expand All @@ -457,10 +454,11 @@ impl Encoding {
.extend_from_slice(bytemuck::cast_slice(bytemuck::bytes_of(&DrawImage {
xy: 0,
width_height: (brush.image.width << 16) | (brush.image.height & 0xFFFF),
sample_alpha: ((quality as u32) << 12)
sample_alpha: ((brush.image.format as u32) << 14
| (quality as u32) << 12
| ((x_extend as u32) << 10)
| ((y_extend as u32) << 8)
| alpha as u32,
| alpha as u32),
})));
}

Expand Down
26 changes: 21 additions & 5 deletions vello_shaders/shader/fine.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -813,15 +813,16 @@ fn read_image(cmd_ix: u32) -> CmdImage {
let width_height = info[info_offset + 7u];
let sample_alpha = info[info_offset + 8u];
let alpha = f32(sample_alpha & 0xFFu) / 255.0;
let quality = sample_alpha >> 12u;
let format = sample_alpha >> 14u;
let quality = (sample_alpha >> 12u) & 0x3u;
let x_extend = (sample_alpha >> 10u) & 0x3u;
let y_extend = (sample_alpha >> 8u) & 0x3u;
// The following are not intended to be bitcasts
let x = f32(xy >> 16u);
let y = f32(xy & 0xffffu);
let width = f32(width_height >> 16u);
let height = f32(width_height & 0xffffu);
return CmdImage(matrx, xlat, vec2(x, y), vec2(width, height), x_extend, y_extend, quality, alpha);
return CmdImage(matrx, xlat, vec2(x, y), vec2(width, height), format, x_extend, y_extend, quality, alpha);
}

fn read_end_clip(cmd_ix: u32) -> CmdEndClip {
Expand All @@ -830,6 +831,21 @@ fn read_end_clip(cmd_ix: u32) -> CmdEndClip {
return CmdEndClip(blend, alpha);
}

const PIXEL_FORMAT_RGBA: u32 = 0u;
const PIXEL_FORMAT_BGRA: u32 = 1u;
// Normalises subpixel order loaded from an image, based on the image's format.
fn pixel_format(pixel: vec4f, format: u32) -> vec4f {
Comment thread
sagudev marked this conversation as resolved.
switch format {
case PIXEL_FORMAT_BGRA: {
// The conversion from RGBA to BGRA is its own inverse.
return pixel.bgra;
Comment thread
sagudev marked this conversation as resolved.
}
case PIXEL_FORMAT_RGBA, default: {
return pixel;
}
}
}

const EXTEND_PAD: u32 = 0u;
const EXTEND_REPEAT: u32 = 1u;
const EXTEND_REFLECT: u32 = 2u;
Expand Down Expand Up @@ -1198,13 +1214,13 @@ fn main(
let atlas_uv_clamped = clamp(atlas_uv, image.atlas_offset, atlas_max);
// Nearest neighbor sampling
let fg_rgba = premul_alpha(textureLoad(image_atlas, vec2<i32>(atlas_uv_clamped), 0));
let fg_i = fg_rgba * area[i] * image.alpha;
let fg_i = pixel_format(fg_rgba * area[i] * image.alpha, image.format);
rgba[i] = rgba[i] * (1.0 - fg_i.a) + fg_i;
}
}
}
case IMAGE_QUALITY_MEDIUM, default: {
// We don't have an implementation for `IMAGE_QUALITY_HIGH` yet, just use the same as medium
// We don't have an implementation for `IMAGE_QUALITY_HIGH` yet, just use the same as medium
for (var i = 0u; i < PIXELS_PER_THREAD; i += 1u) {
// We only need to load from the textures if the value will be used.
if area[i] != 0.0 {
Expand All @@ -1225,7 +1241,7 @@ fn main(
let d = premul_alpha(textureLoad(image_atlas, vec2<i32>(uv_quad.zw), 0));
// Bilinear sampling
let fg_rgba = mix(mix(a, b, uv_frac.y), mix(c, d, uv_frac.y), uv_frac.x);
let fg_i = fg_rgba * area[i] * image.alpha;
let fg_i = pixel_format(fg_rgba * area[i] * image.alpha, image.format);
rgba[i] = rgba[i] * (1.0 - fg_i.a) + fg_i;
}
}
Expand Down
3 changes: 2 additions & 1 deletion vello_shaders/shader/shared/ptcl.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ struct CmdColor {
struct CmdBlurRect {
// Solid fill color.
rgba_color: u32,

// 2x2 transformation matrix (inverse).
matrx: vec4<f32>,
// 2D translation (inverse)
Expand Down Expand Up @@ -97,6 +97,7 @@ struct CmdImage {
xlat: vec2<f32>,
atlas_offset: vec2<f32>,
extents: vec2<f32>,
format: u32,
x_extend_mode: u32,
y_extend_mode: u32,
quality: u32,
Expand Down
45 changes: 45 additions & 0 deletions vello_tests/tests/property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use vello::Scene;
use vello::kurbo::{Affine, Rect};
use vello::peniko::{Brush, Color, ImageFormat, color::palette};
use vello::peniko::{ImageAlphaType, ImageData, ImageSampler};
use vello_tests::TestParams;

fn simple_square(use_cpu: bool) {
Expand Down Expand Up @@ -101,3 +102,47 @@ fn empty_scene_gpu() {
fn empty_scene_cpu() {
empty_scene(true);
}

#[test]
#[cfg_attr(skip_gpu_tests, ignore)]
fn bgra_image() {
let mut scene = Scene::new();
let colors = [
palette::css::RED,
palette::css::BLUE,
palette::css::LIME,
palette::css::WHITE,
];
let blob: Vec<u8> = colors
.iter()
.flat_map(|c| {
let [r, g, b, a] = c.to_rgba8().to_u8_array();
[b, g, r, a]
})
.collect();
let image = vello::peniko::ImageBrush {
image: ImageData {
data: blob.into(),
format: ImageFormat::Bgra8,
width: 2,
height: 2,
alpha_type: ImageAlphaType::Alpha,
},
sampler: ImageSampler {
quality: vello::peniko::ImageQuality::Low,
..Default::default()
},
};
scene.draw_image(&image, Affine::IDENTITY);
let scene_image =
vello_tests::render_then_debug_sync(&scene, &TestParams::new("bgra", 2, 2)).unwrap();
assert_eq!(scene_image.format, ImageFormat::Rgba8);
for (i, pixel) in scene_image.data.data().chunks_exact(4).enumerate() {
let &[r, g, b, a] = pixel else { unreachable!() };
let image_color = Color::from_rgba8(r, g, b, a);
let color = colors[i];
if image_color.premultiply().difference(color.premultiply()) > 1e-4 {
panic!("Got {image_color:?}, expected color {color:?}");
}
}
}