Separate opacity out from paint.

This allows `globalAlpha` to work on render targets.
This commit is contained in:
Patrick Walton 2020-02-26 12:43:07 -08:00
parent 1deb53fa9c
commit 77b3555828
31 changed files with 230 additions and 206 deletions

View File

@ -103,12 +103,9 @@ impl CanvasRenderingContext2D {
let paint = self.current_state.resolve_paint(&paint);
let paint_id = self.scene.push_paint(&paint);
self.scene.push_path(DrawPath::new(outline,
paint_id,
None,
FillRule::Winding,
BlendMode::Clear,
String::new()))
let mut path = DrawPath::new(outline, paint_id);
path.set_blend_mode(BlendMode::Clear);
self.scene.push_path(path);
}
// Line styles
@ -224,8 +221,9 @@ impl CanvasRenderingContext2D {
let mut outline = path.into_outline();
outline.transform(&self.current_state.transform);
let clip_path_id = self.scene
.push_clip_path(ClipPath::new(outline, fill_rule, String::new()));
let mut clip_path = ClipPath::new(outline);
clip_path.set_fill_rule(fill_rule);
let clip_path_id = self.scene.push_clip_path(clip_path);
self.current_state.clip_path = Some(clip_path_id);
}
@ -234,6 +232,7 @@ impl CanvasRenderingContext2D {
let clip_path = self.current_state.clip_path;
let blend_mode = self.current_state.global_composite_operation.to_blend_mode();
let composite_op = self.current_state.global_composite_operation.to_composite_op();
let opacity = (self.current_state.global_alpha * 255.0) as u8;
if !self.current_state.shadow_paint.is_fully_transparent() {
let render_target_id = self.push_render_target_if_needed(composite_op);
@ -243,24 +242,24 @@ impl CanvasRenderingContext2D {
let mut outline = outline.clone();
outline.transform(&Transform2F::from_translation(self.current_state.shadow_offset));
self.scene.push_path(DrawPath::new(outline,
paint_id,
clip_path,
fill_rule,
blend_mode,
String::new()));
let mut path = DrawPath::new(outline, paint_id);
path.set_clip_path(clip_path);
path.set_fill_rule(fill_rule);
path.set_blend_mode(blend_mode);
path.set_opacity(opacity);
self.scene.push_path(path);
self.composite_render_target_if_needed(composite_op, render_target_id);
}
let render_target_id = self.push_render_target_if_needed(composite_op);
self.scene.push_path(DrawPath::new(outline,
paint_id,
clip_path,
fill_rule,
blend_mode,
String::new()));
let mut path = DrawPath::new(outline, paint_id);
path.set_clip_path(clip_path);
path.set_fill_rule(fill_rule);
path.set_blend_mode(blend_mode);
path.set_opacity(opacity);
self.scene.push_path(path);
self.composite_render_target_if_needed(composite_op, render_target_id);
}
@ -387,12 +386,11 @@ impl State {
}
fn resolve_paint<'a>(&self, paint: &'a Paint) -> Cow<'a, Paint> {
if self.global_alpha == 1.0 && (paint.is_color() || self.transform.is_identity()) {
if self.transform.is_identity() {
return Cow::Borrowed(paint);
}
let mut paint = (*paint).clone();
paint.set_opacity(self.global_alpha);
paint.apply_transform(&self.transform);
Cow::Owned(paint)
}

View File

@ -148,12 +148,6 @@ impl Gradient {
.lerp(upper_stop.color.to_f32(), (t - lower_stop.offset) / denom)
.to_u8()
}
pub fn set_opacity(&mut self, alpha: f32) {
for stop in &mut self.stops.array {
stop.color.a = (stop.color.a as f32 * alpha).round() as u8;
}
}
}
impl ColorStop {

View File

@ -86,17 +86,6 @@ impl Image {
pub fn is_opaque(&self) -> bool {
self.is_opaque
}
pub fn set_opacity(&mut self, alpha: f32) {
debug_assert!(alpha >= 0.0 && alpha <= 1.0);
if alpha == 1.0 {
return;
}
// TODO(pcwalton): Go four pixels at a time with SIMD.
self.pixels.iter_mut().for_each(|pixel| pixel.a = (pixel.a as f32 * alpha).round() as u8);
self.is_opaque = false;
}
}
impl PatternSource {
@ -110,18 +99,6 @@ impl PatternSource {
}
}
}
#[inline]
pub fn set_opacity(&mut self, alpha: f32) {
match *self {
PatternSource::Image(ref mut image) => image.set_opacity(alpha),
PatternSource::RenderTarget(_) => {
// TODO(pcwalton): We'll probably have to introduce and use an Opacity filter for
// this.
unimplemented!()
}
}
}
}
impl Debug for Image {

View File

@ -365,6 +365,9 @@ impl Device for MetalDevice {
(VertexAttrClass::Int, VertexAttrType::I8, 1) => MTLVertexFormat::Char,
(VertexAttrClass::Int, VertexAttrType::U8, 1) => MTLVertexFormat::UChar,
(VertexAttrClass::FloatNorm, VertexAttrType::I8, 1) => MTLVertexFormat::CharNormalized,
(VertexAttrClass::FloatNorm, VertexAttrType::U8, 1) => {
MTLVertexFormat::UCharNormalized
}
(VertexAttrClass::Int, VertexAttrType::I16, 1) => MTLVertexFormat::Short,
(VertexAttrClass::Int, VertexAttrType::U16, 1) => MTLVertexFormat::UShort,
(VertexAttrClass::FloatNorm, VertexAttrType::U16, 1) => {

View File

@ -180,6 +180,7 @@ impl<'a> SceneBuilder<'a> {
TilingPathInfo::Draw {
paint_metadata,
blend_mode: path_object.blend_mode(),
opacity: path_object.opacity(),
built_clip_path,
});
@ -670,27 +671,32 @@ impl ObjectBuilder {
mask_tile_index: u16,
tile_coords: Vector2I,
object_index: u16,
opacity: u8,
paint_metadata: &PaintMetadata) {
alpha_tiles.push(AlphaTile {
upper_left: AlphaTileVertex::new(tile_coords,
mask_tile_index,
Vector2I::default(),
object_index,
opacity,
paint_metadata),
upper_right: AlphaTileVertex::new(tile_coords,
mask_tile_index,
Vector2I::new(1, 0),
object_index,
opacity,
paint_metadata),
lower_left: AlphaTileVertex::new(tile_coords,
mask_tile_index,
Vector2I::new(0, 1),
object_index,
opacity,
paint_metadata),
lower_right: AlphaTileVertex::new(tile_coords,
mask_tile_index,
Vector2I::splat(1),
object_index,
opacity,
paint_metadata),
});
}
@ -723,6 +729,7 @@ impl AlphaTileVertex {
tile_index: u16,
tile_offset: Vector2I,
object_index: u16,
opacity: u8,
paint_metadata: &PaintMetadata)
-> AlphaTileVertex {
let tile_position = tile_origin + tile_offset;
@ -737,6 +744,7 @@ impl AlphaTileVertex {
mask_u: mask_uv.x() as u16,
mask_v: mask_uv.y() as u16,
object_index,
opacity,
pad: 0,
}
}

View File

@ -193,6 +193,7 @@ impl<D> AlphaTileVertexArray<D> where D: Device {
"ColorTexCoord").unwrap();
let mask_tex_coord_attr = device.get_vertex_attr(&alpha_tile_program.program,
"MaskTexCoord").unwrap();
let opacity_attr = device.get_vertex_attr(&alpha_tile_program.program, "Opacity").unwrap();
device.bind_buffer(&vertex_array, alpha_tile_vertex_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor {
@ -222,6 +223,15 @@ impl<D> AlphaTileVertexArray<D> where D: Device {
divisor: 0,
buffer_index: 0,
});
device.configure_vertex_attr(&vertex_array, &opacity_attr, &VertexAttrDescriptor {
size: 1,
class: VertexAttrClass::FloatNorm,
attr_type: VertexAttrType::U8,
stride: ALPHA_TILE_VERTEX_SIZE,
offset: 14,
divisor: 0,
buffer_index: 0,
});
device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index);
AlphaTileVertexArray { vertex_array }

View File

@ -173,7 +173,8 @@ pub struct AlphaTileVertex {
pub color_u: u16,
pub color_v: u16,
pub object_index: u16,
pub pad: u16,
pub opacity: u8,
pub pad: u8,
}
impl Debug for RenderCommand {

View File

@ -113,18 +113,6 @@ impl Paint {
}
}
pub fn set_opacity(&mut self, alpha: f32) {
if alpha == 1.0 {
return;
}
match *self {
Paint::Color(ref mut color) => color.a = (color.a as f32 * alpha).round() as u8,
Paint::Gradient(ref mut gradient) => gradient.set_opacity(alpha),
Paint::Pattern(ref mut pattern) => pattern.source.set_opacity(alpha),
}
}
pub fn apply_transform(&mut self, transform: &Transform2F) {
if transform.is_identity() {
return;

View File

@ -226,6 +226,7 @@ pub struct DrawPath {
clip_path: Option<ClipPathId>,
fill_rule: FillRule,
blend_mode: BlendMode,
opacity: u8,
name: String,
}
@ -267,14 +268,16 @@ pub enum DisplayItem {
impl DrawPath {
#[inline]
pub fn new(outline: Outline,
paint: PaintId,
clip_path: Option<ClipPathId>,
fill_rule: FillRule,
blend_mode: BlendMode,
name: String)
-> DrawPath {
DrawPath { outline, paint, clip_path, fill_rule, blend_mode, name }
pub fn new(outline: Outline, paint: PaintId) -> DrawPath {
DrawPath {
outline,
paint,
clip_path: None,
fill_rule: FillRule::Winding,
blend_mode: BlendMode::SrcOver,
opacity: !0,
name: String::new(),
}
}
#[inline]
@ -287,6 +290,11 @@ impl DrawPath {
self.clip_path
}
#[inline]
pub fn set_clip_path(&mut self, new_clip_path: Option<ClipPathId>) {
self.clip_path = new_clip_path
}
#[inline]
pub(crate) fn paint(&self) -> PaintId {
self.paint
@ -297,16 +305,41 @@ impl DrawPath {
self.fill_rule
}
#[inline]
pub fn set_fill_rule(&mut self, new_fill_rule: FillRule) {
self.fill_rule = new_fill_rule
}
#[inline]
pub(crate) fn blend_mode(&self) -> BlendMode {
self.blend_mode
}
#[inline]
pub fn set_blend_mode(&mut self, new_blend_mode: BlendMode) {
self.blend_mode = new_blend_mode
}
#[inline]
pub(crate) fn opacity(&self) -> u8 {
self.opacity
}
#[inline]
pub fn set_opacity(&mut self, new_opacity: u8) {
self.opacity = new_opacity
}
#[inline]
pub fn set_name(&mut self, new_name: String) {
self.name = new_name
}
}
impl ClipPath {
#[inline]
pub fn new(outline: Outline, fill_rule: FillRule, name: String) -> ClipPath {
ClipPath { outline, fill_rule, name }
pub fn new(outline: Outline) -> ClipPath {
ClipPath { outline, fill_rule: FillRule::Winding, name: String::new() }
}
#[inline]
@ -318,6 +351,16 @@ impl ClipPath {
pub(crate) fn fill_rule(&self) -> FillRule {
self.fill_rule
}
#[inline]
pub fn set_fill_rule(&mut self, new_fill_rule: FillRule) {
self.fill_rule = new_fill_rule
}
#[inline]
pub fn set_name(&mut self, new_name: String) {
self.name = new_name
}
}
impl RenderTarget {

View File

@ -46,6 +46,7 @@ pub(crate) enum TilingPathInfo<'a> {
Draw {
paint_metadata: &'a PaintMetadata,
blend_mode: BlendMode,
opacity: u8,
built_clip_path: Option<&'a BuiltPath>,
},
}
@ -127,10 +128,10 @@ impl<'a> Tiler<'a> {
}
fn pack_and_cull_draw_path(&mut self) {
let (paint_metadata, blend_mode, built_clip_path) = match self.path_info {
let (paint_metadata, blend_mode, opacity, built_clip_path) = match self.path_info {
TilingPathInfo::Clip => unreachable!(),
TilingPathInfo::Draw { paint_metadata, blend_mode, built_clip_path } => {
(paint_metadata, blend_mode, built_clip_path)
TilingPathInfo::Draw { paint_metadata, blend_mode, opacity, built_clip_path } => {
(paint_metadata, blend_mode, opacity, built_clip_path)
}
};
@ -181,7 +182,7 @@ impl<'a> Tiler<'a> {
// Next, if this is a solid tile that completely occludes the background, record
// that fact and stop here.
if paint_metadata.is_opaque && blend_mode.occludes_backdrop() {
if paint_metadata.is_opaque && blend_mode.occludes_backdrop() && opacity == !0 {
self.object_builder.built_path.solid_tiles.push(SolidTile::new(tile_coords));
continue;
}
@ -209,6 +210,7 @@ impl<'a> Tiler<'a> {
mask_tile_index,
tile_coords,
self.object_index,
opacity,
paint_metadata);
}

View File

@ -36,12 +36,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord;
in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
}
vec4 sampleDestColor(){

View File

@ -20,15 +20,18 @@ uniform vec2 uTileSize;
in ivec2 aTilePosition;
in vec2 aColorTexCoord;
in vec2 aMaskTexCoord;
in float aOpacity;
out vec2 vColorTexCoord;
out vec2 vMaskTexCoord;
out float vOpacity;
void main(){
vec2 position = aTilePosition * uTileSize;
vMaskTexCoord = aMaskTexCoord;
vColorTexCoord = aColorTexCoord;
vOpacity = aOpacity;
gl_Position = uTransform * vec4(position, 0.0, 1.0);
}

View File

@ -38,12 +38,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord;
in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
}
vec4 sampleDestColor(){

View File

@ -40,12 +40,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord;
in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
}
vec4 sampleDestColor(){

View File

@ -38,12 +38,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord;
in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
}
vec4 sampleDestColor(){

View File

@ -38,12 +38,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord;
in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
}
vec4 sampleDestColor(){

View File

@ -45,12 +45,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord;
in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
}
vec4 sampleDestColor(){

View File

@ -38,12 +38,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord;
in vec2 vMaskTexCoord;
in float vOpacity;
vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage * vOpacity);
}
vec4 sampleDestColor(){

View File

@ -23,19 +23,20 @@ struct main0_in
{
float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
};
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord)
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage);
return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
}
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord);
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
out.oFragColor = float4(srcRGBA.xyz * srcRGBA.w, srcRGBA.w);
return out;
}

View File

@ -14,6 +14,7 @@ struct main0_out
{
float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
float4 gl_Position [[position]];
};
@ -22,6 +23,7 @@ struct main0_in
int2 aTilePosition [[attribute(0)]];
float2 aColorTexCoord [[attribute(1)]];
float2 aMaskTexCoord [[attribute(2)]];
float aOpacity [[attribute(3)]];
};
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
@ -30,6 +32,7 @@ vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer
float2 position = float2(in.aTilePosition) * (*spvDescriptorSet0.uTileSize);
out.vMaskTexCoord = in.aMaskTexCoord;
out.vColorTexCoord = in.aColorTexCoord;
out.vOpacity = in.aOpacity;
out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0);
return out;
}

View File

@ -26,13 +26,14 @@ struct main0_in
{
float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
};
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord)
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage);
return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
}
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -49,7 +50,7 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{
main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord);
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
float3 blended = abs(destRGBA.xyz - srcRGBA.xyz);
float4 param = destRGBA;

View File

@ -27,13 +27,14 @@ struct main0_in
{
float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
};
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord)
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage);
return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
}
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -50,57 +51,57 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{
main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord);
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
float3 _118;
float3 _122;
if ((*spvDescriptorSet0.uBurn) == 0)
{
_118 = destRGBA.xyz;
_122 = destRGBA.xyz;
}
else
{
_118 = float3(1.0) - destRGBA.xyz;
_122 = float3(1.0) - destRGBA.xyz;
}
float3 dest = _118;
float3 _132;
float3 dest = _122;
float3 _136;
if ((*spvDescriptorSet0.uBurn) == 0)
{
_132 = float3(1.0) - srcRGBA.xyz;
_136 = float3(1.0) - srcRGBA.xyz;
}
else
{
_132 = srcRGBA.xyz;
_136 = srcRGBA.xyz;
}
float3 src = _132;
float3 src = _136;
bool3 srcNonzero = src != float3(0.0);
float _153;
float _157;
if (srcNonzero.x)
{
_153 = dest.x / src.x;
_157 = dest.x / src.x;
}
else
{
_153 = 1.0;
_157 = 1.0;
}
float _166;
float _170;
if (srcNonzero.y)
{
_166 = dest.y / src.y;
_170 = dest.y / src.y;
}
else
{
_166 = 1.0;
_170 = 1.0;
}
float _179;
float _183;
if (srcNonzero.z)
{
_179 = dest.z / src.z;
_183 = dest.z / src.z;
}
else
{
_179 = 1.0;
_183 = 1.0;
}
float3 blended = fast::min(float3(_153, _166, _179), float3(1.0));
float3 blended = fast::min(float3(_157, _170, _183), float3(1.0));
if ((*spvDescriptorSet0.uBurn) != 0)
{
blended = float3(1.0) - blended;

View File

@ -26,13 +26,14 @@ struct main0_in
{
float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
};
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord)
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage);
return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
}
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -49,7 +50,7 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{
main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord);
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
float3 dest = destRGBA.xyz;
float3 src = srcRGBA.xyz;

View File

@ -27,6 +27,7 @@ struct main0_in
{
float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
};
// Implementation of the GLSL mod() function, which is slightly different than Metal fmod()
@ -36,11 +37,11 @@ Tx mod(Tx x, Ty y)
return x - y * floor(x / y);
}
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord)
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage);
return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
}
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -85,34 +86,34 @@ float3 convertRGBToHSL(thread const float3& rgb)
float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b)
{
float _125;
float _129;
if (cond.x)
{
_125 = a.x;
_129 = a.x;
}
else
{
_125 = b.x;
_129 = b.x;
}
float _137;
float _141;
if (cond.y)
{
_137 = a.y;
_141 = a.y;
}
else
{
_137 = b.y;
_141 = b.y;
}
float _149;
float _153;
if (cond.z)
{
_149 = a.z;
_153 = a.z;
}
else
{
_149 = b.z;
_153 = b.z;
}
return float3(_125, _137, _149);
return float3(_129, _141, _153);
}
float3 convertHSLToRGB(thread const float3& hsl)
@ -130,7 +131,7 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{
main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord);
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
float3 param = destRGBA.xyz;
float3 destHSL = convertRGBToHSL(param);

View File

@ -27,13 +27,14 @@ struct main0_in
{
float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
};
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord)
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage);
return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
}
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -44,34 +45,34 @@ float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSi
float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b)
{
float _118;
float _122;
if (cond.x)
{
_118 = a.x;
_122 = a.x;
}
else
{
_118 = b.x;
_122 = b.x;
}
float _130;
float _134;
if (cond.y)
{
_130 = a.y;
_134 = a.y;
}
else
{
_130 = b.y;
_134 = b.y;
}
float _142;
float _146;
if (cond.z)
{
_142 = a.z;
_146 = a.z;
}
else
{
_142 = b.z;
_146 = b.z;
}
return float3(_118, _130, _142);
return float3(_122, _134, _146);
}
float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB)
@ -82,29 +83,29 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{
main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord);
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
bool reversed = (*spvDescriptorSet0.uBlendMode) == 3;
float3 _167;
float3 _171;
if (reversed)
{
_167 = srcRGBA.xyz;
_171 = srcRGBA.xyz;
}
else
{
_167 = destRGBA.xyz;
_171 = destRGBA.xyz;
}
float3 src = _167;
float3 _178;
float3 src = _171;
float3 _182;
if (reversed)
{
_178 = destRGBA.xyz;
_182 = destRGBA.xyz;
}
else
{
_178 = srcRGBA.xyz;
_182 = srcRGBA.xyz;
}
float3 dest = _178;
float3 dest = _182;
float3 multiply = src * dest;
float3 blended;
if ((*spvDescriptorSet0.uBlendMode) == 0)

View File

@ -26,13 +26,14 @@ struct main0_in
{
float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]];
float vOpacity [[user(locn2)]];
};
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord)
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord, thread float& vOpacity)
{
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage);
return float4(srcRGBA.xyz, (srcRGBA.w * coverage) * vOpacity);
}
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
@ -43,34 +44,34 @@ float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSi
float3 select3(thread const bool3& cond, thread const float3& a, thread const float3& b)
{
float _118;
float _122;
if (cond.x)
{
_118 = a.x;
_122 = a.x;
}
else
{
_118 = b.x;
_122 = b.x;
}
float _130;
float _134;
if (cond.y)
{
_130 = a.y;
_134 = a.y;
}
else
{
_130 = b.y;
_134 = b.y;
}
float _142;
float _146;
if (cond.z)
{
_142 = a.z;
_146 = a.z;
}
else
{
_142 = b.z;
_146 = b.z;
}
return float3(_118, _130, _142);
return float3(_122, _134, _146);
}
float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA, thread const float3& blendedRGB)
@ -81,7 +82,7 @@ float4 blendColors(thread const float4& destRGBA, thread const float4& srcRGBA,
fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]], float4 gl_FragCoord [[position]])
{
main0_out out = {};
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord);
float4 srcRGBA = sampleSrcColor(spvDescriptorSet0.uStencilTexture, spvDescriptorSet0.uStencilTextureSmplr, in.vMaskTexCoord, spvDescriptorSet0.uPaintTexture, spvDescriptorSet0.uPaintTextureSmplr, in.vColorTexCoord, in.vOpacity);
float4 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
float3 dest = destRGBA.xyz;
float3 src = srcRGBA.xyz;

View File

@ -18,14 +18,17 @@ uniform vec2 uTileSize;
in ivec2 aTilePosition;
in vec2 aColorTexCoord;
in vec2 aMaskTexCoord;
in float aOpacity;
out vec2 vColorTexCoord;
out vec2 vMaskTexCoord;
out float vOpacity;
void main() {
vec2 position = aTilePosition * uTileSize;
vMaskTexCoord = aMaskTexCoord;
vColorTexCoord = aColorTexCoord;
vOpacity = aOpacity;
gl_Position = uTransform * vec4(position, 0.0, 1.0);
}

View File

@ -15,12 +15,13 @@ uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord;
in vec2 vMaskTexCoord;
in float vOpacity;
// NB: This does not premultiply.
vec4 sampleSrcColor() {
float coverage = texture(uStencilTexture, vMaskTexCoord).r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA.rgb, srcRGBA.a * coverage);
return vec4(srcRGBA.rgb, srcRGBA.a * coverage * vOpacity);
}
vec4 sampleDestColor() {

View File

@ -15,7 +15,6 @@ extern crate bitflags;
use hashbrown::HashMap;
use pathfinder_color::ColorU;
use pathfinder_content::effects::BlendMode;
use pathfinder_content::fill::FillRule;
use pathfinder_content::outline::Outline;
use pathfinder_content::segment::{Segment, SegmentFlags};
@ -180,9 +179,9 @@ impl BuiltSVG {
}
if let Some(clip_outline) = clip_outline {
let name = format!("ClipPath({})", node.id());
// FIXME(pcwalton): Is the winding fill rule correct to use?
let clip_path = ClipPath::new(clip_outline, FillRule::Winding, name);
let mut clip_path = ClipPath::new(clip_outline);
clip_path.set_name(format!("ClipPath({})", node.id()));
let clip_path_id = self.scene.push_clip_path(clip_path);
self.clip_paths.insert(node.id().to_owned(), clip_path_id);
}
@ -232,16 +231,14 @@ impl BuiltSVG {
paint: &UsvgPaint,
opacity: Opacity,
fill_rule: UsvgFillRule) {
let style = self.scene.push_paint(&Paint::from_svg_paint(paint,
opacity,
&mut self.result_flags));
let style = self.scene.push_paint(&Paint::from_svg_paint(paint, &mut self.result_flags));
let fill_rule = FillRule::from_usvg_fill_rule(fill_rule);
self.scene.push_path(DrawPath::new(outline,
style,
state.clip_path,
fill_rule,
BlendMode::SrcOver,
name));
let mut path = DrawPath::new(outline, style);
path.set_clip_path(state.clip_path);
path.set_fill_rule(fill_rule);
path.set_name(name);
path.set_opacity((opacity.value() * 255.0) as u8);
self.scene.push_path(path);
}
}
@ -288,17 +285,15 @@ impl Display for BuildResultFlags {
}
trait PaintExt {
fn from_svg_paint(svg_paint: &UsvgPaint, opacity: Opacity, result_flags: &mut BuildResultFlags)
-> Self;
fn from_svg_paint(svg_paint: &UsvgPaint, result_flags: &mut BuildResultFlags) -> Self;
}
impl PaintExt for Paint {
#[inline]
fn from_svg_paint(svg_paint: &UsvgPaint, opacity: Opacity, result_flags: &mut BuildResultFlags)
-> Paint {
fn from_svg_paint(svg_paint: &UsvgPaint, result_flags: &mut BuildResultFlags) -> Paint {
// TODO(pcwalton): Support gradients.
Paint::Color(match *svg_paint {
UsvgPaint::Color(color) => ColorU::from_svg_color(color, opacity),
UsvgPaint::Color(color) => ColorU::from_svg_color(color),
UsvgPaint::Link(_) => {
// TODO(pcwalton)
result_flags.insert(BuildResultFlags::UNSUPPORTED_LINK_PAINT);
@ -412,18 +407,13 @@ where
}
trait ColorUExt {
fn from_svg_color(svg_color: SvgColor, opacity: Opacity) -> Self;
fn from_svg_color(svg_color: SvgColor) -> Self;
}
impl ColorUExt for ColorU {
#[inline]
fn from_svg_color(svg_color: SvgColor, opacity: Opacity) -> ColorU {
ColorU {
r: svg_color.red,
g: svg_color.green,
b: svg_color.blue,
a: (opacity.value() * 255.0).round() as u8,
}
fn from_svg_color(svg_color: SvgColor) -> ColorU {
ColorU { r: svg_color.red, g: svg_color.green, b: svg_color.blue, a: !0 }
}
}

View File

@ -10,7 +10,6 @@
use std::ops::Add;
use pathfinder_color::{ColorF, ColorU};
use pathfinder_content::effects::BlendMode;
use pathfinder_content::fill::FillRule;
use pathfinder_content::outline::{Outline, Contour};
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
@ -196,14 +195,9 @@ pub fn draw_paths_into_scene(library: &SymbolLibrary, scene: &mut Scene) {
path = stroke_to_fill.into_outline();
}
scene.push_path(DrawPath::new(
path,
paint_id,
None,
FillRule::EvenOdd,
BlendMode::SrcOver,
String::new()
));
let mut path = DrawPath::new(path, paint_id);
path.set_fill_rule(FillRule::EvenOdd);
scene.push_path(path);
}
}
}

View File

@ -14,8 +14,6 @@ use font_kit::error::GlyphLoadingError;
use font_kit::hinting::HintingOptions;
use font_kit::loader::Loader;
use lyon_path::builder::{FlatPathBuilder, PathBuilder, Build};
use pathfinder_content::effects::BlendMode;
use pathfinder_content::fill::FillRule;
use pathfinder_content::outline::{Contour, Outline};
use pathfinder_content::stroke::{OutlineStrokeToFill, StrokeStyle};
use pathfinder_geometry::transform2d::Transform2F;
@ -78,13 +76,7 @@ impl SceneExt for Scene {
outline = stroke_to_fill.into_outline();
}
self.push_path(DrawPath::new(outline,
paint_id,
None,
FillRule::Winding,
BlendMode::SrcOver,
String::new()));
self.push_path(DrawPath::new(outline, paint_id));
Ok(())
}