Implement the source-in, destination-in, source-out, and destination-atop blend

modes to round out the assortment of Porter-Duff blend modes
This commit is contained in:
Patrick Walton 2020-02-25 12:52:11 -08:00
parent 02012431ca
commit 9b4217300f
8 changed files with 349 additions and 11 deletions

View File

@ -524,11 +524,15 @@ pub enum LineJoin {
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum CompositeOperation { pub enum CompositeOperation {
SourceOver, SourceOver,
DestinationOver, SourceIn,
DestinationOut, SourceOut,
SourceAtop, SourceAtop,
Xor, DestinationOver,
DestinationIn,
DestinationOut,
DestinationAtop,
Lighter, Lighter,
Xor,
Multiply, Multiply,
Screen, Screen,
Overlay, Overlay,
@ -547,9 +551,13 @@ impl CompositeOperation {
fn to_blend_mode(self) -> BlendMode { fn to_blend_mode(self) -> BlendMode {
match self { match self {
CompositeOperation::SourceOver => BlendMode::SrcOver, CompositeOperation::SourceOver => BlendMode::SrcOver,
CompositeOperation::DestinationOver => BlendMode::DestOver, CompositeOperation::SourceIn => BlendMode::SrcIn,
CompositeOperation::DestinationOut => BlendMode::DestOut, CompositeOperation::SourceOut => BlendMode::SrcOut,
CompositeOperation::SourceAtop => BlendMode::SrcAtop, CompositeOperation::SourceAtop => BlendMode::SrcAtop,
CompositeOperation::DestinationOver => BlendMode::DestOver,
CompositeOperation::DestinationIn => BlendMode::DestIn,
CompositeOperation::DestinationOut => BlendMode::DestOut,
CompositeOperation::DestinationAtop => BlendMode::DestAtop,
CompositeOperation::Xor => BlendMode::Xor, CompositeOperation::Xor => BlendMode::Xor,
CompositeOperation::Lighter => BlendMode::Lighter, CompositeOperation::Lighter => BlendMode::Lighter,
CompositeOperation::Multiply => BlendMode::Multiply, CompositeOperation::Multiply => BlendMode::Multiply,

View File

@ -75,6 +75,12 @@ pub enum BlendMode {
Lighten, Lighten,
Darken, Darken,
// Porter-Duff
SrcIn,
DestIn,
SrcOut,
DestAtop,
// Overlay // Overlay
Multiply, Multiply,
Screen, Screen,
@ -123,6 +129,10 @@ impl BlendMode {
BlendMode::Lighter | BlendMode::Lighter |
BlendMode::Lighten | BlendMode::Lighten |
BlendMode::Darken | BlendMode::Darken |
BlendMode::SrcIn |
BlendMode::DestIn |
BlendMode::SrcOut |
BlendMode::DestAtop |
BlendMode::Multiply | BlendMode::Multiply |
BlendMode::Screen | BlendMode::Screen |
BlendMode::HardLight | BlendMode::HardLight |

View File

@ -11,12 +11,13 @@
use crate::gpu::debug::DebugUIPresenter; use crate::gpu::debug::DebugUIPresenter;
use crate::gpu::options::{DestFramebuffer, RendererOptions}; use crate::gpu::options::{DestFramebuffer, RendererOptions};
use crate::gpu::shaders::{AlphaTileDodgeBurnProgram, AlphaTileHSLProgram, AlphaTileOverlayProgram}; use crate::gpu::shaders::{AlphaTileDodgeBurnProgram, AlphaTileHSLProgram, AlphaTileOverlayProgram};
use crate::gpu::shaders::{AlphaTileProgram, AlphaTileVertexArray, CopyTileProgram}; use crate::gpu::shaders::{AlphaTilePorterDuffProgram, AlphaTileProgram, AlphaTileVertexArray};
use crate::gpu::shaders::{CopyTileVertexArray, FillProgram, FillVertexArray, FilterBasicProgram}; use crate::gpu::shaders::{CopyTileProgram, CopyTileVertexArray, FillProgram, FillVertexArray};
use crate::gpu::shaders::{FilterBasicVertexArray, FilterTextProgram, FilterTextVertexArray}; use crate::gpu::shaders::{FilterBasicProgram, FilterBasicVertexArray, FilterTextProgram};
use crate::gpu::shaders::{MAX_FILLS_PER_BATCH, MaskTileProgram, MaskTileVertexArray}; use crate::gpu::shaders::{FilterTextVertexArray, MAX_FILLS_PER_BATCH, MaskTileProgram};
use crate::gpu::shaders::{ReprojectionProgram, ReprojectionVertexArray, SolidTileProgram}; use crate::gpu::shaders::{MaskTileVertexArray, ReprojectionProgram, ReprojectionVertexArray};
use crate::gpu::shaders::{SolidTileVertexArray, StencilProgram, StencilVertexArray}; use crate::gpu::shaders::{SolidTileProgram, SolidTileVertexArray};
use crate::gpu::shaders::{StencilProgram, StencilVertexArray};
use crate::gpu_data::{AlphaTile, FillBatchPrimitive, MaskTile, PaintData, PaintPageContents}; use crate::gpu_data::{AlphaTile, FillBatchPrimitive, MaskTile, PaintData, PaintPageContents};
use crate::gpu_data::{PaintPageId, RenderCommand, SolidTileVertex}; use crate::gpu_data::{PaintPageId, RenderCommand, SolidTileVertex};
use crate::options::BoundingQuad; use crate::options::BoundingQuad;
@ -61,6 +62,11 @@ const OVERLAY_BLEND_MODE_SCREEN: i32 = 1;
const OVERLAY_BLEND_MODE_HARD_LIGHT: i32 = 2; const OVERLAY_BLEND_MODE_HARD_LIGHT: i32 = 2;
const OVERLAY_BLEND_MODE_OVERLAY: i32 = 3; const OVERLAY_BLEND_MODE_OVERLAY: i32 = 3;
const PORTER_DUFF_FACTOR_ZERO: i32 = 0;
const PORTER_DUFF_FACTOR_DEST_ALPHA: i32 = 1;
const PORTER_DUFF_FACTOR_SRC_ALPHA: i32 = 2;
const PORTER_DUFF_FACTOR_ONE_MINUS_DEST_ALPHA: i32 = 3;
pub struct Renderer<D> pub struct Renderer<D>
where where
D: Device, D: Device,
@ -77,6 +83,7 @@ where
copy_tile_program: CopyTileProgram<D>, copy_tile_program: CopyTileProgram<D>,
solid_tile_program: SolidTileProgram<D>, solid_tile_program: SolidTileProgram<D>,
alpha_tile_program: AlphaTileProgram<D>, alpha_tile_program: AlphaTileProgram<D>,
alpha_tile_porterduff_program: AlphaTilePorterDuffProgram<D>,
alpha_tile_overlay_program: AlphaTileOverlayProgram<D>, alpha_tile_overlay_program: AlphaTileOverlayProgram<D>,
alpha_tile_dodgeburn_program: AlphaTileDodgeBurnProgram<D>, alpha_tile_dodgeburn_program: AlphaTileDodgeBurnProgram<D>,
alpha_tile_hsl_program: AlphaTileHSLProgram<D>, alpha_tile_hsl_program: AlphaTileHSLProgram<D>,
@ -85,6 +92,7 @@ where
copy_tile_vertex_array: CopyTileVertexArray<D>, copy_tile_vertex_array: CopyTileVertexArray<D>,
solid_tile_vertex_array: SolidTileVertexArray<D>, solid_tile_vertex_array: SolidTileVertexArray<D>,
alpha_tile_vertex_array: AlphaTileVertexArray<D>, alpha_tile_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_porterduff_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_overlay_vertex_array: AlphaTileVertexArray<D>, alpha_tile_overlay_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_dodgeburn_vertex_array: AlphaTileVertexArray<D>, alpha_tile_dodgeburn_vertex_array: AlphaTileVertexArray<D>,
alpha_tile_hsl_vertex_array: AlphaTileVertexArray<D>, alpha_tile_hsl_vertex_array: AlphaTileVertexArray<D>,
@ -158,6 +166,7 @@ where
let copy_tile_program = CopyTileProgram::new(&device, resources); let copy_tile_program = CopyTileProgram::new(&device, resources);
let solid_tile_program = SolidTileProgram::new(&device, resources); let solid_tile_program = SolidTileProgram::new(&device, resources);
let alpha_tile_program = AlphaTileProgram::new(&device, resources); let alpha_tile_program = AlphaTileProgram::new(&device, resources);
let alpha_tile_porterduff_program = AlphaTilePorterDuffProgram::new(&device, resources);
let alpha_tile_overlay_program = AlphaTileOverlayProgram::new(&device, resources); let alpha_tile_overlay_program = AlphaTileOverlayProgram::new(&device, resources);
let alpha_tile_dodgeburn_program = AlphaTileDodgeBurnProgram::new(&device, resources); let alpha_tile_dodgeburn_program = AlphaTileDodgeBurnProgram::new(&device, resources);
let alpha_tile_hsl_program = AlphaTileHSLProgram::new(&device, resources); let alpha_tile_hsl_program = AlphaTileHSLProgram::new(&device, resources);
@ -214,6 +223,12 @@ where
&alpha_tile_vertex_buffer, &alpha_tile_vertex_buffer,
&quads_vertex_indices_buffer, &quads_vertex_indices_buffer,
); );
let alpha_tile_porterduff_vertex_array = AlphaTileVertexArray::new(
&device,
&alpha_tile_porterduff_program.alpha_tile_program,
&alpha_tile_vertex_buffer,
&quads_vertex_indices_buffer,
);
let alpha_tile_overlay_vertex_array = AlphaTileVertexArray::new( let alpha_tile_overlay_vertex_array = AlphaTileVertexArray::new(
&device, &device,
&alpha_tile_overlay_program.alpha_tile_program, &alpha_tile_overlay_program.alpha_tile_program,
@ -293,6 +308,7 @@ where
copy_tile_program, copy_tile_program,
solid_tile_program, solid_tile_program,
alpha_tile_program, alpha_tile_program,
alpha_tile_porterduff_program,
alpha_tile_overlay_program, alpha_tile_overlay_program,
alpha_tile_dodgeburn_program, alpha_tile_dodgeburn_program,
alpha_tile_hsl_program, alpha_tile_hsl_program,
@ -301,6 +317,7 @@ where
copy_tile_vertex_array, copy_tile_vertex_array,
solid_tile_vertex_array, solid_tile_vertex_array,
alpha_tile_vertex_array, alpha_tile_vertex_array,
alpha_tile_porterduff_vertex_array,
alpha_tile_overlay_vertex_array, alpha_tile_overlay_vertex_array,
alpha_tile_dodgeburn_vertex_array, alpha_tile_dodgeburn_vertex_array,
alpha_tile_hsl_vertex_array, alpha_tile_hsl_vertex_array,
@ -735,6 +752,10 @@ where
let (alpha_tile_program, alpha_tile_vertex_array) = match blend_mode_program { let (alpha_tile_program, alpha_tile_vertex_array) = match blend_mode_program {
BlendModeProgram::Regular => (&self.alpha_tile_program, &self.alpha_tile_vertex_array), BlendModeProgram::Regular => (&self.alpha_tile_program, &self.alpha_tile_vertex_array),
BlendModeProgram::PorterDuff => {
(&self.alpha_tile_porterduff_program.alpha_tile_program,
&self.alpha_tile_porterduff_vertex_array)
}
BlendModeProgram::Overlay => { BlendModeProgram::Overlay => {
(&self.alpha_tile_overlay_program.alpha_tile_program, (&self.alpha_tile_overlay_program.alpha_tile_program,
&self.alpha_tile_overlay_vertex_array) &self.alpha_tile_overlay_vertex_array)
@ -777,6 +798,11 @@ where
match blend_mode_program { match blend_mode_program {
BlendModeProgram::Regular => {} BlendModeProgram::Regular => {}
BlendModeProgram::PorterDuff => {
self.set_uniforms_for_porter_duff_blend_mode(&mut textures,
&mut uniforms,
blend_mode);
}
BlendModeProgram::Overlay => { BlendModeProgram::Overlay => {
self.set_uniforms_for_overlay_blend_mode(&mut textures, &mut uniforms, blend_mode); self.set_uniforms_for_overlay_blend_mode(&mut textures, &mut uniforms, blend_mode);
} }
@ -809,6 +835,37 @@ where
self.preserve_draw_framebuffer(); self.preserve_draw_framebuffer();
} }
fn set_uniforms_for_porter_duff_blend_mode<'a>(
&'a self,
textures: &mut Vec<&'a D::Texture>,
uniforms: &mut Vec<(&'a D::Uniform, UniformData)>,
blend_mode: BlendMode) {
let (src_factor, dest_factor) = match blend_mode {
BlendMode::SrcIn => {
(PORTER_DUFF_FACTOR_DEST_ALPHA, PORTER_DUFF_FACTOR_ZERO)
}
BlendMode::DestIn => {
(PORTER_DUFF_FACTOR_ZERO, PORTER_DUFF_FACTOR_SRC_ALPHA)
}
BlendMode::SrcOut => {
(PORTER_DUFF_FACTOR_ONE_MINUS_DEST_ALPHA, PORTER_DUFF_FACTOR_ZERO)
}
BlendMode::DestAtop => {
(PORTER_DUFF_FACTOR_ONE_MINUS_DEST_ALPHA, PORTER_DUFF_FACTOR_SRC_ALPHA)
}
_ => unreachable!(),
};
uniforms.push((&self.alpha_tile_porterduff_program.src_factor_uniform,
UniformData::Int(src_factor)));
uniforms.push((&self.alpha_tile_porterduff_program.dest_factor_uniform,
UniformData::Int(dest_factor)));
textures.push(self.device.framebuffer_texture(&self.dest_blend_framebuffer));
uniforms.push((&self.alpha_tile_porterduff_program.dest_uniform,
UniformData::TextureUnit(textures.len() as u32 - 1)));
}
fn set_uniforms_for_overlay_blend_mode<'a>(&'a self, fn set_uniforms_for_overlay_blend_mode<'a>(&'a self,
textures: &mut Vec<&'a D::Texture>, textures: &mut Vec<&'a D::Texture>,
uniforms: &mut Vec<(&'a D::Uniform, UniformData)>, uniforms: &mut Vec<(&'a D::Uniform, UniformData)>,
@ -1477,6 +1534,10 @@ impl BlendModeExt for BlendMode {
op: BlendOp::Min, op: BlendOp::Min,
}) })
} }
BlendMode::SrcIn |
BlendMode::DestIn |
BlendMode::SrcOut |
BlendMode::DestAtop |
BlendMode::Multiply | BlendMode::Multiply |
BlendMode::Screen | BlendMode::Screen |
BlendMode::HardLight | BlendMode::HardLight |
@ -1497,6 +1558,7 @@ impl BlendModeExt for BlendMode {
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum BlendModeProgram { pub(crate) enum BlendModeProgram {
Regular, Regular,
PorterDuff,
Overlay, Overlay,
DodgeBurn, DodgeBurn,
HSL, HSL,
@ -1514,6 +1576,10 @@ impl BlendModeProgram {
BlendMode::Lighter | BlendMode::Lighter |
BlendMode::Lighten | BlendMode::Lighten |
BlendMode::Darken => BlendModeProgram::Regular, BlendMode::Darken => BlendModeProgram::Regular,
BlendMode::SrcIn |
BlendMode::DestIn |
BlendMode::SrcOut |
BlendMode::DestAtop => BlendModeProgram::PorterDuff,
BlendMode::Multiply | BlendMode::Multiply |
BlendMode::Screen | BlendMode::Screen |
BlendMode::HardLight | BlendMode::HardLight |
@ -1530,6 +1596,7 @@ impl BlendModeProgram {
pub(crate) fn needs_readable_framebuffer(self) -> bool { pub(crate) fn needs_readable_framebuffer(self) -> bool {
match self { match self {
BlendModeProgram::Regular => false, BlendModeProgram::Regular => false,
BlendModeProgram::PorterDuff |
BlendModeProgram::Overlay | BlendModeProgram::Overlay |
BlendModeProgram::DodgeBurn | BlendModeProgram::DodgeBurn |
BlendModeProgram::HSL => true, BlendModeProgram::HSL => true,

View File

@ -450,6 +450,31 @@ impl<D> CopyTileProgram<D> where D: Device {
} }
} }
pub struct AlphaTilePorterDuffProgram<D> where D: Device {
pub alpha_tile_program: AlphaTileProgram<D>,
pub dest_uniform: D::Uniform,
pub dest_factor_uniform: D::Uniform,
pub src_factor_uniform: D::Uniform,
}
impl<D> AlphaTilePorterDuffProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> AlphaTilePorterDuffProgram<D> {
let alpha_tile_program =
AlphaTileProgram::from_fragment_shader_name(device,
resources,
"tile_alpha_porterduff");
let dest_uniform = device.get_uniform(&alpha_tile_program.program, "Dest");
let dest_factor_uniform = device.get_uniform(&alpha_tile_program.program, "DestFactor");
let src_factor_uniform = device.get_uniform(&alpha_tile_program.program, "SrcFactor");
AlphaTilePorterDuffProgram {
alpha_tile_program,
dest_uniform,
dest_factor_uniform,
src_factor_uniform,
}
}
}
pub struct AlphaTileHSLProgram<D> where D: Device { pub struct AlphaTileHSLProgram<D> where D: Device {
pub alpha_tile_program: AlphaTileProgram<D>, pub alpha_tile_program: AlphaTileProgram<D>,
pub dest_uniform: D::Uniform, pub dest_uniform: D::Uniform,

View File

@ -0,0 +1,96 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#extension GL_GOOGLE_include_directive : enable
precision highp float;
uniform int uDestFactor;
uniform int uSrcFactor;
out vec4 oFragColor;
uniform sampler2D uStencilTexture;
uniform sampler2D uPaintTexture;
uniform sampler2D uDest;
uniform vec2 uFramebufferSize;
in vec2 vColorTexCoord;
in vec2 vMaskTexCoord;
vec4 sampleSrcColor(){
float coverage = texture(uStencilTexture, vMaskTexCoord). r;
vec4 srcRGBA = texture(uPaintTexture, vColorTexCoord);
return vec4(srcRGBA . rgb, srcRGBA . a * coverage);
}
vec4 sampleDestColor(){
vec2 destTexCoord = gl_FragCoord . xy / uFramebufferSize;
return texture(uDest, destTexCoord);
}
vec4 blendColors(vec4 destRGBA, vec4 srcRGBA, vec3 blendedRGB){
return vec4(srcRGBA . a *(1.0 - destRGBA . a)* srcRGBA . rgb +
srcRGBA . a * destRGBA . a * blendedRGB +
(1.0 - srcRGBA . a)* destRGBA . a * destRGBA . rgb,
1.0);
}
vec3 select3(bvec3 cond, vec3 a, vec3 b){
return vec3(cond . x ? a . x : b . x, cond . y ? a . y : b . y, cond . z ? a . z : b . z);
}
vec4 getFactor(int factor, vec4 destRGBA, vec4 srcRGBA){
if(factor == 0)
return vec4(0.0);
if(factor == 1)
return vec4(destRGBA . a);
if(factor == 2)
return vec4(srcRGBA . a);
return vec4(1.0 - destRGBA . a);
}
void main(){
vec4 srcRGBA = sampleSrcColor();
vec4 destRGBA = sampleDestColor();
vec4 destFactor = getFactor(uDestFactor, destRGBA, srcRGBA);
vec4 srcFactor = getFactor(uSrcFactor, destRGBA, srcRGBA);
vec4 blended = destFactor * destRGBA * vec4(destRGBA . aaa, 1.0)+
srcFactor * srcRGBA * vec4(srcRGBA . aaa, 1.0);
oFragColor = blended;
}

View File

@ -0,0 +1,80 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#pragma clang diagnostic ignored "-Wmissing-prototypes"
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct spvDescriptorSetBuffer0
{
texture2d<float> uStencilTexture [[id(0)]];
sampler uStencilTextureSmplr [[id(1)]];
texture2d<float> uPaintTexture [[id(2)]];
sampler uPaintTextureSmplr [[id(3)]];
constant float2* uFramebufferSize [[id(4)]];
texture2d<float> uDest [[id(5)]];
sampler uDestSmplr [[id(6)]];
constant int* uDestFactor [[id(7)]];
constant int* uSrcFactor [[id(8)]];
};
struct main0_out
{
float4 oFragColor [[color(0)]];
};
struct main0_in
{
float2 vColorTexCoord [[user(locn0)]];
float2 vMaskTexCoord [[user(locn1)]];
};
float4 sampleSrcColor(thread texture2d<float> uStencilTexture, thread const sampler uStencilTextureSmplr, thread float2& vMaskTexCoord, thread texture2d<float> uPaintTexture, thread const sampler uPaintTextureSmplr, thread float2& vColorTexCoord)
{
float coverage = uStencilTexture.sample(uStencilTextureSmplr, vMaskTexCoord).x;
float4 srcRGBA = uPaintTexture.sample(uPaintTextureSmplr, vColorTexCoord);
return float4(srcRGBA.xyz, srcRGBA.w * coverage);
}
float4 sampleDestColor(thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread texture2d<float> uDest, thread const sampler uDestSmplr)
{
float2 destTexCoord = gl_FragCoord.xy / uFramebufferSize;
return uDest.sample(uDestSmplr, destTexCoord);
}
float4 getFactor(thread const int& factor, thread const float4& destRGBA, thread const float4& srcRGBA)
{
if (factor == 0)
{
return float4(0.0);
}
if (factor == 1)
{
return float4(destRGBA.w);
}
if (factor == 2)
{
return float4(srcRGBA.w);
}
return float4(1.0 - destRGBA.w);
}
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 destRGBA = sampleDestColor(gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), spvDescriptorSet0.uDest, spvDescriptorSet0.uDestSmplr);
int param = (*spvDescriptorSet0.uDestFactor);
float4 param_1 = destRGBA;
float4 param_2 = srcRGBA;
float4 destFactor = getFactor(param, param_1, param_2);
int param_3 = (*spvDescriptorSet0.uSrcFactor);
float4 param_4 = destRGBA;
float4 param_5 = srcRGBA;
float4 srcFactor = getFactor(param_3, param_4, param_5);
float4 blended = ((destFactor * destRGBA) * float4(destRGBA.www, 1.0)) + ((srcFactor * srcRGBA) * float4(srcRGBA.www, 1.0));
out.oFragColor = blended;
return out;
}

View File

@ -26,6 +26,7 @@ SHADERS=\
tile_alpha_dodgeburn.fs.glsl \ tile_alpha_dodgeburn.fs.glsl \
tile_alpha_hsl.fs.glsl \ tile_alpha_hsl.fs.glsl \
tile_alpha_overlay.fs.glsl \ tile_alpha_overlay.fs.glsl \
tile_alpha_porterduff.fs.glsl \
tile_copy.fs.glsl \ tile_copy.fs.glsl \
tile_copy.vs.glsl \ tile_copy.vs.glsl \
tile_solid.fs.glsl \ tile_solid.fs.glsl \

View File

@ -0,0 +1,51 @@
#version 330
// pathfinder/shaders/tile_alpha_porterduff.fs.glsl
//
// Copyright © 2020 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Porter-Duff blend modes not supported by the standard GPU blender.
#extension GL_GOOGLE_include_directive : enable
#define PORTER_DUFF_FACTOR_ZERO 0
#define PORTER_DUFF_FACTOR_DEST_ALPHA 1
#define PORTER_DUFF_FACTOR_SRC_ALPHA 2
#define PORTER_DUFF_FACTOR_ONE_MINUS_DEST_ALPHA 3
precision highp float;
uniform int uDestFactor;
uniform int uSrcFactor;
out vec4 oFragColor;
#include "tile_alpha_sample.inc.glsl"
vec4 getFactor(int factor, vec4 destRGBA, vec4 srcRGBA) {
if (factor == PORTER_DUFF_FACTOR_ZERO)
return vec4(0.0);
if (factor == PORTER_DUFF_FACTOR_DEST_ALPHA)
return vec4(destRGBA.a);
if (factor == PORTER_DUFF_FACTOR_SRC_ALPHA)
return vec4(srcRGBA.a);
return vec4(1.0 - destRGBA.a);
}
void main() {
vec4 srcRGBA = sampleSrcColor();
vec4 destRGBA = sampleDestColor();
vec4 destFactor = getFactor(uDestFactor, destRGBA, srcRGBA);
vec4 srcFactor = getFactor(uSrcFactor, destRGBA, srcRGBA);
vec4 blended = destFactor * destRGBA * vec4(destRGBA.aaa, 1.0) +
srcFactor * srcRGBA * vec4(srcRGBA.aaa, 1.0);
oFragColor = blended;
}