use crate::copy::GpuCopyInstance;
use crate::schedule::round::BlendOp;
use crate::target::TextureParity;
use crate::util::{pack_opacity, pack_u16_pair};
use bytemuck::{Pod, Zeroable};
use vello_common::geometry::{RectU16, SizeU16};
use vello_common::peniko::{Compose, Mix};
#[repr(C)]
#[derive(Debug, Copy, Clone, Pod, Zeroable)]
pub(crate) struct GpuBlendInstance {
pub(crate) geometry_origin: u32,
pub(crate) geometry_size: u32,
pub(crate) geometry_alpha_col_idx: u32,
pub(crate) parent_texture_size: u32,
pub(crate) child_texture_origin: u32,
pub(crate) child_parent_origin: u32,
pub(crate) child_rect_size: u32,
pub(crate) blend_config: u32,
}
impl GpuBlendInstance {
pub(crate) fn new(
blend: &BlendOp,
clip_strip: Option<BlendStrip>,
parent_texture_size: SizeU16,
) -> Self {
let parent_rect = blend.parent_region.texture_rect(blend.blend_bbox);
let child_parent_rect = blend
.parent_region
.texture_rect(blend.child_region.layer_bbox);
let geometry = clip_strip.map_or_else(
|| BlendGeometry {
rect: parent_rect,
alpha_col_idx: None,
},
|strip| BlendGeometry {
rect: strip.rect,
alpha_col_idx: strip.alpha_col_idx,
},
);
Self {
geometry_origin: pack_u16_pair(geometry.rect.x0, geometry.rect.y0),
geometry_size: pack_u16_pair(geometry.rect.width(), geometry.rect.height()),
geometry_alpha_col_idx: geometry.alpha_col_idx.unwrap_or(0),
parent_texture_size: pack_u16_pair(
parent_texture_size.width(),
parent_texture_size.height(),
),
child_texture_origin: pack_u16_pair(
blend.child_region.texture.rect.x0,
blend.child_region.texture.rect.y0,
),
child_parent_origin: pack_u16_pair(child_parent_rect.x0, child_parent_rect.y0),
child_rect_size: pack_u16_pair(
blend.child_region.layer_bbox.width(),
blend.child_region.layer_bbox.height(),
),
blend_config: pack_blend_config(
blend.blend_mode.mix,
blend.blend_mode.compose,
blend.opacity,
blend.parent_region.texture.target.texture_parity,
blend.child_region.texture.target.texture_parity,
geometry.alpha_col_idx.is_some(),
),
}
}
pub(crate) fn copy_from_scratch(self) -> GpuCopyInstance {
GpuCopyInstance {
dest_texture_origin: self.geometry_origin,
source_texture_origin: self.geometry_origin,
copy_rect_size: self.geometry_size,
dest_texture_size: self.parent_texture_size,
}
}
}
#[derive(Debug, Copy, Clone)]
pub(crate) struct BlendStrip {
rect: RectU16,
alpha_col_idx: Option<u32>,
}
impl BlendStrip {
pub(crate) fn from_fill_segment(rect: RectU16, alpha_col_idx: Option<u32>) -> Self {
Self {
rect,
alpha_col_idx,
}
}
}
#[derive(Debug, Copy, Clone)]
struct BlendGeometry {
rect: RectU16,
alpha_col_idx: Option<u32>,
}
fn pack_blend_config(
mix: Mix,
compose: Compose,
opacity: f32,
parent_texture_parity: TextureParity,
child_texture_parity: TextureParity,
has_alpha: bool,
) -> u32 {
pack_compose(compose)
| (pack_mix(mix) << 8)
| (u32::from(pack_opacity(opacity)) << 16)
| (u32::from(parent_texture_parity) << 24)
| (u32::from(child_texture_parity) << 25)
| u32::from(has_alpha) << 26
}
fn pack_mix(mix: Mix) -> u32 {
match mix {
Mix::Normal => 0,
Mix::Multiply => 1,
Mix::Screen => 2,
Mix::Overlay => 3,
Mix::Darken => 4,
Mix::Lighten => 5,
Mix::ColorDodge => 6,
Mix::ColorBurn => 7,
Mix::HardLight => 8,
Mix::SoftLight => 9,
Mix::Difference => 10,
Mix::Exclusion => 11,
Mix::Hue => 12,
Mix::Saturation => 13,
Mix::Color => 14,
Mix::Luminosity => 15,
}
}
fn pack_compose(compose: Compose) -> u32 {
match compose {
Compose::Clear => 0,
Compose::Copy => 1,
Compose::Dest => 2,
Compose::SrcOver => 3,
Compose::DestOver => 4,
Compose::SrcIn => 5,
Compose::DestIn => 6,
Compose::SrcOut => 7,
Compose::DestOut => 8,
Compose::SrcAtop => 9,
Compose::DestAtop => 10,
Compose::Xor => 11,
Compose::Plus => 12,
Compose::PlusLighter => 13,
}
}