Merge pull request #320 from pcwalton/painting-nothing

Clear the canvas to the background color if no drawing command did so.
This commit is contained in:
Patrick Walton 2020-05-07 21:45:23 -07:00 committed by GitHub
commit 46070914be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1852 additions and 15 deletions

View File

@ -10,7 +10,7 @@
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::{BlitProgram, BlitVertexArray, ClipTileProgram, ClipTileVertexArray}; use crate::gpu::shaders::{BlitProgram, BlitVertexArray, ClearProgram, ClearVertexArray, ClipTileProgram, ClipTileVertexArray};
use crate::gpu::shaders::{CopyTileProgram, CopyTileVertexArray, FillProgram, FillVertexArray}; use crate::gpu::shaders::{CopyTileProgram, CopyTileVertexArray, FillProgram, FillVertexArray};
use crate::gpu::shaders::{MAX_FILLS_PER_BATCH, MAX_TILES_PER_BATCH, ReprojectionProgram}; use crate::gpu::shaders::{MAX_FILLS_PER_BATCH, MAX_TILES_PER_BATCH, ReprojectionProgram};
use crate::gpu::shaders::{ReprojectionVertexArray, StencilProgram, StencilVertexArray}; use crate::gpu::shaders::{ReprojectionVertexArray, StencilProgram, StencilVertexArray};
@ -33,8 +33,9 @@ use pathfinder_geometry::transform3d::Transform4F;
use pathfinder_geometry::util; use pathfinder_geometry::util;
use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F, vec2f, vec2i}; use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F, vec2f, vec2i};
use pathfinder_gpu::{BlendFactor, BlendOp, BlendState, BufferData, BufferTarget, BufferUploadMode}; use pathfinder_gpu::{BlendFactor, BlendOp, BlendState, BufferData, BufferTarget, BufferUploadMode};
use pathfinder_gpu::{ClearOps, ComputeDimensions, ComputeState, DepthFunc, DepthState, Device, ImageAccess, ImageBinding, Primitive, RenderOptions}; use pathfinder_gpu::{ClearOps, ComputeDimensions, ComputeState, DepthFunc, DepthState, Device};
use pathfinder_gpu::{RenderState, RenderTarget, StencilFunc, StencilState, TextureDataRef}; use pathfinder_gpu::{ImageAccess, ImageBinding, Primitive, RenderOptions, RenderState};
use pathfinder_gpu::{RenderTarget, StencilFunc, StencilState, TextureDataRef};
use pathfinder_gpu::{TextureFormat, UniformData}; use pathfinder_gpu::{TextureFormat, UniformData};
use pathfinder_resources::ResourceLoader; use pathfinder_resources::ResourceLoader;
use pathfinder_simd::default::{F32x2, F32x4, I32x2}; use pathfinder_simd::default::{F32x2, F32x4, I32x2};
@ -104,6 +105,7 @@ pub struct Renderer<D> where D: Device {
dest_framebuffer: DestFramebuffer<D>, dest_framebuffer: DestFramebuffer<D>,
options: RendererOptions, options: RendererOptions,
blit_program: BlitProgram<D>, blit_program: BlitProgram<D>,
clear_program: ClearProgram<D>,
fill_program: FillProgram<D>, fill_program: FillProgram<D>,
tile_program: TileProgram<D>, tile_program: TileProgram<D>,
tile_copy_program: CopyTileProgram<D>, tile_copy_program: CopyTileProgram<D>,
@ -143,6 +145,7 @@ pub struct Renderer<D> where D: Device {
struct Frame<D> where D: Device { struct Frame<D> where D: Device {
framebuffer_flags: FramebufferFlags, framebuffer_flags: FramebufferFlags,
blit_vertex_array: BlitVertexArray<D>, blit_vertex_array: BlitVertexArray<D>,
clear_vertex_array: ClearVertexArray<D>,
fill_vertex_storage_allocator: StorageAllocator<D, FillVertexStorage<D>>, fill_vertex_storage_allocator: StorageAllocator<D, FillVertexStorage<D>>,
tile_vertex_storage_allocator: StorageAllocator<D, TileVertexStorage<D>>, tile_vertex_storage_allocator: StorageAllocator<D, TileVertexStorage<D>>,
quads_vertex_indices_buffer: D::Buffer, quads_vertex_indices_buffer: D::Buffer,
@ -163,6 +166,7 @@ impl<D> Renderer<D> where D: Device {
options: RendererOptions) options: RendererOptions)
-> Renderer<D> { -> Renderer<D> {
let blit_program = BlitProgram::new(&device, resources); let blit_program = BlitProgram::new(&device, resources);
let clear_program = ClearProgram::new(&device, resources);
let fill_program = FillProgram::new(&device, resources, &options); let fill_program = FillProgram::new(&device, resources, &options);
let tile_program = TileProgram::new(&device, resources); let tile_program = TileProgram::new(&device, resources);
let tile_copy_program = CopyTileProgram::new(&device, resources); let tile_copy_program = CopyTileProgram::new(&device, resources);
@ -191,6 +195,7 @@ impl<D> Renderer<D> where D: Device {
let front_frame = Frame::new(&device, let front_frame = Frame::new(&device,
&blit_program, &blit_program,
&clear_program,
&tile_clip_program, &tile_clip_program,
&reprojection_program, &reprojection_program,
&stencil_program, &stencil_program,
@ -199,6 +204,7 @@ impl<D> Renderer<D> where D: Device {
window_size); window_size);
let back_frame = Frame::new(&device, let back_frame = Frame::new(&device,
&blit_program, &blit_program,
&clear_program,
&tile_clip_program, &tile_clip_program,
&reprojection_program, &reprojection_program,
&stencil_program, &stencil_program,
@ -212,6 +218,7 @@ impl<D> Renderer<D> where D: Device {
dest_framebuffer, dest_framebuffer,
options, options,
blit_program, blit_program,
clear_program,
fill_program, fill_program,
tile_program, tile_program,
tile_copy_program, tile_copy_program,
@ -251,7 +258,7 @@ impl<D> Renderer<D> where D: Device {
pub fn begin_scene(&mut self) { pub fn begin_scene(&mut self) {
self.back_frame.framebuffer_flags = FramebufferFlags::empty(); self.back_frame.framebuffer_flags = FramebufferFlags::empty();
for alpha_tile_page in self.back_frame.alpha_tile_pages.values_mut() { for alpha_tile_page in self.back_frame.alpha_tile_pages.values_mut() {
alpha_tile_page.must_preserve_framebuffer = false; alpha_tile_page.framebuffer_is_dirty = false;
} }
self.device.begin_commands(); self.device.begin_commands();
@ -311,6 +318,7 @@ impl<D> Renderer<D> where D: Device {
} }
pub fn end_scene(&mut self) { pub fn end_scene(&mut self) {
self.clear_dest_framebuffer_if_necessary();
self.blit_intermediate_dest_framebuffer_if_necessary(); self.blit_intermediate_dest_framebuffer_if_necessary();
let old_front_frame_fence = self.front_frame_fence.take(); let old_front_frame_fence = self.front_frame_fence.take();
@ -641,7 +649,7 @@ impl<D> Renderer<D> where D: Device {
BufferTarget::Vertex); BufferTarget::Vertex);
let mut clear_color = None; let mut clear_color = None;
if !alpha_tile_page.must_preserve_framebuffer { if !alpha_tile_page.framebuffer_is_dirty {
clear_color = Some(ColorF::default()); clear_color = Some(ColorF::default());
}; };
@ -681,7 +689,7 @@ impl<D> Renderer<D> where D: Device {
self.device.end_timer_query(&timer_query); self.device.end_timer_query(&timer_query);
self.current_timer.as_mut().unwrap().fill_times.push(TimerFuture::new(timer_query)); self.current_timer.as_mut().unwrap().fill_times.push(TimerFuture::new(timer_query));
alpha_tile_page.must_preserve_framebuffer = true; alpha_tile_page.framebuffer_is_dirty = true;
buffered_fills.clear(); buffered_fills.clear();
} }
@ -783,7 +791,7 @@ impl<D> Renderer<D> where D: Device {
self.device.end_timer_query(&timer_query); self.device.end_timer_query(&timer_query);
self.current_timer.as_mut().unwrap().fill_times.push(TimerFuture::new(timer_query)); self.current_timer.as_mut().unwrap().fill_times.push(TimerFuture::new(timer_query));
alpha_tile_page.must_preserve_framebuffer = true; alpha_tile_page.framebuffer_is_dirty = true;
buffered_fills.clear(); buffered_fills.clear();
} }
@ -804,7 +812,7 @@ impl<D> Renderer<D> where D: Device {
} }
let mut clear_color = None; let mut clear_color = None;
if !self.back_frame.alpha_tile_pages[&dest_page].must_preserve_framebuffer { if !self.back_frame.alpha_tile_pages[&dest_page].framebuffer_is_dirty {
clear_color = Some(ColorF::default()); clear_color = Some(ColorF::default());
}; };
@ -856,7 +864,7 @@ impl<D> Renderer<D> where D: Device {
.alpha_tile_pages .alpha_tile_pages
.get_mut(&dest_page) .get_mut(&dest_page)
.unwrap() .unwrap()
.must_preserve_framebuffer = true; .framebuffer_is_dirty = true;
} }
fn tile_transform(&self) -> Transform4F { fn tile_transform(&self) -> Transform4F {
@ -1231,6 +1239,39 @@ impl<D> Renderer<D> where D: Device {
]); ]);
} }
fn clear_dest_framebuffer_if_necessary(&mut self) {
let background_color = match self.options.background_color {
None => return,
Some(background_color) => background_color,
};
if self.back_frame
.framebuffer_flags
.contains(FramebufferFlags::DEST_FRAMEBUFFER_IS_DIRTY) {
return;
}
let main_viewport = self.main_viewport();
let uniforms = [
(&self.clear_program.rect_uniform, UniformData::Vec4(main_viewport.to_f32().0)),
(&self.clear_program.framebuffer_size_uniform,
UniformData::Vec2(main_viewport.size().to_f32().0)),
(&self.clear_program.color_uniform, UniformData::Vec4(background_color.0)),
];
self.device.draw_elements(6, &RenderState {
target: &RenderTarget::Default,
program: &self.clear_program.program,
vertex_array: &self.back_frame.clear_vertex_array.vertex_array,
primitive: Primitive::Triangles,
textures: &[],
images: &[],
uniforms: &uniforms[..],
viewport: main_viewport,
options: RenderOptions::default(),
});
}
fn blit_intermediate_dest_framebuffer_if_necessary(&mut self) { fn blit_intermediate_dest_framebuffer_if_necessary(&mut self) {
if !self.flags.contains(RendererFlags::INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED) { if !self.flags.contains(RendererFlags::INTERMEDIATE_DEST_FRAMEBUFFER_NEEDED) {
return; return;
@ -1287,7 +1328,7 @@ impl<D> Renderer<D> where D: Device {
None => { None => {
self.back_frame self.back_frame
.framebuffer_flags .framebuffer_flags
.contains(FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS) .contains(FramebufferFlags::DEST_FRAMEBUFFER_IS_DIRTY)
} }
}; };
@ -1312,7 +1353,7 @@ impl<D> Renderer<D> where D: Device {
None => { None => {
self.back_frame self.back_frame
.framebuffer_flags .framebuffer_flags
.insert(FramebufferFlags::MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS); .insert(FramebufferFlags::DEST_FRAMEBUFFER_IS_DIRTY);
} }
} }
} }
@ -1360,6 +1401,7 @@ impl<D> Frame<D> where D: Device {
// FIXME(pcwalton): This signature shouldn't be so big. Make a struct. // FIXME(pcwalton): This signature shouldn't be so big. Make a struct.
fn new(device: &D, fn new(device: &D,
blit_program: &BlitProgram<D>, blit_program: &BlitProgram<D>,
clear_program: &ClearProgram<D>,
tile_clip_program: &ClipTileProgram<D>, tile_clip_program: &ClipTileProgram<D>,
reprojection_program: &ReprojectionProgram<D>, reprojection_program: &ReprojectionProgram<D>,
stencil_program: &StencilProgram<D>, stencil_program: &StencilProgram<D>,
@ -1373,6 +1415,10 @@ impl<D> Frame<D> where D: Device {
&blit_program, &blit_program,
&quad_vertex_positions_buffer, &quad_vertex_positions_buffer,
&quad_vertex_indices_buffer); &quad_vertex_indices_buffer);
let clear_vertex_array = ClearVertexArray::new(device,
&clear_program,
&quad_vertex_positions_buffer,
&quad_vertex_indices_buffer);
let tile_clip_vertex_array = ClipTileVertexArray::new(device, let tile_clip_vertex_array = ClipTileVertexArray::new(device,
&tile_clip_program, &tile_clip_program,
&quad_vertex_positions_buffer, &quad_vertex_positions_buffer,
@ -1399,6 +1445,7 @@ impl<D> Frame<D> where D: Device {
Frame { Frame {
blit_vertex_array, blit_vertex_array,
clear_vertex_array,
tile_vertex_storage_allocator, tile_vertex_storage_allocator,
fill_vertex_storage_allocator, fill_vertex_storage_allocator,
tile_clip_vertex_array, tile_clip_vertex_array,
@ -1698,8 +1745,8 @@ impl Div<usize> for RenderTime {
bitflags! { bitflags! {
struct FramebufferFlags: u8 { struct FramebufferFlags: u8 {
const MUST_PRESERVE_MASK_FRAMEBUFFER_CONTENTS = 0x01; const MASK_FRAMEBUFFER_IS_DIRTY = 0x01;
const MUST_PRESERVE_DEST_FRAMEBUFFER_CONTENTS = 0x02; const DEST_FRAMEBUFFER_IS_DIRTY = 0x02;
} }
} }
@ -1912,7 +1959,7 @@ struct AlphaTilePage<D> where D: Device {
buffered_fills: Vec<Fill>, buffered_fills: Vec<Fill>,
pending_fills: Vec<Fill>, pending_fills: Vec<Fill>,
framebuffer: D::Framebuffer, framebuffer: D::Framebuffer,
must_preserve_framebuffer: bool, framebuffer_is_dirty: bool,
} }
impl<D> AlphaTilePage<D> where D: Device { impl<D> AlphaTilePage<D> where D: Device {
@ -1924,7 +1971,7 @@ impl<D> AlphaTilePage<D> where D: Device {
buffered_fills: vec![], buffered_fills: vec![],
pending_fills: vec![], pending_fills: vec![],
framebuffer, framebuffer,
must_preserve_framebuffer: false, framebuffer_is_dirty: false,
} }
} }
} }

View File

@ -52,6 +52,35 @@ impl<D> BlitVertexArray<D> where D: Device {
} }
} }
pub struct ClearVertexArray<D> where D: Device {
pub vertex_array: D::VertexArray,
}
impl<D> ClearVertexArray<D> where D: Device {
pub fn new(device: &D,
clear_program: &ClearProgram<D>,
quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer)
-> ClearVertexArray<D> {
let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&clear_program.program, "Position").unwrap();
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&vertex_array, &position_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: 4,
offset: 0,
divisor: 0,
buffer_index: 0,
});
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
ClearVertexArray { vertex_array }
}
}
pub struct FillVertexArray<D> where D: Device { pub struct FillVertexArray<D> where D: Device {
pub vertex_array: D::VertexArray, pub vertex_array: D::VertexArray,
} }
@ -337,6 +366,23 @@ impl<D> BlitProgram<D> where D: Device {
} }
} }
pub struct ClearProgram<D> where D: Device {
pub program: D::Program,
pub rect_uniform: D::Uniform,
pub framebuffer_size_uniform: D::Uniform,
pub color_uniform: D::Uniform,
}
impl<D> ClearProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ClearProgram<D> {
let program = device.create_raster_program(resources, "clear");
let rect_uniform = device.get_uniform(&program, "Rect");
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
let color_uniform = device.get_uniform(&program, "Color");
ClearProgram { program, rect_uniform, framebuffer_size_uniform, color_uniform }
}
}
pub enum FillProgram<D> where D: Device { pub enum FillProgram<D> where D: Device {
Raster(FillRasterProgram<D>), Raster(FillRasterProgram<D>),
Compute(FillComputeProgram<D>), Compute(FillComputeProgram<D>),

View File

@ -0,0 +1,25 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
precision highp float;
precision highp sampler2D;
uniform vec4 uColor;
out vec4 oFragColor;
void main(){
oFragColor = vec4(uColor . rgb, 1.0)* uColor . a;
}

View File

@ -0,0 +1,27 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
precision highp float;
precision highp sampler2D;
uniform vec4 uRect;
uniform vec2 uFramebufferSize;
in ivec2 aPosition;
void main(){
vec2 position = mix(uRect . xy, uRect . zw, vec2(aPosition))/ uFramebufferSize * 2.0 - 1.0;
gl_Position = vec4(position . x, - position . y, 0.0, 1.0);
}

View File

@ -0,0 +1,25 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
precision highp float;
precision highp sampler2D;
uniform vec4 uColor;
out vec4 oFragColor;
void main(){
oFragColor = vec4(uColor . rgb, 1.0)* uColor . a;
}

View File

@ -0,0 +1,27 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
precision highp float;
precision highp sampler2D;
uniform vec4 uRect;
uniform vec2 uFramebufferSize;
in ivec2 aPosition;
void main(){
vec2 position = mix(uRect . xy, uRect . zw, vec2(aPosition))/ uFramebufferSize * 2.0 - 1.0;
gl_Position = vec4(position . x, - position . y, 0.0, 1.0);
}

View File

@ -0,0 +1,782 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#extension GL_GOOGLE_include_directive : enable
precision highp float;
precision highp sampler2D;
layout(local_size_x = 16, local_size_y = 4)in;
layout(rgba8)uniform image2D uDestImage;
uniform sampler2D uTextureMetadata;
uniform ivec2 uTextureMetadataSize;
uniform sampler2D uColorTexture0;
uniform sampler2D uMaskTexture0;
uniform sampler2D uGammaLUT;
uniform vec2 uTileSize;
uniform vec4 uFilterParams0;
uniform vec4 uFilterParams1;
uniform vec4 uFilterParams2;
uniform vec2 uFramebufferSize;
uniform vec2 uColorTextureSize0;
uniform int uCtrl;
uniform sampler2D uAreaLUT;
layout(std430, binding = 0)buffer bFills {
restrict readonly uvec2 iFills[];
};
layout(std430, binding = 1)buffer bNextFills {
restrict readonly int iNextFills[];
};
layout(std430, binding = 2)buffer bFillTileMap {
restrict readonly int iFillTileMap[];
};
layout(std430, binding = 3)buffer bTiles {
restrict readonly uint iTiles[];
};
layout(std430, binding = 4)buffer bNextTiles {
restrict readonly int iNextTiles[];
};
layout(std430, binding = 5)buffer bFirstTiles {
restrict readonly int iFirstTiles[];
};
vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT){
vec2 left = from . x < to . x ? from : to, right = from . x < to . x ? to : from;
vec2 window = clamp(vec2(from . x, to . x), - 0.5, 0.5);
float offset = mix(window . x, window . y, 0.5)- left . x;
float t = offset /(right . x - left . x);
float y = mix(left . y, right . y, t);
float d =(right . y - left . y)/(right . x - left . x);
float dX = window . x - window . y;
return texture(areaLUT, vec2(y + 8.0, abs(d * dX))/ 16.0)* dX;
}
vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT);
ivec2 calculateTileOrigin(uint tileIndex){
return ivec2(tileIndex & 0xff,(tileIndex >> 8u)& 0xff)* 16;
}
vec4 calculateFillAlpha(ivec2 tileSubCoord, uint tileIndex){
int fillIndex = iFillTileMap[tileIndex];
if(fillIndex < 0)
return vec4(0.0);
vec4 coverages = vec4(0.0);
do {
uvec2 fill = iFills[fillIndex];
vec2 from = vec2(fill . y & 0xf,(fill . y >> 4u)& 0xf)+
vec2(fill . x & 0xff,(fill . x >> 8u)& 0xff)/ 256.0;
vec2 to = vec2((fill . y >> 8u)& 0xf,(fill . y >> 12u)& 0xf)+
vec2((fill . x >> 16u)& 0xff,(fill . x >> 24u)& 0xff)/ 256.0;
coverages += computeCoverage(from -(vec2(tileSubCoord)+ vec2(0.5)),
to -(vec2(tileSubCoord)+ vec2(0.5)),
uAreaLUT);
fillIndex = iNextFills[fillIndex];
} while(fillIndex >= 0);
return coverages;
}
vec4 sampleColor(sampler2D colorTexture, vec2 colorTexCoord){
return texture(colorTexture, colorTexCoord);
}
vec4 combineColor0(vec4 destColor, vec4 srcColor, int op){
switch(op){
case 0x1 :
return vec4(srcColor . rgb, srcColor . a * destColor . a);
case 0x2 :
return vec4(destColor . rgb, srcColor . a * destColor . a);
}
return destColor;
}
float filterTextSample1Tap(float offset, sampler2D colorTexture, vec2 colorTexCoord){
return texture(colorTexture, colorTexCoord + vec2(offset, 0.0)). r;
}
void filterTextSample9Tap(out vec4 outAlphaLeft,
out float outAlphaCenter,
out vec4 outAlphaRight,
sampler2D colorTexture,
vec2 colorTexCoord,
vec4 kernel,
float onePixel){
bool wide = kernel . x > 0.0;
outAlphaLeft =
vec4(wide ? filterTextSample1Tap(- 4.0 * onePixel, colorTexture, colorTexCoord): 0.0,
filterTextSample1Tap(- 3.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(- 2.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(- 1.0 * onePixel, colorTexture, colorTexCoord));
outAlphaCenter = filterTextSample1Tap(0.0, colorTexture, colorTexCoord);
outAlphaRight =
vec4(filterTextSample1Tap(1.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(2.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(3.0 * onePixel, colorTexture, colorTexCoord),
wide ? filterTextSample1Tap(4.0 * onePixel, colorTexture, colorTexCoord): 0.0);
}
float filterTextConvolve7Tap(vec4 alpha0, vec3 alpha1, vec4 kernel){
return dot(alpha0, kernel)+ dot(alpha1, kernel . zyx);
}
float filterTextGammaCorrectChannel(float bgColor, float fgColor, sampler2D gammaLUT){
return texture(gammaLUT, vec2(fgColor, 1.0 - bgColor)). r;
}
vec3 filterTextGammaCorrect(vec3 bgColor, vec3 fgColor, sampler2D gammaLUT){
return vec3(filterTextGammaCorrectChannel(bgColor . r, fgColor . r, gammaLUT),
filterTextGammaCorrectChannel(bgColor . g, fgColor . g, gammaLUT),
filterTextGammaCorrectChannel(bgColor . b, fgColor . b, gammaLUT));
}
vec4 filterText(vec2 colorTexCoord,
sampler2D colorTexture,
sampler2D gammaLUT,
vec2 colorTextureSize,
vec4 filterParams0,
vec4 filterParams1,
vec4 filterParams2){
vec4 kernel = filterParams0;
vec3 bgColor = filterParams1 . rgb;
vec3 fgColor = filterParams2 . rgb;
bool gammaCorrectionEnabled = filterParams2 . a != 0.0;
vec3 alpha;
if(kernel . w == 0.0){
alpha = texture(colorTexture, colorTexCoord). rrr;
} else {
vec4 alphaLeft, alphaRight;
float alphaCenter;
filterTextSample9Tap(alphaLeft,
alphaCenter,
alphaRight,
colorTexture,
colorTexCoord,
kernel,
1.0 / colorTextureSize . x);
float r = filterTextConvolve7Tap(alphaLeft, vec3(alphaCenter, alphaRight . xy), kernel);
float g = filterTextConvolve7Tap(vec4(alphaLeft . yzw, alphaCenter), alphaRight . xyz, kernel);
float b = filterTextConvolve7Tap(vec4(alphaLeft . zw, alphaCenter, alphaRight . x),
alphaRight . yzw,
kernel);
alpha = vec3(r, g, b);
}
if(gammaCorrectionEnabled)
alpha = filterTextGammaCorrect(bgColor, alpha, gammaLUT);
return vec4(mix(bgColor, fgColor, alpha), 1.0);
}
vec4 filterRadialGradient(vec2 colorTexCoord,
sampler2D colorTexture,
vec2 colorTextureSize,
vec2 fragCoord,
vec2 framebufferSize,
vec4 filterParams0,
vec4 filterParams1){
vec2 lineFrom = filterParams0 . xy, lineVector = filterParams0 . zw;
vec2 radii = filterParams1 . xy, uvOrigin = filterParams1 . zw;
vec2 dP = colorTexCoord - lineFrom, dC = lineVector;
float dR = radii . y - radii . x;
float a = dot(dC, dC)- dR * dR;
float b = dot(dP, dC)+ radii . x * dR;
float c = dot(dP, dP)- radii . x * radii . x;
float discrim = b * b - a * c;
vec4 color = vec4(0.0);
if(abs(discrim)>= 0.00001){
vec2 ts = vec2(sqrt(discrim)* vec2(1.0, - 1.0)+ vec2(b))/ vec2(a);
if(ts . x > ts . y)
ts = ts . yx;
float t = ts . x >= 0.0 ? ts . x : ts . y;
color = texture(colorTexture, uvOrigin + vec2(clamp(t, 0.0, 1.0), 0.0));
}
return color;
}
vec4 filterBlur(vec2 colorTexCoord,
sampler2D colorTexture,
vec2 colorTextureSize,
vec4 filterParams0,
vec4 filterParams1){
vec2 srcOffsetScale = filterParams0 . xy / colorTextureSize;
int support = int(filterParams0 . z);
vec3 gaussCoeff = filterParams1 . xyz;
float gaussSum = gaussCoeff . x;
vec4 color = texture(colorTexture, colorTexCoord)* gaussCoeff . x;
gaussCoeff . xy *= gaussCoeff . yz;
for(int i = 1;i <= support;i += 2){
float gaussPartialSum = gaussCoeff . x;
gaussCoeff . xy *= gaussCoeff . yz;
gaussPartialSum += gaussCoeff . x;
vec2 srcOffset = srcOffsetScale *(float(i)+ gaussCoeff . x / gaussPartialSum);
color +=(texture(colorTexture, colorTexCoord - srcOffset)+
texture(colorTexture, colorTexCoord + srcOffset))* gaussPartialSum;
gaussSum += 2.0 * gaussPartialSum;
gaussCoeff . xy *= gaussCoeff . yz;
}
return color / gaussSum;
}
vec4 filterNone(vec2 colorTexCoord, sampler2D colorTexture){
return sampleColor(colorTexture, colorTexCoord);
}
vec4 filterColor(vec2 colorTexCoord,
sampler2D colorTexture,
sampler2D gammaLUT,
vec2 colorTextureSize,
vec2 fragCoord,
vec2 framebufferSize,
vec4 filterParams0,
vec4 filterParams1,
vec4 filterParams2,
int colorFilter){
switch(colorFilter){
case 0x1 :
return filterRadialGradient(colorTexCoord,
colorTexture,
colorTextureSize,
fragCoord,
framebufferSize,
filterParams0,
filterParams1);
case 0x3 :
return filterBlur(colorTexCoord,
colorTexture,
colorTextureSize,
filterParams0,
filterParams1);
case 0x2 :
return filterText(colorTexCoord,
colorTexture,
gammaLUT,
colorTextureSize,
filterParams0,
filterParams1,
filterParams2);
}
return filterNone(colorTexCoord, colorTexture);
}
vec3 compositeSelect(bvec3 cond, vec3 ifTrue, vec3 ifFalse){
return vec3(cond . x ? ifTrue . x : ifFalse . x,
cond . y ? ifTrue . y : ifFalse . y,
cond . z ? ifTrue . z : ifFalse . z);
}
float compositeDivide(float num, float denom){
return denom != 0.0 ? num / denom : 0.0;
}
vec3 compositeColorDodge(vec3 destColor, vec3 srcColor){
bvec3 destZero = equal(destColor, vec3(0.0)), srcOne = equal(srcColor, vec3(1.0));
return compositeSelect(destZero,
vec3(0.0),
compositeSelect(srcOne, vec3(1.0), destColor /(vec3(1.0)- srcColor)));
}
vec3 compositeHSLToRGB(vec3 hsl){
float a = hsl . y * min(hsl . z, 1.0 - hsl . z);
vec3 ks = mod(vec3(0.0, 8.0, 4.0)+ vec3(hsl . x * 1.9098593171027443), 12.0);
return hsl . zzz - clamp(min(ks - vec3(3.0), vec3(9.0)- ks), - 1.0, 1.0)* a;
}
vec3 compositeRGBToHSL(vec3 rgb){
float v = max(max(rgb . r, rgb . g), rgb . b), xMin = min(min(rgb . r, rgb . g), rgb . b);
float c = v - xMin, l = mix(xMin, v, 0.5);
vec3 terms = rgb . r == v ? vec3(0.0, rgb . gb):
rgb . g == v ? vec3(2.0, rgb . br):
vec3(4.0, rgb . rg);
float h = 1.0471975511965976 * compositeDivide(terms . x * c + terms . y - terms . z, c);
float s = compositeDivide(c, v);
return vec3(h, s, l);
}
vec3 compositeScreen(vec3 destColor, vec3 srcColor){
return destColor + srcColor - destColor * srcColor;
}
vec3 compositeHardLight(vec3 destColor, vec3 srcColor){
return compositeSelect(lessThanEqual(srcColor, vec3(0.5)),
destColor * vec3(2.0)* srcColor,
compositeScreen(destColor, vec3(2.0)* srcColor - vec3(1.0)));
}
vec3 compositeSoftLight(vec3 destColor, vec3 srcColor){
vec3 darkenedDestColor =
compositeSelect(lessThanEqual(destColor, vec3(0.25)),
((vec3(16.0)* destColor - 12.0)* destColor + 4.0)* destColor,
sqrt(destColor));
vec3 factor = compositeSelect(lessThanEqual(srcColor, vec3(0.5)),
destColor *(vec3(1.0)- destColor),
darkenedDestColor - destColor);
return destColor +(srcColor * 2.0 - 1.0)* factor;
}
vec3 compositeHSL(vec3 destColor, vec3 srcColor, int op){
switch(op){
case 0xc :
return vec3(srcColor . x, destColor . y, destColor . z);
case 0xd :
return vec3(destColor . x, srcColor . y, destColor . z);
case 0xe :
return vec3(srcColor . x, srcColor . y, destColor . z);
default :
return vec3(destColor . x, destColor . y, srcColor . z);
}
}
vec3 compositeRGB(vec3 destColor, vec3 srcColor, int op){
switch(op){
case 0x1 :
return destColor * srcColor;
case 0x2 :
return compositeScreen(destColor, srcColor);
case 0x3 :
return compositeHardLight(srcColor, destColor);
case 0x4 :
return min(destColor, srcColor);
case 0x5 :
return max(destColor, srcColor);
case 0x6 :
return compositeColorDodge(destColor, srcColor);
case 0x7 :
return vec3(1.0)- compositeColorDodge(vec3(1.0)- destColor, vec3(1.0)- srcColor);
case 0x8 :
return compositeHardLight(destColor, srcColor);
case 0x9 :
return compositeSoftLight(destColor, srcColor);
case 0xa :
return abs(destColor - srcColor);
case 0xb :
return destColor + srcColor - vec3(2.0)* destColor * srcColor;
case 0xc :
case 0xd :
case 0xe :
case 0xf :
return compositeHSLToRGB(compositeHSL(compositeRGBToHSL(destColor),
compositeRGBToHSL(srcColor),
op));
}
return srcColor;
}
vec4 composite(vec4 srcColor,
sampler2D destTexture,
vec2 destTextureSize,
vec2 fragCoord,
int op){
if(op == 0x0)
return srcColor;
vec2 destTexCoord = fragCoord / destTextureSize;
vec4 destColor = texture(destTexture, destTexCoord);
vec3 blendedRGB = compositeRGB(destColor . rgb, srcColor . rgb, op);
return vec4(srcColor . a *(1.0 - destColor . a)* srcColor . rgb +
srcColor . a * destColor . a * blendedRGB +
(1.0 - srcColor . a)* destColor . rgb,
1.0);
}
float sampleMask(float maskAlpha,
sampler2D maskTexture,
vec2 maskTextureSize,
vec3 maskTexCoord,
int maskCtrl){
if(maskCtrl == 0)
return maskAlpha;
ivec2 maskTexCoordI = ivec2(floor(maskTexCoord . xy));
vec4 texel = texture(maskTexture,(vec2(maskTexCoordI / ivec2(1, 4))+ 0.5)/ maskTextureSize);
float coverage = texel[maskTexCoordI . y % 4]+ maskTexCoord . z;
if((maskCtrl & 0x1)!= 0)
coverage = abs(coverage);
else
coverage = 1.0 - abs(1.0 - mod(coverage, 2.0));
return min(maskAlpha, coverage);
}
vec4 calculateColorWithMaskAlpha(float maskAlpha,
vec4 baseColor,
vec2 colorTexCoord0,
vec2 fragCoord,
int ctrl){
vec4 color = baseColor;
int color0Combine =(ctrl >> 6)&
0x3;
if(color0Combine != 0){
int color0Filter =(ctrl >> 4)& 0x3;
vec4 color0 = filterColor(colorTexCoord0,
uColorTexture0,
uGammaLUT,
uColorTextureSize0,
fragCoord,
uFramebufferSize,
uFilterParams0,
uFilterParams1,
uFilterParams2,
color0Filter);
color = combineColor0(color, color0, color0Combine);
}
color . a *= maskAlpha;
color . rgb *= color . a;
return color;
}
void lookupTextureMetadata(int color,
out mat2 outColorTexMatrix0,
out vec4 outColorTexOffsets,
out vec4 outBaseColor){
vec2 textureMetadataScale = vec2(1.0)/ vec2(uTextureMetadataSize);
vec2 metadataEntryCoord = vec2(color % 128 * 4, color / 128);
vec2 colorTexMatrix0Coord =(metadataEntryCoord + vec2(0.5, 0.5))* textureMetadataScale;
vec2 colorTexOffsetsCoord =(metadataEntryCoord + vec2(1.5, 0.5))* textureMetadataScale;
vec2 baseColorCoord =(metadataEntryCoord + vec2(2.5, 0.5))* textureMetadataScale;
outColorTexMatrix0 = mat2(texture(uTextureMetadata, colorTexMatrix0Coord));
outColorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord);
outBaseColor = texture(uTextureMetadata, baseColorCoord);
}
void main(){
int maskCtrl0 =(uCtrl >> 0)& 0x1;
vec4 colors[4]= { vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)};
ivec2 tileSubCoord = ivec2(gl_LocalInvocationID . xy)* ivec2(1, 4);
ivec2 tileOrigin = ivec2(0);
int tileIndex = iFirstTiles[gl_WorkGroupID . z];
int overlapCount = 0;
while(tileIndex >= 0){
overlapCount ++;
uint tileCoord = iTiles[tileIndex * 3 + 0];
uint maskTexCoord = iTiles[tileIndex * 3 + 1];
uint colorCtrl = iTiles[tileIndex * 3 + 2];
tileOrigin = ivec2(int(tileCoord & 0xffff), int(tileCoord >> 16));
int ctrl = int(uCtrl);
int tileColor = int(colorCtrl & 0xffff);
int tileCtrl = int(colorCtrl >> 16);
mat2 colorTexMatrix0;
vec4 colorTexOffsets;
vec4 baseColor;
lookupTextureMetadata(tileColor, colorTexMatrix0, colorTexOffsets, baseColor);
int maskTileCtrl0 =(tileCtrl >> 0)& 0x3;
vec4 maskAlphas = vec4(1.0);
if(maskCtrl0 != 0 && maskTileCtrl0 != 0){
uint maskTileIndex0 = maskTexCoord & 0xffff;
int maskTileBackdrop0 = int(maskTexCoord << 8)>> 24;
maskAlphas = clamp(abs(calculateFillAlpha(tileSubCoord, maskTileIndex0)+
float(maskTileBackdrop0)), 0.0, 1.0);
}
for(int yOffset = 0;yOffset < 4;yOffset ++){
ivec2 fragCoordI = tileOrigin * ivec2(uTileSize)+ tileSubCoord + ivec2(0, yOffset);
vec2 fragCoord = vec2(fragCoordI)+ vec2(0.5);
vec2 colorTexCoord0 = colorTexMatrix0 * fragCoord + colorTexOffsets . xy;
vec4 color = calculateColorWithMaskAlpha(maskAlphas[yOffset],
baseColor,
colorTexCoord0,
fragCoord,
ctrl);
colors[yOffset]= colors[yOffset]*(1.0 - color . a)+ color;
}
tileIndex = iNextTiles[tileIndex];
}
for(int yOffset = 0;yOffset < 4;yOffset ++){
ivec2 fragCoord = tileOrigin * ivec2(uTileSize)+ tileSubCoord + ivec2(0, yOffset);
vec4 color = colors[yOffset];
if(color . a < 1.0)
color = imageLoad(uDestImage, fragCoord)*(1.0 - color . a)+ color;
imageStore(uDestImage, fragCoord, color);
}
}

View File

@ -0,0 +1,708 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#extension GL_GOOGLE_include_directive : enable
precision highp float;
precision highp sampler2D;
uniform sampler2D uColorTexture0;
uniform sampler2D uMaskTexture0;
uniform sampler2D uDestTexture;
uniform sampler2D uGammaLUT;
uniform vec4 uFilterParams0;
uniform vec4 uFilterParams1;
uniform vec4 uFilterParams2;
uniform vec2 uFramebufferSize;
uniform vec2 uColorTextureSize0;
uniform int uCtrl;
uniform sampler2D uAreaLUT;
layout(std430, binding = 0)buffer bFills {
restrict readonly uvec2 iFills[];
};
layout(std430, binding = 1)buffer bNextFills {
restrict readonly int iNextFills[];
};
layout(std430, binding = 2)buffer bFillTileMap {
restrict readonly int iFillTileMap[];
};
in vec2 vTileSubCoord;
flat in uint vMaskTileIndex0;
flat in int vMaskTileBackdrop0;
in vec2 vColorTexCoord0;
in vec4 vBaseColor;
in float vTileCtrl;
out vec4 oFragColor;
vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT){
vec2 left = from . x < to . x ? from : to, right = from . x < to . x ? to : from;
vec2 window = clamp(vec2(from . x, to . x), - 0.5, 0.5);
float offset = mix(window . x, window . y, 0.5)- left . x;
float t = offset /(right . x - left . x);
float y = mix(left . y, right . y, t);
float d =(right . y - left . y)/(right . x - left . x);
float dX = window . x - window . y;
return texture(areaLUT, vec2(y + 8.0, abs(d * dX))/ 16.0)* dX;
}
vec4 computeCoverage(vec2 from, vec2 to, sampler2D areaLUT);
ivec2 calculateTileOrigin(uint tileIndex){
return ivec2(tileIndex & 0xff,(tileIndex >> 8u)& 0xff)* 16;
}
vec4 calculateFillAlpha(ivec2 tileSubCoord, uint tileIndex){
int fillIndex = iFillTileMap[tileIndex];
if(fillIndex < 0)
return vec4(0.0);
vec4 coverages = vec4(0.0);
do {
uvec2 fill = iFills[fillIndex];
vec2 from = vec2(fill . y & 0xf,(fill . y >> 4u)& 0xf)+
vec2(fill . x & 0xff,(fill . x >> 8u)& 0xff)/ 256.0;
vec2 to = vec2((fill . y >> 8u)& 0xf,(fill . y >> 12u)& 0xf)+
vec2((fill . x >> 16u)& 0xff,(fill . x >> 24u)& 0xff)/ 256.0;
coverages += computeCoverage(from -(vec2(tileSubCoord)+ vec2(0.5)),
to -(vec2(tileSubCoord)+ vec2(0.5)),
uAreaLUT);
fillIndex = iNextFills[fillIndex];
} while(fillIndex >= 0);
return coverages;
}
vec4 sampleColor(sampler2D colorTexture, vec2 colorTexCoord){
return texture(colorTexture, colorTexCoord);
}
vec4 combineColor0(vec4 destColor, vec4 srcColor, int op){
switch(op){
case 0x1 :
return vec4(srcColor . rgb, srcColor . a * destColor . a);
case 0x2 :
return vec4(destColor . rgb, srcColor . a * destColor . a);
}
return destColor;
}
float filterTextSample1Tap(float offset, sampler2D colorTexture, vec2 colorTexCoord){
return texture(colorTexture, colorTexCoord + vec2(offset, 0.0)). r;
}
void filterTextSample9Tap(out vec4 outAlphaLeft,
out float outAlphaCenter,
out vec4 outAlphaRight,
sampler2D colorTexture,
vec2 colorTexCoord,
vec4 kernel,
float onePixel){
bool wide = kernel . x > 0.0;
outAlphaLeft =
vec4(wide ? filterTextSample1Tap(- 4.0 * onePixel, colorTexture, colorTexCoord): 0.0,
filterTextSample1Tap(- 3.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(- 2.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(- 1.0 * onePixel, colorTexture, colorTexCoord));
outAlphaCenter = filterTextSample1Tap(0.0, colorTexture, colorTexCoord);
outAlphaRight =
vec4(filterTextSample1Tap(1.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(2.0 * onePixel, colorTexture, colorTexCoord),
filterTextSample1Tap(3.0 * onePixel, colorTexture, colorTexCoord),
wide ? filterTextSample1Tap(4.0 * onePixel, colorTexture, colorTexCoord): 0.0);
}
float filterTextConvolve7Tap(vec4 alpha0, vec3 alpha1, vec4 kernel){
return dot(alpha0, kernel)+ dot(alpha1, kernel . zyx);
}
float filterTextGammaCorrectChannel(float bgColor, float fgColor, sampler2D gammaLUT){
return texture(gammaLUT, vec2(fgColor, 1.0 - bgColor)). r;
}
vec3 filterTextGammaCorrect(vec3 bgColor, vec3 fgColor, sampler2D gammaLUT){
return vec3(filterTextGammaCorrectChannel(bgColor . r, fgColor . r, gammaLUT),
filterTextGammaCorrectChannel(bgColor . g, fgColor . g, gammaLUT),
filterTextGammaCorrectChannel(bgColor . b, fgColor . b, gammaLUT));
}
vec4 filterText(vec2 colorTexCoord,
sampler2D colorTexture,
sampler2D gammaLUT,
vec2 colorTextureSize,
vec4 filterParams0,
vec4 filterParams1,
vec4 filterParams2){
vec4 kernel = filterParams0;
vec3 bgColor = filterParams1 . rgb;
vec3 fgColor = filterParams2 . rgb;
bool gammaCorrectionEnabled = filterParams2 . a != 0.0;
vec3 alpha;
if(kernel . w == 0.0){
alpha = texture(colorTexture, colorTexCoord). rrr;
} else {
vec4 alphaLeft, alphaRight;
float alphaCenter;
filterTextSample9Tap(alphaLeft,
alphaCenter,
alphaRight,
colorTexture,
colorTexCoord,
kernel,
1.0 / colorTextureSize . x);
float r = filterTextConvolve7Tap(alphaLeft, vec3(alphaCenter, alphaRight . xy), kernel);
float g = filterTextConvolve7Tap(vec4(alphaLeft . yzw, alphaCenter), alphaRight . xyz, kernel);
float b = filterTextConvolve7Tap(vec4(alphaLeft . zw, alphaCenter, alphaRight . x),
alphaRight . yzw,
kernel);
alpha = vec3(r, g, b);
}
if(gammaCorrectionEnabled)
alpha = filterTextGammaCorrect(bgColor, alpha, gammaLUT);
return vec4(mix(bgColor, fgColor, alpha), 1.0);
}
vec4 filterRadialGradient(vec2 colorTexCoord,
sampler2D colorTexture,
vec2 colorTextureSize,
vec2 fragCoord,
vec2 framebufferSize,
vec4 filterParams0,
vec4 filterParams1){
vec2 lineFrom = filterParams0 . xy, lineVector = filterParams0 . zw;
vec2 radii = filterParams1 . xy, uvOrigin = filterParams1 . zw;
vec2 dP = colorTexCoord - lineFrom, dC = lineVector;
float dR = radii . y - radii . x;
float a = dot(dC, dC)- dR * dR;
float b = dot(dP, dC)+ radii . x * dR;
float c = dot(dP, dP)- radii . x * radii . x;
float discrim = b * b - a * c;
vec4 color = vec4(0.0);
if(abs(discrim)>= 0.00001){
vec2 ts = vec2(sqrt(discrim)* vec2(1.0, - 1.0)+ vec2(b))/ vec2(a);
if(ts . x > ts . y)
ts = ts . yx;
float t = ts . x >= 0.0 ? ts . x : ts . y;
color = texture(colorTexture, uvOrigin + vec2(clamp(t, 0.0, 1.0), 0.0));
}
return color;
}
vec4 filterBlur(vec2 colorTexCoord,
sampler2D colorTexture,
vec2 colorTextureSize,
vec4 filterParams0,
vec4 filterParams1){
vec2 srcOffsetScale = filterParams0 . xy / colorTextureSize;
int support = int(filterParams0 . z);
vec3 gaussCoeff = filterParams1 . xyz;
float gaussSum = gaussCoeff . x;
vec4 color = texture(colorTexture, colorTexCoord)* gaussCoeff . x;
gaussCoeff . xy *= gaussCoeff . yz;
for(int i = 1;i <= support;i += 2){
float gaussPartialSum = gaussCoeff . x;
gaussCoeff . xy *= gaussCoeff . yz;
gaussPartialSum += gaussCoeff . x;
vec2 srcOffset = srcOffsetScale *(float(i)+ gaussCoeff . x / gaussPartialSum);
color +=(texture(colorTexture, colorTexCoord - srcOffset)+
texture(colorTexture, colorTexCoord + srcOffset))* gaussPartialSum;
gaussSum += 2.0 * gaussPartialSum;
gaussCoeff . xy *= gaussCoeff . yz;
}
return color / gaussSum;
}
vec4 filterNone(vec2 colorTexCoord, sampler2D colorTexture){
return sampleColor(colorTexture, colorTexCoord);
}
vec4 filterColor(vec2 colorTexCoord,
sampler2D colorTexture,
sampler2D gammaLUT,
vec2 colorTextureSize,
vec2 fragCoord,
vec2 framebufferSize,
vec4 filterParams0,
vec4 filterParams1,
vec4 filterParams2,
int colorFilter){
switch(colorFilter){
case 0x1 :
return filterRadialGradient(colorTexCoord,
colorTexture,
colorTextureSize,
fragCoord,
framebufferSize,
filterParams0,
filterParams1);
case 0x3 :
return filterBlur(colorTexCoord,
colorTexture,
colorTextureSize,
filterParams0,
filterParams1);
case 0x2 :
return filterText(colorTexCoord,
colorTexture,
gammaLUT,
colorTextureSize,
filterParams0,
filterParams1,
filterParams2);
}
return filterNone(colorTexCoord, colorTexture);
}
vec3 compositeSelect(bvec3 cond, vec3 ifTrue, vec3 ifFalse){
return vec3(cond . x ? ifTrue . x : ifFalse . x,
cond . y ? ifTrue . y : ifFalse . y,
cond . z ? ifTrue . z : ifFalse . z);
}
float compositeDivide(float num, float denom){
return denom != 0.0 ? num / denom : 0.0;
}
vec3 compositeColorDodge(vec3 destColor, vec3 srcColor){
bvec3 destZero = equal(destColor, vec3(0.0)), srcOne = equal(srcColor, vec3(1.0));
return compositeSelect(destZero,
vec3(0.0),
compositeSelect(srcOne, vec3(1.0), destColor /(vec3(1.0)- srcColor)));
}
vec3 compositeHSLToRGB(vec3 hsl){
float a = hsl . y * min(hsl . z, 1.0 - hsl . z);
vec3 ks = mod(vec3(0.0, 8.0, 4.0)+ vec3(hsl . x * 1.9098593171027443), 12.0);
return hsl . zzz - clamp(min(ks - vec3(3.0), vec3(9.0)- ks), - 1.0, 1.0)* a;
}
vec3 compositeRGBToHSL(vec3 rgb){
float v = max(max(rgb . r, rgb . g), rgb . b), xMin = min(min(rgb . r, rgb . g), rgb . b);
float c = v - xMin, l = mix(xMin, v, 0.5);
vec3 terms = rgb . r == v ? vec3(0.0, rgb . gb):
rgb . g == v ? vec3(2.0, rgb . br):
vec3(4.0, rgb . rg);
float h = 1.0471975511965976 * compositeDivide(terms . x * c + terms . y - terms . z, c);
float s = compositeDivide(c, v);
return vec3(h, s, l);
}
vec3 compositeScreen(vec3 destColor, vec3 srcColor){
return destColor + srcColor - destColor * srcColor;
}
vec3 compositeHardLight(vec3 destColor, vec3 srcColor){
return compositeSelect(lessThanEqual(srcColor, vec3(0.5)),
destColor * vec3(2.0)* srcColor,
compositeScreen(destColor, vec3(2.0)* srcColor - vec3(1.0)));
}
vec3 compositeSoftLight(vec3 destColor, vec3 srcColor){
vec3 darkenedDestColor =
compositeSelect(lessThanEqual(destColor, vec3(0.25)),
((vec3(16.0)* destColor - 12.0)* destColor + 4.0)* destColor,
sqrt(destColor));
vec3 factor = compositeSelect(lessThanEqual(srcColor, vec3(0.5)),
destColor *(vec3(1.0)- destColor),
darkenedDestColor - destColor);
return destColor +(srcColor * 2.0 - 1.0)* factor;
}
vec3 compositeHSL(vec3 destColor, vec3 srcColor, int op){
switch(op){
case 0xc :
return vec3(srcColor . x, destColor . y, destColor . z);
case 0xd :
return vec3(destColor . x, srcColor . y, destColor . z);
case 0xe :
return vec3(srcColor . x, srcColor . y, destColor . z);
default :
return vec3(destColor . x, destColor . y, srcColor . z);
}
}
vec3 compositeRGB(vec3 destColor, vec3 srcColor, int op){
switch(op){
case 0x1 :
return destColor * srcColor;
case 0x2 :
return compositeScreen(destColor, srcColor);
case 0x3 :
return compositeHardLight(srcColor, destColor);
case 0x4 :
return min(destColor, srcColor);
case 0x5 :
return max(destColor, srcColor);
case 0x6 :
return compositeColorDodge(destColor, srcColor);
case 0x7 :
return vec3(1.0)- compositeColorDodge(vec3(1.0)- destColor, vec3(1.0)- srcColor);
case 0x8 :
return compositeHardLight(destColor, srcColor);
case 0x9 :
return compositeSoftLight(destColor, srcColor);
case 0xa :
return abs(destColor - srcColor);
case 0xb :
return destColor + srcColor - vec3(2.0)* destColor * srcColor;
case 0xc :
case 0xd :
case 0xe :
case 0xf :
return compositeHSLToRGB(compositeHSL(compositeRGBToHSL(destColor),
compositeRGBToHSL(srcColor),
op));
}
return srcColor;
}
vec4 composite(vec4 srcColor,
sampler2D destTexture,
vec2 destTextureSize,
vec2 fragCoord,
int op){
if(op == 0x0)
return srcColor;
vec2 destTexCoord = fragCoord / destTextureSize;
vec4 destColor = texture(destTexture, destTexCoord);
vec3 blendedRGB = compositeRGB(destColor . rgb, srcColor . rgb, op);
return vec4(srcColor . a *(1.0 - destColor . a)* srcColor . rgb +
srcColor . a * destColor . a * blendedRGB +
(1.0 - srcColor . a)* destColor . rgb,
1.0);
}
float sampleMask(float maskAlpha,
sampler2D maskTexture,
vec2 maskTextureSize,
vec3 maskTexCoord,
int maskCtrl){
if(maskCtrl == 0)
return maskAlpha;
ivec2 maskTexCoordI = ivec2(floor(maskTexCoord . xy));
vec4 texel = texture(maskTexture,(vec2(maskTexCoordI / ivec2(1, 4))+ 0.5)/ maskTextureSize);
float coverage = texel[maskTexCoordI . y % 4]+ maskTexCoord . z;
if((maskCtrl & 0x1)!= 0)
coverage = abs(coverage);
else
coverage = 1.0 - abs(1.0 - mod(coverage, 2.0));
return min(maskAlpha, coverage);
}
vec4 calculateColorWithMaskAlpha(float maskAlpha,
vec4 baseColor,
vec2 colorTexCoord0,
vec2 fragCoord,
int ctrl){
vec4 color = baseColor;
int color0Combine =(ctrl >> 6)&
0x3;
if(color0Combine != 0){
int color0Filter =(ctrl >> 4)& 0x3;
vec4 color0 = filterColor(colorTexCoord0,
uColorTexture0,
uGammaLUT,
uColorTextureSize0,
fragCoord,
uFramebufferSize,
uFilterParams0,
uFilterParams1,
uFilterParams2,
color0Filter);
color = combineColor0(color, color0, color0Combine);
}
color . a *= maskAlpha;
color . rgb *= color . a;
return color;
}
vec4 calculateColor(int tileCtrl, int ctrl){
float maskAlpha = 1.0;
int maskCtrl0 =(ctrl >> 0)& 0x1;
int maskTileCtrl0 =(tileCtrl >> 0)& 0x3;
uint maskTileIndex0 = vMaskTileIndex0;
if(maskCtrl0 != 0 && maskTileCtrl0 != 0){
ivec2 tileSubCoord = ivec2(floor(vTileSubCoord));
vec4 alphas = calculateFillAlpha(tileSubCoord, maskTileIndex0)+ float(vMaskTileBackdrop0);
maskAlpha = alphas . x;
}
return calculateColorWithMaskAlpha(maskAlpha,
vBaseColor,
vColorTexCoord0,
gl_FragCoord . xy,
ctrl);
}
void main(){
oFragColor = calculateColor(int(vTileCtrl), uCtrl);
}

View File

@ -0,0 +1,58 @@
#version {{version}}
// Automatically generated from files in pathfinder/shaders/. Do not edit!
precision highp float;
precision highp sampler2D;
uniform mat4 uTransform;
uniform vec2 uTileSize;
uniform sampler2D uTextureMetadata;
uniform ivec2 uTextureMetadataSize;
in ivec2 aTileOffset;
in ivec2 aTileOrigin;
in uint aMaskTileIndex0;
in ivec2 aMaskBackdrop;
in int aColor;
in int aTileCtrl;
out vec2 vTileSubCoord;
flat out uint vMaskTileIndex0;
flat out int vMaskTileBackdrop0;
out vec2 vColorTexCoord0;
out vec4 vBaseColor;
out float vTileCtrl;
void main(){
vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset);
vec2 position =(tileOrigin + tileOffset)* uTileSize;
vec2 textureMetadataScale = vec2(1.0)/ vec2(uTextureMetadataSize);
vec2 metadataEntryCoord = vec2(aColor % 128 * 4, aColor / 128);
vec2 colorTexMatrix0Coord =(metadataEntryCoord + vec2(0.5, 0.5))* textureMetadataScale;
vec2 colorTexOffsetsCoord =(metadataEntryCoord + vec2(1.5, 0.5))* textureMetadataScale;
vec2 baseColorCoord =(metadataEntryCoord + vec2(2.5, 0.5))* textureMetadataScale;
vec4 colorTexMatrix0 = texture(uTextureMetadata, colorTexMatrix0Coord);
vec4 colorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord);
vec4 baseColor = texture(uTextureMetadata, baseColorCoord);
vTileSubCoord = tileOffset * vec2(16.0);
vColorTexCoord0 = mat2(colorTexMatrix0)* position + colorTexOffsets . xy;
vMaskTileIndex0 = aMaskTileIndex0;
vMaskTileBackdrop0 = aMaskBackdrop . x;
vBaseColor = baseColor;
vTileCtrl = float(aTileCtrl);
gl_Position = uTransform * vec4(position, 0.0, 1.0);
}

View File

@ -0,0 +1,18 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 oFragColor [[color(0)]];
};
fragment main0_out main0(constant float4& uColor [[buffer(0)]])
{
main0_out out = {};
out.oFragColor = float4(uColor.xyz, 1.0) * uColor.w;
return out;
}

View File

@ -0,0 +1,24 @@
// Automatically generated from files in pathfinder/shaders/. Do not edit!
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
};
struct main0_in
{
int2 aPosition [[attribute(0)]];
};
vertex main0_out main0(main0_in in [[stage_in]], constant float4& uRect [[buffer(0)]], constant float2& uFramebufferSize [[buffer(1)]])
{
main0_out out = {};
float2 position = ((mix(uRect.xy, uRect.zw, float2(in.aPosition)) / uFramebufferSize) * 2.0) - float2(1.0);
out.gl_Position = float4(position.x, -position.y, 0.0, 1.0);
return out;
}

View File

@ -6,6 +6,8 @@
using namespace metal; using namespace metal;
constant float3 _1042 = {};
struct main0_out struct main0_out
{ {
float4 oFragColor [[color(0)]]; float4 oFragColor [[color(0)]];

View File

@ -5,6 +5,8 @@ EMPTY=
SHADERS=\ SHADERS=\
blit.fs.glsl \ blit.fs.glsl \
blit.vs.glsl \ blit.vs.glsl \
clear.fs.glsl \
clear.vs.glsl \
debug_solid.fs.glsl \ debug_solid.fs.glsl \
debug_solid.vs.glsl \ debug_solid.vs.glsl \
debug_texture.fs.glsl \ debug_texture.fs.glsl \

22
shaders/clear.fs.glsl Normal file
View File

@ -0,0 +1,22 @@
#version 330
// pathfinder/shaders/clear.fs.glsl
//
// Copyright © 2019 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.
precision highp float;
precision highp sampler2D;
uniform vec4 uColor;
out vec4 oFragColor;
void main() {
oFragColor = vec4(uColor.rgb, 1.0) * uColor.a;
}

24
shaders/clear.vs.glsl Normal file
View File

@ -0,0 +1,24 @@
#version 330
// pathfinder/shaders/clear.vs.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.
precision highp float;
precision highp sampler2D;
uniform vec4 uRect;
uniform vec2 uFramebufferSize;
in ivec2 aPosition;
void main() {
vec2 position = mix(uRect.xy, uRect.zw, vec2(aPosition)) / uFramebufferSize * 2.0 - 1.0;
gl_Position = vec4(position.x, -position.y, 0.0, 1.0);
}