Switch back to instanced drawing for tiles.

Improves tile build time by something around 2x in the NanoVG demo.
This commit is contained in:
Patrick Walton 2020-04-06 11:08:57 -07:00
parent 941abd202e
commit 895f73096e
32 changed files with 430 additions and 418 deletions

14
Cargo.lock generated
View File

@ -289,6 +289,7 @@ dependencies = [
"font-kit 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gl 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_canvas 0.1.0",
"pathfinder_color 0.1.0",
"pathfinder_content 0.1.0",
@ -1009,7 +1010,7 @@ dependencies = [
[[package]]
name = "half"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -1701,7 +1702,7 @@ name = "pathfinder_gl"
version = "0.1.0"
dependencies = [
"gl 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_geometry 0.4.0",
"pathfinder_gpu 0.1.0",
@ -1714,7 +1715,7 @@ name = "pathfinder_gpu"
version = "0.1.0"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"image 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_color 0.1.0",
"pathfinder_geometry 0.4.0",
@ -1764,7 +1765,7 @@ dependencies = [
"cocoa 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"metal 0.17.1 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"pathfinder_geometry 0.4.0",
@ -1779,6 +1780,7 @@ version = "0.1.0"
dependencies = [
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hashbrown 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"instant 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2385,7 +2387,7 @@ name = "swf-parser"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lzma-rs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"memchr 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2944,7 +2946,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum glutin_glx_sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "08c243de74d6cf5ea100c788826d2fb9319de315485dd4b310811a663b3809c3"
"checksum glutin_wgl_sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a93dba7ee3a0feeac0f437141ff25e71ce2066bcf1a706acab1559ffff94eb6a"
"checksum goblin 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3081214398d39e4bd7f2c1975f0488ed04614ffdd976c6fc7a0708278552c0da"
"checksum half 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9ff54597ea139063f4225f1ec47011b03c9de4a486957ff3fc506881dac951d0"
"checksum half 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f36b5f248235f45773d4944f555f83ea61fe07b18b561ccf99d7483d7381e54d"
"checksum harfbuzz 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46f7426266a5ece3e49eae6f48e602c0f8c39917354a847eac9c06437dcde8da"
"checksum harfbuzz-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "212d74cab8498b2d15700b694fb38f77562869d05e1f8b602dd05221a1ca2d63"
"checksum harfbuzz_rs 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cab35982090055087fad29795c465b33e8cf201bda50bfa008311ffe88630f16"

View File

@ -308,7 +308,6 @@ impl CanvasRenderingContext2D {
let transform = self.current_state.transform;
let clip_path = self.current_state.clip_path;
let blend_mode = self.current_state.global_composite_operation.to_blend_mode();
let opacity = (self.current_state.global_alpha * 255.0) as u8;
outline.transform(&transform);
@ -334,7 +333,6 @@ impl CanvasRenderingContext2D {
}
path.set_fill_rule(fill_rule);
path.set_blend_mode(blend_mode);
path.set_opacity(opacity);
self.canvas.scene.push_path(path);
self.composite_shadow_blur_render_targets_if_needed(shadow_blur_info, clip_path);
@ -344,7 +342,6 @@ impl CanvasRenderingContext2D {
path.set_clip_path(clip_path);
path.set_fill_rule(fill_rule);
path.set_blend_mode(blend_mode);
path.set_opacity(opacity);
self.canvas.scene.push_path(path);
}
@ -587,7 +584,7 @@ impl State {
}
fn resolve_paint<'a>(&self, paint: &'a Paint) -> Cow<'a, Paint> {
let mut must_copy = !self.transform.is_identity();
let mut must_copy = !self.transform.is_identity() || self.global_alpha < 1.0;
if !must_copy {
if let Paint::Pattern(ref pattern) = *paint {
must_copy = self.image_smoothing_enabled != pattern.smoothing_enabled()
@ -600,6 +597,7 @@ impl State {
let mut paint = (*paint).clone();
paint.apply_transform(&self.transform);
paint.apply_opacity(self.global_alpha);
if let Paint::Pattern(ref mut pattern) = paint {
pattern.set_smoothing_enabled(self.image_smoothing_enabled);
}

View File

@ -45,7 +45,6 @@ impl CanvasRenderingContext2D {
let clip_path = self.current_state.clip_path;
let blend_mode = self.current_state.global_composite_operation.to_blend_mode();
let opacity = (self.current_state.global_alpha * 255.0) as u8;
drop(self.canvas.scene.push_layout(&layout,
&TextStyle { size: self.current_state.font_size },
@ -54,7 +53,6 @@ impl CanvasRenderingContext2D {
HintingOptions::None,
clip_path,
blend_mode,
opacity,
paint_id));
}
@ -67,7 +65,6 @@ impl CanvasRenderingContext2D {
let clip_path = self.current_state.clip_path;
let blend_mode = self.current_state.global_composite_operation.to_blend_mode();
let opacity = (self.current_state.global_alpha * 255.0) as u8;
match self.current_state.text_align {
TextAlign::Left => {},
@ -96,7 +93,6 @@ impl CanvasRenderingContext2D {
HintingOptions::None,
clip_path,
blend_mode,
opacity,
paint_id));
}

View File

@ -120,6 +120,11 @@ impl Gradient {
&self.stops.array
}
#[inline]
pub fn stops_mut(&mut self) -> &mut [ColorStop] {
&mut self.stops.array
}
pub fn sample(&self, mut t: f32) -> ColorU {
if self.stops.is_empty() {
return ColorU::transparent_black();

View File

@ -31,6 +31,7 @@ pub struct Pattern {
transform: Transform2F,
filter: Option<PatternFilter>,
flags: PatternFlags,
opacity: u8,
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
@ -69,6 +70,7 @@ impl Pattern {
transform: Transform2F::default(),
filter: None,
flags: PatternFlags::empty(),
opacity: !0,
}
}
@ -140,6 +142,16 @@ impl Pattern {
self.flags.set(PatternFlags::NO_SMOOTHING, !enable);
}
#[inline]
pub fn opacity(&self) -> u8 {
self.opacity
}
#[inline]
pub fn set_opacity(&mut self, opacity: u8) {
self.opacity = opacity
}
#[inline]
pub fn is_opaque(&self) -> bool {
self.source.is_opaque()

View File

@ -43,3 +43,6 @@ path = "../../resources"
[dependencies.pathfinder_simd]
path = "../../simd"
[target.'cfg(not(windows))'.dependencies]
jemallocator = "0.3"

View File

@ -42,13 +42,20 @@ use std::f32::consts::PI;
use std::sync::Arc;
use std::time::Instant;
#[cfg(not(windows))]
use jemallocator;
#[cfg(not(windows))]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
// TODO(pcwalton): See if we can reduce the amount of code by using the canvas shadow feature.
const PI_2: f32 = PI * 2.0;
const FRAC_PI_2_3: f32 = PI * 2.0 / 3.0;
const WINDOW_WIDTH: i32 = 1024;
const WINDOW_HEIGHT: i32 = 768;
const WINDOW_HEIGHT: i32 = WINDOW_WIDTH * 3 / 4;
static FONT_NAME_REGULAR: &'static str = "Roboto-Regular";
static FONT_NAME_BOLD: &'static str = "Roboto-Bold";

View File

@ -228,6 +228,14 @@ impl Transform2F {
pub fn m22(&self) -> f32 {
self.matrix.m22()
}
#[inline]
pub fn m31(&self) -> f32 {
self.vector.x()
}
#[inline]
pub fn m32(&self) -> f32 {
self.vector.y()
}
#[inline]
pub fn translate(&self, vector: Vector2F) -> Transform2F {

View File

@ -9,7 +9,7 @@ crate-type = ["rlib", "staticlib"]
[dependencies]
gl = "0.14"
half = "1.4"
half = "1.5"
[dependencies.log]
version = "0.4"

View File

@ -132,6 +132,9 @@ impl GLDevice {
UniformData::Float(value) => {
gl::Uniform1f(uniform.location, value); ck();
}
UniformData::IVec2(value) => {
gl::Uniform2i(uniform.location, value[0], value[1]); ck();
}
UniformData::IVec3(value) => {
gl::Uniform3i(uniform.location, value[0], value[1], value[2]); ck();
}

View File

@ -6,7 +6,7 @@ edition = "2018"
[dependencies]
bitflags = "1.0"
half = "1.4"
half = "1.5"
[dependencies.image]
version = "0.23"

View File

@ -20,7 +20,7 @@ use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::transform3d::Transform4F;
use pathfinder_geometry::vector::{Vector2I, vec2i};
use pathfinder_resources::ResourceLoader;
use pathfinder_simd::default::{F32x2, F32x4};
use pathfinder_simd::default::{F32x2, F32x4, I32x2};
use std::os::raw::c_void;
use std::time::Duration;
@ -166,6 +166,7 @@ pub enum ShaderKind {
#[derive(Clone, Copy)]
pub enum UniformData {
Float(f32),
IVec2(I32x2),
IVec3([i32; 3]),
Int(i32),
Mat2(F32x4),

View File

@ -11,7 +11,7 @@ block = "0.1"
cocoa = "0.19"
core-foundation = "0.7"
foreign-types = "0.3"
half = "1.4"
half = "1.5"
metal = "0.17"
objc = "0.2"

View File

@ -48,7 +48,7 @@ use pathfinder_gpu::{Device, Primitive, RenderState, RenderTarget, ShaderKind, S
use pathfinder_gpu::{TextureData, TextureDataRef, TextureFormat, TextureSamplingFlags};
use pathfinder_gpu::{UniformData, VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
use pathfinder_resources::ResourceLoader;
use pathfinder_simd::default::{F32x2, F32x4};
use pathfinder_simd::default::{F32x2, F32x4, I32x2};
use std::cell::{Cell, RefCell};
use std::mem;
use std::ptr;
@ -621,19 +621,23 @@ impl Device for MetalDevice {
}
fn begin_timer_query(&self, query: &MetalTimerQuery) {
/*
self.command_buffers
.borrow_mut()
.last()
.unwrap()
.encode_signal_event(&self.shared_event, query.0.event_value);
*/
}
fn end_timer_query(&self, query: &MetalTimerQuery) {
/*
self.command_buffers
.borrow_mut()
.last()
.unwrap()
.encode_signal_event(&self.shared_event, query.0.event_value + 1);
*/
}
fn try_recv_timer_query(&self, query: &MetalTimerQuery) -> Option<Duration> {
@ -908,6 +912,10 @@ impl MetalDevice {
UniformData::Float(value) => {
uniform_buffer_data.write_f32::<NativeEndian>(value).unwrap()
}
UniformData::IVec2(vector) => {
uniform_buffer_data.write_i32::<NativeEndian>(vector.x()).unwrap();
uniform_buffer_data.write_i32::<NativeEndian>(vector.y()).unwrap();
}
UniformData::IVec3(values) => {
uniform_buffer_data.write_i32::<NativeEndian>(values[0]).unwrap();
uniform_buffer_data.write_i32::<NativeEndian>(values[1]).unwrap();
@ -1297,6 +1305,9 @@ impl UniformDataExt for UniformData {
UniformData::Float(ref data) => {
Some(slice::from_raw_parts(data as *const f32 as *const u8, 4 * 1))
}
UniformData::IVec2(ref data) => {
Some(slice::from_raw_parts(data as *const I32x2 as *const u8, 4 * 3))
}
UniformData::IVec3(ref data) => {
Some(slice::from_raw_parts(data as *const i32 as *const u8, 4 * 3))
}
@ -1337,6 +1348,8 @@ impl TextureFormatExt for TextureFormat {
// FIXME(pcwalton): This is wrong! But it prevents a crash for now.
Some(TextureFormat::RGBA8)
}
MTLPixelFormat::RGBA16Float => Some(TextureFormat::RGBA16F),
MTLPixelFormat::RGBA32Float => Some(TextureFormat::RGBA32F),
_ => None,
}
}

View File

@ -7,6 +7,7 @@ authors = ["Patrick Walton <pcwalton@mimiga.net>"]
[dependencies]
bitflags = "1.0"
byteorder = "1.2"
half = "1.5"
hashbrown = "0.7"
rayon = "1.0"
serde = "1.0"

View File

@ -13,7 +13,7 @@
use crate::concurrent::executor::Executor;
use crate::gpu::renderer::{BlendModeExt, MASK_TILES_ACROSS, MASK_TILES_DOWN};
use crate::gpu_data::{FillBatchPrimitive, RenderCommand, TexturePageId, Tile, TileBatch};
use crate::gpu_data::{TileBatchTexture, TileObjectPrimitive, TileVertex};
use crate::gpu_data::{TileBatchTexture, TileObjectPrimitive};
use crate::options::{PreparedBuildOptions, PreparedRenderTransform, RenderCommandListener};
use crate::paint::{PaintInfo, PaintMetadata};
use crate::scene::{DisplayItem, Scene};
@ -125,8 +125,8 @@ impl<'a> SceneBuilder<'a> {
render_commands,
paint_metadata,
opacity_tile_page,
opacity_tile_transform,
render_target_metadata: _
opacity_tile_transform: _,
render_target_metadata: _,
} = self.scene.build_paint_info(render_transform);
for render_command in render_commands {
self.listener.send(render_command);
@ -153,7 +153,6 @@ impl<'a> SceneBuilder<'a> {
},
paint_metadata: &paint_metadata,
opacity_tile_page,
opacity_tile_transform,
built_clip_paths: &built_clip_paths,
})
});
@ -186,7 +185,6 @@ impl<'a> SceneBuilder<'a> {
path_build_params: PathBuildParams { path_index, view_box, built_options, scene },
paint_metadata,
opacity_tile_page,
opacity_tile_transform,
built_clip_paths,
} = params;
@ -204,10 +202,9 @@ impl<'a> SceneBuilder<'a> {
path_object.fill_rule(),
view_box,
TilingPathInfo::Draw(DrawTilingPathInfo {
paint_id,
paint_metadata,
opacity_tile_transform,
blend_mode: path_object.blend_mode(),
opacity: path_object.opacity(),
built_clip_path,
}));
@ -444,7 +441,7 @@ impl<'a> SceneBuilder<'a> {
};
for alpha_tile in alpha_tiles {
let alpha_tile_coords = alpha_tile.upper_left.tile_position();
let alpha_tile_coords = alpha_tile.tile_position();
if layer_z_buffer.test(alpha_tile_coords, current_depth) {
culled_alpha_tiles.push(*alpha_tile);
}
@ -452,6 +449,7 @@ impl<'a> SceneBuilder<'a> {
}
fn pack_tiles(&mut self, culled_tiles: CulledTiles) {
self.listener.send(RenderCommand::BeginTileDrawing);
for display_item in culled_tiles.display_list {
match display_item {
CulledDisplayItem::DrawTiles(batch) => {
@ -509,7 +507,6 @@ struct DrawPathBuildParams<'a> {
path_build_params: PathBuildParams<'a>,
paint_metadata: &'a [PaintMetadata],
opacity_tile_page: TexturePageId,
opacity_tile_transform: Transform2F,
built_clip_paths: &'a [BuiltPath],
}
@ -522,8 +519,7 @@ impl BuiltPath {
let occludes = match *tiling_path_info {
TilingPathInfo::Draw(ref draw_tiling_path_info) => {
draw_tiling_path_info.paint_metadata.is_opaque &&
draw_tiling_path_info.blend_mode.occludes_backdrop() &&
draw_tiling_path_info.opacity == !0
draw_tiling_path_info.blend_mode.occludes_backdrop()
}
TilingPathInfo::Clip => true,
};
@ -769,74 +765,42 @@ impl<'a> PackedTile<'a> {
tiles: &mut Vec<Tile>,
draw_tiling_path_info: &DrawTilingPathInfo) {
let fill_tile_index = self.draw_tile.alpha_tile_index as u16;
let fill_tile_backdrop = self.draw_tile.backdrop as i16;
let fill_tile_backdrop = self.draw_tile.backdrop as i8;
let (clip_tile_index, clip_tile_backdrop) = match self.clip_tile {
None => (0, 0),
Some(clip_tile) => (clip_tile.alpha_tile_index as u16, clip_tile.backdrop as i16),
Some(clip_tile) => (clip_tile.alpha_tile_index as u16, clip_tile.backdrop as i8),
};
tiles.push(Tile {
upper_left: TileVertex::new_alpha(self.tile_coords,
tiles.push(Tile::new_alpha(self.tile_coords,
fill_tile_index,
fill_tile_backdrop,
clip_tile_index,
clip_tile_backdrop,
Vector2I::zero(),
draw_tiling_path_info),
upper_right: TileVertex::new_alpha(self.tile_coords,
fill_tile_index,
fill_tile_backdrop,
clip_tile_index,
clip_tile_backdrop,
vec2i(1, 0),
draw_tiling_path_info),
lower_left: TileVertex::new_alpha(self.tile_coords,
fill_tile_index,
fill_tile_backdrop,
clip_tile_index,
clip_tile_backdrop,
vec2i(0, 1),
draw_tiling_path_info),
lower_right: TileVertex::new_alpha(self.tile_coords,
fill_tile_index,
fill_tile_backdrop,
clip_tile_index,
clip_tile_backdrop,
vec2i(1, 1),
draw_tiling_path_info),
});
draw_tiling_path_info));
}
}
impl TileVertex {
impl Tile {
#[inline]
fn new_alpha(tile_origin: Vector2I,
draw_tile_index: u16,
draw_tile_backdrop: i16,
draw_tile_backdrop: i8,
clip_tile_index: u16,
clip_tile_backdrop: i16,
tile_offset: Vector2I,
clip_tile_backdrop: i8,
draw_tiling_path_info: &DrawTilingPathInfo)
-> TileVertex {
// TODO(pcwalton): Opacity.
let tile_position = tile_origin + tile_offset;
let color_0_uv = draw_tiling_path_info.paint_metadata.calculate_tex_coords(tile_position);
let color_1_uv = calculate_opacity_uv(draw_tiling_path_info);
let mask_0_uv = calculate_mask_uv(draw_tile_index, tile_offset);
let mask_1_uv = calculate_mask_uv(clip_tile_index, tile_offset);
TileVertex {
tile_x: tile_position.x() as i16,
tile_y: tile_position.y() as i16,
color_0_u: color_0_uv.x(),
color_0_v: color_0_uv.y(),
color_1_u: color_1_uv.x(),
color_1_v: color_1_uv.y(),
mask_0_u: mask_0_uv.x(),
mask_0_v: mask_0_uv.y(),
mask_1_u: mask_1_uv.x(),
mask_1_v: mask_1_uv.y(),
-> Tile {
let mask_0_uv = calculate_mask_uv(draw_tile_index);
let mask_1_uv = calculate_mask_uv(clip_tile_index);
Tile {
tile_x: tile_origin.x() as i16,
tile_y: tile_origin.y() as i16,
mask_0_u: mask_0_uv.x() as u8,
mask_0_v: mask_0_uv.y() as u8,
mask_1_u: mask_1_uv.x() as u8,
mask_1_v: mask_1_uv.y() as u8,
mask_0_backdrop: draw_tile_backdrop,
mask_1_backdrop: clip_tile_backdrop,
color: draw_tiling_path_info.paint_id.0,
}
}
@ -846,16 +810,9 @@ impl TileVertex {
}
}
fn calculate_mask_uv(tile_index: u16, tile_offset: Vector2I) -> Vector2F {
fn calculate_mask_uv(tile_index: u16) -> Vector2I {
debug_assert_eq!(MASK_TILES_ACROSS, MASK_TILES_DOWN);
let mask_u = tile_index as i32 % MASK_TILES_ACROSS as i32;
let mask_v = tile_index as i32 / MASK_TILES_ACROSS as i32;
let scale = vec2f(1.0 / MASK_TILES_ACROSS as f32, 1.0 / MASK_TILES_DOWN as f32);
(vec2i(mask_u, mask_v) + tile_offset).to_f32() * scale
}
fn calculate_opacity_uv(draw_tiling_path_info: &DrawTilingPathInfo) -> Vector2F {
let DrawTilingPathInfo { opacity_tile_transform, opacity, .. } = *draw_tiling_path_info;
let texel_coord = (vec2i((opacity % 16) as i32, (opacity / 16) as i32).to_f32() +
vec2f(0.5, 0.5)) * (1.0 / 16.0);
opacity_tile_transform * texel_coord
vec2i(mask_u, mask_v)
}

View File

@ -144,26 +144,13 @@ where
let mean_gpu_sample = self.gpu_samples.mean();
self.ui_presenter.draw_text(
device,
&format!(
"Stage 0 GPU: {:.3} ms",
duration_to_ms(mean_gpu_sample.time.stage_0)
),
&format!("GPU: {:.3} ms", duration_to_ms(mean_gpu_sample.time.time)),
origin + vec2i(0, LINE_HEIGHT * 1),
false,
);
self.ui_presenter.draw_text(
device,
&format!(
"Stage 1 GPU: {:.3} ms",
duration_to_ms(mean_gpu_sample.time.stage_1)
),
origin + vec2i(0, LINE_HEIGHT * 2),
false,
);
let wallclock_time = f64::max(duration_to_ms(mean_gpu_sample.time.stage_0),
duration_to_ms(mean_cpu_sample.elapsed)) +
duration_to_ms(mean_gpu_sample.time.stage_1);
let wallclock_time = f64::max(duration_to_ms(mean_gpu_sample.time.time),
duration_to_ms(mean_cpu_sample.elapsed));
self.ui_presenter.draw_text(
device,
&format!("Wallclock: {:.3} ms", wallclock_time),
@ -255,12 +242,7 @@ impl Add<GPUSample> for GPUSample {
impl Div<usize> for GPUSample {
type Output = GPUSample;
fn div(self, divisor: usize) -> GPUSample {
GPUSample {
time: RenderTime {
stage_0: self.time.stage_0 / (divisor as u32),
stage_1: self.time.stage_1 / (divisor as u32),
}
}
GPUSample { time: RenderTime { time: self.time.time / divisor as u32 } }
}
}

View File

@ -14,10 +14,11 @@ use crate::gpu::shaders::{BlitProgram, BlitVertexArray, CopyTileProgram, CopyTil
use crate::gpu::shaders::{FillProgram, FillVertexArray, MAX_FILLS_PER_BATCH, ReprojectionProgram};
use crate::gpu::shaders::{ReprojectionVertexArray, StencilProgram, StencilVertexArray};
use crate::gpu::shaders::{TileProgram, TileVertexArray};
use crate::gpu_data::{FillBatchPrimitive, RenderCommand, TextureLocation, TexturePageDescriptor};
use crate::gpu_data::{TexturePageId, Tile, TileBatchTexture};
use crate::gpu_data::{FillBatchPrimitive, RenderCommand, TextureLocation, TextureMetadataEntry};
use crate::gpu_data::{TexturePageDescriptor, TexturePageId, Tile, TileBatchTexture};
use crate::options::BoundingQuad;
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
use half::f16;
use pathfinder_color::{self as color, ColorF, ColorU};
use pathfinder_content::effects::{BlendMode, BlurDirection, DefringingKernel};
use pathfinder_content::effects::{Filter, PatternFilter};
@ -26,13 +27,14 @@ use pathfinder_content::render_target::RenderTargetId;
use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::transform3d::Transform4F;
use pathfinder_geometry::util;
use pathfinder_geometry::vector::{Vector2F, Vector2I, Vector4F, vec2f, vec2i};
use pathfinder_gpu::{BlendFactor, BlendState, BufferData, BufferTarget, BufferUploadMode};
use pathfinder_gpu::{ClearOps, DepthFunc, DepthState, Device, Primitive, RenderOptions};
use pathfinder_gpu::{RenderState, RenderTarget, StencilFunc, StencilState, TextureDataRef};
use pathfinder_gpu::{TextureFormat, UniformData};
use pathfinder_resources::ResourceLoader;
use pathfinder_simd::default::{F32x2, F32x4};
use pathfinder_simd::default::{F32x2, F32x4, I32x2};
use std::cmp;
use std::collections::VecDeque;
use std::f32;
@ -51,6 +53,11 @@ pub(crate) const MASK_TILES_DOWN: u32 = 256;
const SQRT_2_PI_INV: f32 = 0.3989422804014327;
const TEXTURE_CACHE_SIZE: usize = 8;
const TIMER_QUERY_CACHE_SIZE: usize = 8;
const TEXTURE_METADATA_ENTRIES_PER_ROW: i32 = 256;
const TEXTURE_METADATA_TEXTURE_WIDTH: i32 = TEXTURE_METADATA_ENTRIES_PER_ROW * 2;
const TEXTURE_METADATA_TEXTURE_HEIGHT: i32 = 65536 / TEXTURE_METADATA_ENTRIES_PER_ROW;
// FIXME(pcwalton): Shrink this again!
const MASK_FRAMEBUFFER_WIDTH: i32 = TILE_WIDTH as i32 * MASK_TILES_ACROSS as i32;
@ -106,7 +113,6 @@ where
blit_vertex_array: BlitVertexArray<D>,
tile_vertex_array: TileVertexArray<D>,
tile_copy_vertex_array: CopyTileVertexArray<D>,
area_lut_texture: D::Texture,
tile_vertex_buffer: D::Buffer,
quad_vertex_positions_buffer: D::Buffer,
quad_vertex_indices_buffer: D::Buffer,
@ -119,7 +125,8 @@ where
texture_pages: Vec<TexturePage<D>>,
render_targets: Vec<RenderTargetInfo>,
render_target_stack: Vec<RenderTargetId>,
texture_metadata_texture: D::Texture,
area_lut_texture: D::Texture,
gamma_lut_texture: D::Texture,
// Stencil shader
@ -137,8 +144,8 @@ where
// Debug
pub stats: RenderStats,
current_timers: RenderTimers<D>,
pending_timers: VecDeque<RenderTimers<D>>,
current_timer: Option<D::TimerQuery>,
pending_timers: VecDeque<D::TimerQuery>,
free_timer_queries: Vec<D::TimerQuery>,
pub debug_ui_presenter: DebugUIPresenter<D>,
@ -165,6 +172,10 @@ where
let area_lut_texture = device.create_texture_from_png(resources, "area-lut");
let gamma_lut_texture = device.create_texture_from_png(resources, "gamma-lut");
let texture_metadata_texture = device.create_texture(
TextureFormat::RGBA16F,
Vector2I::new(TEXTURE_METADATA_TEXTURE_WIDTH, TEXTURE_METADATA_TEXTURE_HEIGHT));
let quad_vertex_positions_buffer = device.create_buffer();
device.allocate_buffer(
&quad_vertex_positions_buffer,
@ -198,7 +209,8 @@ where
&device,
&tile_program,
&tile_vertex_buffer,
&quads_vertex_indices_buffer,
&quad_vertex_positions_buffer,
&quad_vertex_indices_buffer,
);
let tile_copy_vertex_array = CopyTileVertexArray::new(
&device,
@ -225,6 +237,11 @@ where
let intermediate_dest_texture = device.create_texture(TextureFormat::RGBA8, window_size);
let intermediate_dest_framebuffer = device.create_framebuffer(intermediate_dest_texture);
let mut timer_queries = vec![];
for _ in 0..TIMER_QUERY_CACHE_SIZE {
timer_queries.push(device.create_timer_query());
}
let debug_ui_presenter = DebugUIPresenter::new(&device, resources, window_size);
Renderer {
@ -239,7 +256,6 @@ where
blit_vertex_array,
tile_vertex_array,
tile_copy_vertex_array,
area_lut_texture,
tile_vertex_buffer,
quad_vertex_positions_buffer,
quad_vertex_indices_buffer,
@ -253,7 +269,9 @@ where
render_targets: vec![],
render_target_stack: vec![],
area_lut_texture,
gamma_lut_texture,
texture_metadata_texture,
stencil_program,
stencil_vertex_array,
@ -262,9 +280,9 @@ where
reprojection_vertex_array,
stats: RenderStats::default(),
current_timers: RenderTimers::new(),
current_timer: None,
pending_timers: VecDeque::new(),
free_timer_queries: vec![],
free_timer_queries: timer_queries,
debug_ui_presenter,
framebuffer_flags: FramebufferFlags::empty(),
@ -295,11 +313,12 @@ where
RenderCommand::DeclareRenderTarget { id, location } => {
self.declare_render_target(id, location)
}
RenderCommand::AddFills(ref fills) => self.add_fills(fills),
RenderCommand::FlushFills => {
self.draw_buffered_fills();
self.begin_composite_timer_query();
RenderCommand::UploadTextureMetadata(ref metadata) => {
self.upload_texture_metadata(metadata)
}
RenderCommand::AddFills(ref fills) => self.add_fills(fills),
RenderCommand::FlushFills => self.draw_buffered_fills(),
RenderCommand::BeginTileDrawing => self.begin_tile_drawing(),
RenderCommand::PushRenderTarget(render_target_id) => {
self.push_render_target(render_target_id)
}
@ -320,13 +339,22 @@ where
}
}
fn begin_tile_drawing(&mut self) {
if let Some(timer_query) = self.allocate_timer_query() {
self.device.begin_timer_query(&timer_query);
self.current_timer = Some(timer_query);
}
}
pub fn end_scene(&mut self) {
self.blit_intermediate_dest_framebuffer_if_necessary();
self.end_composite_timer_query();
self.pending_timers.push_back(mem::replace(&mut self.current_timers, RenderTimers::new()));
self.device.end_commands();
if let Some(timer_query) = self.current_timer.take() {
self.device.end_timer_query(&timer_query);
self.pending_timers.push_back(timer_query);
}
}
fn start_rendering(&mut self,
@ -351,32 +379,14 @@ where
}
pub fn shift_rendering_time(&mut self) -> Option<RenderTime> {
let timers = self.pending_timers.front()?;
// Accumulate stage-0 time.
let mut total_stage_0_time = Duration::new(0, 0);
for timer_query in &timers.stage_0 {
match self.device.try_recv_timer_query(timer_query) {
None => return None,
Some(stage_0_time) => total_stage_0_time += stage_0_time,
if let Some(query) = self.pending_timers.pop_front() {
if let Some(time) = self.device.try_recv_timer_query(&query) {
self.free_timer_queries.push(query);
return Some(RenderTime { time });
}
self.pending_timers.push_front(query);
}
// Get stage-1 time.
let stage_1_time = {
let stage_1_timer_query = timers.stage_1.as_ref().unwrap();
match self.device.try_recv_timer_query(stage_1_timer_query) {
None => return None,
Some(query) => query,
}
};
// Recycle all timer queries.
let timers = self.pending_timers.pop_front().unwrap();
self.free_timer_queries.extend(timers.stage_0.into_iter());
self.free_timer_queries.push(timers.stage_1.unwrap());
Some(RenderTime { stage_0: total_stage_0_time, stage_1: stage_1_time })
None
}
#[inline]
@ -464,6 +474,34 @@ where
render_target.location = location;
}
fn upload_texture_metadata(&mut self, metadata: &[TextureMetadataEntry]) {
let padded_texel_size =
(util::alignup_i32(metadata.len() as i32, TEXTURE_METADATA_ENTRIES_PER_ROW) *
TEXTURE_METADATA_TEXTURE_WIDTH * 4) as usize;
let mut texels = Vec::with_capacity(padded_texel_size);
for entry in metadata {
texels.extend_from_slice(&[
f16::from_f32(entry.color_0_transform.m11()),
f16::from_f32(entry.color_0_transform.m21()),
f16::from_f32(entry.color_0_transform.m12()),
f16::from_f32(entry.color_0_transform.m22()),
f16::from_f32(entry.color_0_transform.m31()),
f16::from_f32(entry.color_0_transform.m32()),
f16::from_f32(entry.opacity),
f16::default(),
]);
}
while texels.len() < padded_texel_size {
texels.push(f16::default())
}
let texture = &mut self.texture_metadata_texture;
let width = TEXTURE_METADATA_TEXTURE_WIDTH;
let height = texels.len() as i32 / (4 * TEXTURE_METADATA_TEXTURE_WIDTH);
let rect = RectI::new(Vector2I::zero(), Vector2I::new(width, height));
self.device.upload_to_texture(texture, rect, TextureDataRef::F16(&texels));
}
fn upload_tiles(&mut self, tiles: &[Tile]) {
self.device.allocate_buffer(&self.tile_vertex_buffer,
BufferData::Memory(&tiles),
@ -532,9 +570,6 @@ where
clear_color = Some(ColorF::default());
};
let timer_query = self.allocate_timer_query();
self.device.begin_timer_query(&timer_query);
debug_assert!(self.buffered_fills.len() <= u32::MAX as usize);
self.device.draw_elements_instanced(6, self.buffered_fills.len() as u32, &RenderState {
target: &RenderTarget::Framebuffer(&self.fill_framebuffer),
@ -564,9 +599,6 @@ where
},
});
self.device.end_timer_query(&timer_query);
self.current_timers.stage_0.push(timer_query);
self.framebuffer_flags.insert(FramebufferFlags::MUST_PRESERVE_FILL_FRAMEBUFFER_CONTENTS);
self.buffered_fills.clear();
}
@ -607,7 +639,7 @@ where
}
}
let mut textures = vec![];
let mut textures = vec![&self.texture_metadata_texture];
let mut uniforms = vec![
(&self.tile_program.transform_uniform,
UniformData::Mat4(self.tile_transform().to_columns())),
@ -615,6 +647,10 @@ where
UniformData::Vec2(F32x2::new(TILE_WIDTH as f32, TILE_HEIGHT as f32))),
(&self.tile_program.framebuffer_size_uniform,
UniformData::Vec2(draw_viewport.size().to_f32().0)),
(&self.tile_program.texture_metadata_uniform, UniformData::TextureUnit(0)),
(&self.tile_program.texture_metadata_size_uniform,
UniformData::IVec2(I32x2::new(TEXTURE_METADATA_TEXTURE_WIDTH,
TEXTURE_METADATA_TEXTURE_HEIGHT))),
];
if needs_readable_framebuffer {
@ -687,7 +723,7 @@ where
uniforms.push((&self.tile_program.ctrl_uniform, UniformData::Int(ctrl)));
self.device.draw_elements(tile_count * 6, &RenderState {
self.device.draw_elements_instanced(6, tile_count, &RenderState {
target: &self.draw_render_target(),
program: &self.tile_program.program,
vertex_array: &self.tile_vertex_array.vertex_array,
@ -1036,23 +1072,8 @@ where
self.device.framebuffer_texture(&self.texture_page_framebuffer(id))
}
fn allocate_timer_query(&mut self) -> D::TimerQuery {
match self.free_timer_queries.pop() {
Some(query) => query,
None => self.device.create_timer_query(),
}
}
fn begin_composite_timer_query(&mut self) {
let timer_query = self.allocate_timer_query();
self.device.begin_timer_query(&timer_query);
self.current_timers.stage_1 = Some(timer_query);
}
fn end_composite_timer_query(&mut self) {
if let Some(ref query) = self.current_timers.stage_1 {
self.device.end_timer_query(query);
}
fn allocate_timer_query(&mut self) -> Option<D::TimerQuery> {
self.free_timer_queries.pop()
}
}
@ -1090,27 +1111,15 @@ impl Div<usize> for RenderStats {
}
}
struct RenderTimers<D> where D: Device {
stage_0: Vec<D::TimerQuery>,
stage_1: Option<D::TimerQuery>,
}
impl<D> RenderTimers<D> where D: Device {
fn new() -> RenderTimers<D> {
RenderTimers { stage_0: vec![], stage_1: None }
}
}
#[derive(Clone, Copy, Debug)]
pub struct RenderTime {
pub stage_0: Duration,
pub stage_1: Duration,
pub time: Duration,
}
impl Default for RenderTime {
#[inline]
fn default() -> RenderTime {
RenderTime { stage_0: Duration::new(0, 0), stage_1: Duration::new(0, 0) }
RenderTime { time: Duration::new(0, 0) }
}
}
@ -1119,10 +1128,7 @@ impl Add<RenderTime> for RenderTime {
#[inline]
fn add(self, other: RenderTime) -> RenderTime {
RenderTime {
stage_0: self.stage_0 + other.stage_0,
stage_1: self.stage_1 + other.stage_1,
}
RenderTime { time: self.time + other.time }
}
}

View File

@ -15,7 +15,7 @@ use pathfinder_resources::ResourceLoader;
// TODO(pcwalton): Replace with `mem::size_of` calls?
const FILL_INSTANCE_SIZE: usize = 8;
const TILE_VERTEX_SIZE: usize = 40;
const TILE_INSTANCE_SIZE: usize = 12;
pub const MAX_FILLS_PER_BATCH: usize = 0x4000;
@ -155,83 +155,80 @@ impl<D> TileVertexArray<D> where D: Device {
pub fn new(device: &D,
tile_program: &TileProgram<D>,
tile_vertex_buffer: &D::Buffer,
quads_vertex_indices_buffer: &D::Buffer)
quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer)
-> TileVertexArray<D> {
let vertex_array = device.create_vertex_array();
let tile_position_attr =
device.get_vertex_attr(&tile_program.program, "TilePosition").unwrap();
let color_0_tex_coord_attr =
device.get_vertex_attr(&tile_program.program, "ColorTexCoord0").unwrap();
let color_1_tex_coord_attr =
device.get_vertex_attr(&tile_program.program, "ColorTexCoord1").unwrap();
let tile_offset_attr =
device.get_vertex_attr(&tile_program.program, "TileOffset").unwrap();
let tile_origin_attr =
device.get_vertex_attr(&tile_program.program, "TileOrigin").unwrap();
let mask_0_tex_coord_attr =
device.get_vertex_attr(&tile_program.program, "MaskTexCoord0").unwrap();
let mask_1_tex_coord_attr =
device.get_vertex_attr(&tile_program.program, "MaskTexCoord1").unwrap();
let mask_backdrop_attr =
device.get_vertex_attr(&tile_program.program, "MaskBackdrop").unwrap();
let color_attr = device.get_vertex_attr(&tile_program.program, "Color").unwrap();
device.bind_buffer(&vertex_array, tile_vertex_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&vertex_array, &tile_position_attr, &VertexAttrDescriptor {
device.bind_buffer(&vertex_array, quad_vertex_positions_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&vertex_array, &tile_offset_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: TILE_VERTEX_SIZE,
stride: 4,
offset: 0,
divisor: 0,
buffer_index: 0,
});
device.configure_vertex_attr(&vertex_array,
&color_0_tex_coord_attr,
&VertexAttrDescriptor {
device.bind_buffer(&vertex_array, tile_vertex_buffer, BufferTarget::Vertex);
device.configure_vertex_attr(&vertex_array, &tile_origin_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Float,
attr_type: VertexAttrType::F32,
stride: TILE_VERTEX_SIZE,
offset: 4,
divisor: 0,
buffer_index: 0,
});
device.configure_vertex_attr(&vertex_array,
&color_1_tex_coord_attr,
&VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Float,
attr_type: VertexAttrType::F32,
stride: TILE_VERTEX_SIZE,
offset: 12,
divisor: 0,
buffer_index: 0,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: TILE_INSTANCE_SIZE,
offset: 0,
divisor: 1,
buffer_index: 1,
});
device.configure_vertex_attr(&vertex_array, &mask_0_tex_coord_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Float,
attr_type: VertexAttrType::F32,
stride: TILE_VERTEX_SIZE,
offset: 20,
divisor: 0,
buffer_index: 0,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::U8,
stride: TILE_INSTANCE_SIZE,
offset: 4,
divisor: 1,
buffer_index: 1,
});
device.configure_vertex_attr(&vertex_array, &mask_1_tex_coord_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Float,
attr_type: VertexAttrType::F32,
stride: TILE_VERTEX_SIZE,
offset: 28,
divisor: 0,
buffer_index: 0,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::U8,
stride: TILE_INSTANCE_SIZE,
offset: 6,
divisor: 1,
buffer_index: 1,
});
device.configure_vertex_attr(&vertex_array, &mask_backdrop_attr, &VertexAttrDescriptor {
size: 2,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: TILE_VERTEX_SIZE,
offset: 36,
divisor: 0,
buffer_index: 0,
attr_type: VertexAttrType::I8,
stride: TILE_INSTANCE_SIZE,
offset: 8,
divisor: 1,
buffer_index: 1,
});
device.bind_buffer(&vertex_array, quads_vertex_indices_buffer, BufferTarget::Index);
device.configure_vertex_attr(&vertex_array, &color_attr, &VertexAttrDescriptor {
size: 1,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: TILE_INSTANCE_SIZE,
offset: 10,
divisor: 1,
buffer_index: 1,
});
device.bind_buffer(&vertex_array, quad_vertex_indices_buffer, BufferTarget::Index);
TileVertexArray { vertex_array }
}
@ -258,7 +255,7 @@ impl<D> CopyTileVertexArray<D> where D: Device {
size: 2,
class: VertexAttrClass::Int,
attr_type: VertexAttrType::I16,
stride: TILE_VERTEX_SIZE,
stride: TILE_INSTANCE_SIZE,
offset: 0,
divisor: 0,
buffer_index: 0,
@ -314,6 +311,8 @@ pub struct TileProgram<D> where D: Device {
pub program: D::Program,
pub transform_uniform: D::Uniform,
pub tile_size_uniform: D::Uniform,
pub texture_metadata_uniform: D::Uniform,
pub texture_metadata_size_uniform: D::Uniform,
pub dest_texture_uniform: D::Uniform,
pub color_texture_0_uniform: D::Uniform,
pub color_texture_1_uniform: D::Uniform,
@ -333,6 +332,8 @@ impl<D> TileProgram<D> where D: Device {
let program = device.create_program(resources, "tile");
let transform_uniform = device.get_uniform(&program, "Transform");
let tile_size_uniform = device.get_uniform(&program, "TileSize");
let texture_metadata_uniform = device.get_uniform(&program, "TextureMetadata");
let texture_metadata_size_uniform = device.get_uniform(&program, "TextureMetadataSize");
let dest_texture_uniform = device.get_uniform(&program, "DestTexture");
let color_texture_0_uniform = device.get_uniform(&program, "ColorTexture0");
let color_texture_1_uniform = device.get_uniform(&program, "ColorTexture1");
@ -349,6 +350,8 @@ impl<D> TileProgram<D> where D: Device {
program,
transform_uniform,
tile_size_uniform,
texture_metadata_uniform,
texture_metadata_size_uniform,
dest_texture_uniform,
color_texture_0_uniform,
color_texture_1_uniform,

View File

@ -17,6 +17,7 @@ use pathfinder_content::fill::FillRule;
use pathfinder_content::render_target::RenderTargetId;
use pathfinder_geometry::line_segment::{LineSegmentU4, LineSegmentU8};
use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::transform2d::Transform2F;
use pathfinder_geometry::vector::Vector2I;
use pathfinder_gpu::TextureSamplingFlags;
use std::fmt::{Debug, Formatter, Result as DebugResult};
@ -50,6 +51,9 @@ pub enum RenderCommand {
// TODO(pcwalton): Add a rect to this so we can render to subrects of a page.
DeclareRenderTarget { id: RenderTargetId, location: TextureLocation },
// Upload texture metadata.
UploadTextureMetadata(Vec<TextureMetadataEntry>),
// Adds fills to the queue.
AddFills(Vec<FillBatchPrimitive>),
@ -63,6 +67,9 @@ pub enum RenderCommand {
// Pops a render target from the stack.
PopRenderTarget,
// Marks that tile compositing is about to begin.
BeginTileDrawing,
// Draws a batch of tiles to the render target on top of the stack.
DrawTiles(TileBatch),
@ -117,6 +124,13 @@ pub struct TileObjectPrimitive {
pub backdrop: i8,
}
#[derive(Clone, Copy, Debug)]
#[repr(C)]
pub struct TextureMetadataEntry {
pub color_0_transform: Transform2F,
pub opacity: f32,
}
// FIXME(pcwalton): Move `subpx` before `px` and remove `repr(packed)`.
#[derive(Clone, Copy, Debug, Default)]
#[repr(packed)]
@ -129,27 +143,15 @@ pub struct FillBatchPrimitive {
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct Tile {
pub upper_left: TileVertex,
pub upper_right: TileVertex,
pub lower_left: TileVertex,
pub lower_right: TileVertex,
}
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct TileVertex {
pub tile_x: i16,
pub tile_y: i16,
pub color_0_u: f32,
pub color_0_v: f32,
pub color_1_u: f32,
pub color_1_v: f32,
pub mask_0_u: f32,
pub mask_0_v: f32,
pub mask_1_u: f32,
pub mask_1_v: f32,
pub mask_0_backdrop: i16,
pub mask_1_backdrop: i16,
pub mask_0_u: u8,
pub mask_0_v: u8,
pub mask_1_u: u8,
pub mask_1_v: u8,
pub mask_0_backdrop: i8,
pub mask_1_backdrop: i8,
pub color: u16,
}
impl Debug for RenderCommand {
@ -165,12 +167,16 @@ impl Debug for RenderCommand {
RenderCommand::DeclareRenderTarget { id, location } => {
write!(formatter, "DeclareRenderTarget({:?}, {:?})", id, location)
}
RenderCommand::UploadTextureMetadata(ref metadata) => {
write!(formatter, "UploadTextureMetadata(x{})", metadata.len())
}
RenderCommand::AddFills(ref fills) => write!(formatter, "AddFills(x{})", fills.len()),
RenderCommand::FlushFills => write!(formatter, "FlushFills"),
RenderCommand::PushRenderTarget(render_target_id) => {
write!(formatter, "PushRenderTarget({:?})", render_target_id)
}
RenderCommand::PopRenderTarget => write!(formatter, "PopRenderTarget"),
RenderCommand::BeginTileDrawing => write!(formatter, "BeginTileDrawing"),
RenderCommand::DrawTiles(ref batch) => {
write!(formatter,
"DrawTiles(x{}, C0 {:?}, C1 {:?}, M0 {:?}, {:?})",

View File

@ -9,9 +9,9 @@
// except according to those terms.
use crate::allocator::{AllocationMode, TextureAllocator};
use crate::gpu_data::{RenderCommand, TextureLocation, TexturePageDescriptor, TexturePageId};
use crate::gpu_data::{RenderCommand, TextureLocation, TextureMetadataEntry};
use crate::gpu_data::{TexturePageDescriptor, TexturePageId};
use crate::scene::RenderTarget;
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
use hashbrown::HashMap;
use pathfinder_color::ColorU;
use pathfinder_content::effects::{Filter, PatternFilter};
@ -136,6 +136,27 @@ impl Paint {
Paint::Pattern(ref mut pattern) => pattern.apply_transform(*transform),
}
}
fn opacity(&self) -> u8 {
match *self {
Paint::Color(_) | Paint::Gradient(_) => !0,
Paint::Pattern(ref pattern) => pattern.opacity(),
}
}
pub fn apply_opacity(&mut self, new_opacity: f32) {
match *self {
Paint::Color(ref mut color) => color.a = (color.a as f32 * new_opacity) as u8,
Paint::Gradient(ref mut gradient) => {
for stop in gradient.stops_mut() {
stop.color.a = (stop.color.a as f32 * new_opacity) as u8
}
}
Paint::Pattern(ref mut pattern) => {
pattern.set_opacity((pattern.opacity() as f32 * new_opacity) as u8)
}
}
}
}
pub struct PaintInfo {
@ -167,6 +188,8 @@ pub struct PaintMetadata {
pub is_opaque: bool,
/// The filter to be applied to this paint.
pub filter: PaintFilter,
/// The paint opacity (global alpha, in canvas terminology).
pub opacity: u8,
}
#[derive(Clone, Copy, Debug)]
@ -292,6 +315,7 @@ impl Palette {
sampling_flags,
is_opaque: paint.is_opaque(),
filter,
opacity: paint.opacity(),
});
}
@ -300,8 +324,9 @@ impl Palette {
let texture_scale = allocator.page_scale(metadata.location.page);
metadata.texture_transform = match paint {
Paint::Color(_) => {
let matrix = Matrix2x2F(F32x4::default());
let vector = rect_to_inset_uv(metadata.location.rect, texture_scale).origin();
Transform2F { matrix: Matrix2x2F(F32x4::default()), vector } * render_transform.inverse()
Transform2F { matrix, vector } * render_transform.inverse()
}
Paint::Gradient(Gradient { line: gradient_line, radii: None, .. }) => {
let v0 = metadata.location.rect.to_f32().center().y() * texture_scale.y();
@ -354,9 +379,18 @@ impl Palette {
let opacity_tile_page = opacity_tile_builder.tile_location.page;
let opacity_tile_transform = opacity_tile_builder.tile_transform(&allocator);
// Create texture metadata.
let texture_metadata = paint_metadata.iter().map(|paint_metadata| {
TextureMetadataEntry {
color_0_transform: paint_metadata.texture_transform,
opacity: paint_metadata.opacity as f32 / 255.0,
}
}).collect();
// Create render commands.
let mut render_commands = vec![
RenderCommand::AllocateTexturePages(texture_page_descriptors)
RenderCommand::UploadTextureMetadata(texture_metadata),
RenderCommand::AllocateTexturePages(texture_page_descriptors),
];
for (index, metadata) in render_target_metadata.iter().enumerate() {
let id = RenderTargetId(index as u32);
@ -386,14 +420,6 @@ impl Palette {
}
impl PaintMetadata {
// TODO(pcwalton): Apply clamp/repeat to tile rect.
pub(crate) fn calculate_tex_coords(&self, tile_position: Vector2I) -> Vector2F {
let tile_size = vec2i(TILE_WIDTH as i32, TILE_HEIGHT as i32);
let position = (tile_position * tile_size).to_f32();
let tex_coords = self.texture_transform * position;
tex_coords
}
pub(crate) fn filter(&self) -> Filter {
match self.filter {
PaintFilter::None => Filter::None,

View File

@ -143,7 +143,6 @@ impl Scene {
}),
fill_rule: draw_path.fill_rule,
blend_mode: draw_path.blend_mode,
opacity: draw_path.opacity,
name: draw_path.name,
});
}
@ -313,7 +312,6 @@ pub struct DrawPath {
clip_path: Option<ClipPathId>,
fill_rule: FillRule,
blend_mode: BlendMode,
opacity: u8,
name: String,
}
@ -355,7 +353,6 @@ impl DrawPath {
clip_path: None,
fill_rule: FillRule::Winding,
blend_mode: BlendMode::SrcOver,
opacity: !0,
name: String::new(),
}
}
@ -400,16 +397,6 @@ impl DrawPath {
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

View File

@ -10,7 +10,7 @@
use crate::builder::{BuiltPath, ObjectBuilder, Occluder, SceneBuilder, SolidTiles};
use crate::gpu_data::TileObjectPrimitive;
use crate::paint::PaintMetadata;
use crate::paint::{PaintId, PaintMetadata};
use pathfinder_content::effects::BlendMode;
use pathfinder_content::fill::FillRule;
use pathfinder_content::outline::{Contour, Outline, PointIndex};
@ -18,7 +18,6 @@ use pathfinder_content::segment::Segment;
use pathfinder_content::sorted_vector::SortedVector;
use pathfinder_geometry::line_segment::LineSegment2F;
use pathfinder_geometry::rect::{RectF, RectI};
use pathfinder_geometry::transform2d::Transform2F;
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2f, vec2i};
use std::cmp::Ordering;
use std::mem;
@ -48,10 +47,9 @@ pub(crate) enum TilingPathInfo<'a> {
#[derive(Clone, Copy)]
pub(crate) struct DrawTilingPathInfo<'a> {
pub(crate) paint_id: PaintId,
pub(crate) paint_metadata: &'a PaintMetadata,
pub(crate) opacity_tile_transform: Transform2F,
pub(crate) blend_mode: BlendMode,
pub(crate) opacity: u8,
pub(crate) built_clip_path: Option<&'a BuiltPath>,
}

View File

@ -11,13 +11,13 @@
//! Software occlusion culling.
use crate::builder::Occluder;
use crate::gpu_data::{Tile, TileBatch, TileBatchTexture, TileVertex};
use crate::gpu_data::{Tile, TileBatch, TileBatchTexture};
use crate::paint::{PaintId, PaintMetadata};
use crate::tile_map::DenseTileMap;
use crate::tiles;
use pathfinder_content::effects::{BlendMode, Filter};
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::vector::{Vector2F, Vector2I, vec2i};
use pathfinder_geometry::vector::Vector2I;
use vec_map::VecMap;
pub(crate) struct ZBuffer {
@ -71,7 +71,8 @@ impl ZBuffer {
let tile_coords = self.buffer.index_to_coords(tile_index);
let depth_metadata = self.depth_metadata[depth as usize];
let paint_metadata = &paint_metadata[depth_metadata.paint_id.0 as usize];
let paint_id = depth_metadata.paint_id;
let paint_metadata = &paint_metadata[paint_id.0 as usize];
let tile_position = tile_coords + self.buffer.rect.origin();
@ -103,7 +104,7 @@ impl ZBuffer {
}
let batch = solid_tiles.batches.last_mut().unwrap();
batch.tiles.push(Tile::new_solid_with_paint_metadata(tile_position, paint_metadata));
batch.tiles.push(Tile::new_solid_from_paint_id(tile_position, paint_id));
}
solid_tiles
@ -111,42 +112,17 @@ impl ZBuffer {
}
impl Tile {
pub(crate) fn new_solid_with_paint_metadata(tile_position: Vector2I,
paint_metadata: &PaintMetadata)
-> Tile {
pub(crate) fn new_solid_from_paint_id(tile_origin: Vector2I, paint_id: PaintId) -> Tile {
Tile {
upper_left: TileVertex::new_solid_from_paint_metadata(tile_position, paint_metadata),
upper_right: TileVertex::new_solid_from_paint_metadata(tile_position + vec2i(1, 0),
paint_metadata),
lower_left: TileVertex::new_solid_from_paint_metadata(tile_position + vec2i(0, 1),
paint_metadata),
lower_right: TileVertex::new_solid_from_paint_metadata(tile_position + vec2i(1, 1),
paint_metadata),
}
}
}
impl TileVertex {
fn new_solid_from_uv(tile_position: Vector2I, color_0_uv: Vector2F) -> TileVertex {
TileVertex {
tile_x: tile_position.x() as i16,
tile_y: tile_position.y() as i16,
color_0_u: color_0_uv.x(),
color_0_v: color_0_uv.y(),
color_1_u: 0.0,
color_1_v: 0.0,
mask_0_u: 0.0,
mask_0_v: 0.0,
mask_1_u: 0.0,
mask_1_v: 0.0,
tile_x: tile_origin.x() as i16,
tile_y: tile_origin.y() as i16,
mask_0_backdrop: 0,
mask_1_backdrop: 0,
mask_0_u: 0,
mask_0_v: 0,
mask_1_u: 0,
mask_1_v: 0,
color: paint_id.0,
}
}
fn new_solid_from_paint_metadata(tile_position: Vector2I, paint_metadata: &PaintMetadata)
-> TileVertex {
let color_uv = paint_metadata.calculate_tex_coords(tile_position);
TileVertex::new_solid_from_uv(tile_position, color_uv)
}
}

View File

@ -76,11 +76,9 @@ precision highp sampler2D;
uniform sampler2D uColorTexture0;
uniform sampler2D uColorTexture1;
uniform sampler2D uMaskTexture0;
uniform sampler2D uMaskTexture1;
uniform sampler2D uDestTexture;
@ -95,7 +93,7 @@ uniform int uCtrl;
in vec3 vMaskTexCoord0;
in vec3 vMaskTexCoord1;
in vec2 vColorTexCoord0;
in vec2 vColorTexCoord1;
in float vOpacity;
out vec4 oFragColor;
@ -575,11 +573,9 @@ void calculateColor(int ctrl){
uFilterParams2,
color0Filter);
}
if(((ctrl >> 7)& 0x1)!= 0)
color *= sampleColor(uColorTexture1, vColorTexCoord1);
color . a *= maskAlpha;
color . a *= maskAlpha * vOpacity;
int compositeOp =(ctrl >> 8)& 0xf;

View File

@ -17,25 +17,39 @@ precision highp sampler2D;
uniform mat4 uTransform;
uniform vec2 uTileSize;
uniform sampler2D uTextureMetadata;
uniform ivec2 uTextureMetadataSize;
in ivec2 aTilePosition;
in vec2 aColorTexCoord0;
in vec2 aColorTexCoord1;
in vec2 aMaskTexCoord0;
in vec2 aMaskTexCoord1;
in ivec2 aTileOffset;
in ivec2 aTileOrigin;
in uvec2 aMaskTexCoord0;
in uvec2 aMaskTexCoord1;
in ivec2 aMaskBackdrop;
in int aColor;
out vec3 vMaskTexCoord0;
out vec3 vMaskTexCoord1;
out vec2 vColorTexCoord0;
out vec2 vColorTexCoord1;
out float vOpacity;
void main(){
vec2 position = vec2(aTilePosition)* uTileSize;
vColorTexCoord0 = aColorTexCoord0;
vColorTexCoord1 = aColorTexCoord1;
vMaskTexCoord0 = vec3(aMaskTexCoord0, float(aMaskBackdrop . x));
vMaskTexCoord1 = vec3(aMaskTexCoord1, float(aMaskBackdrop . y));
vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset);
vec2 position =(tileOrigin + tileOffset)* uTileSize;
vec2 maskTexCoord0 =(vec2(aMaskTexCoord0)+ tileOffset)/ 256.0;
vec2 maskTexCoord1 =(vec2(aMaskTexCoord1)+ tileOffset)/ 256.0;
vec2 textureMetadataScale = vec2(1.0)/ vec2(uTextureMetadataSize);
vec2 metadataEntryCoord = ivec2(aColor % 256 * 2, aColor / 256);
vec2 colorTexMatrix0Coord =(metadataEntryCoord + vec2(0.5, 0.5))* textureMetadataScale;
vec2 colorTexOffsetsCoord =(metadataEntryCoord + vec2(1.5, 0.5))* textureMetadataScale;
vec4 colorTexMatrix0 = texture(uTextureMetadata, colorTexMatrix0Coord);
vec4 colorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord);
vColorTexCoord0 = mat2(colorTexMatrix0)* position + colorTexOffsets . xy;
vOpacity = colorTexOffsets . z;
vMaskTexCoord0 = vec3(maskTexCoord0, float(aMaskBackdrop . x));
vMaskTexCoord1 = vec3(maskTexCoord1, float(aMaskBackdrop . y));
gl_Position = uTransform * vec4(position, 0.0, 1.0);
}

View File

@ -21,11 +21,9 @@ struct spvDescriptorSetBuffer0
constant float4* uFilterParams0 [[id(10)]];
constant float4* uFilterParams1 [[id(11)]];
constant float4* uFilterParams2 [[id(12)]];
texture2d<float> uColorTexture1 [[id(13)]];
sampler uColorTexture1Smplr [[id(14)]];
texture2d<float> uDestTexture [[id(15)]];
sampler uDestTextureSmplr [[id(16)]];
constant int* uCtrl [[id(17)]];
texture2d<float> uDestTexture [[id(13)]];
sampler uDestTextureSmplr [[id(14)]];
constant int* uCtrl [[id(15)]];
};
constant float3 _1003 = {};
@ -40,7 +38,7 @@ struct main0_in
float3 vMaskTexCoord0 [[user(locn0)]];
float3 vMaskTexCoord1 [[user(locn1)]];
float2 vColorTexCoord0 [[user(locn2)]];
float2 vColorTexCoord1 [[user(locn3)]];
float vOpacity [[user(locn3)]];
};
// Implementation of the GLSL mod() function, which is slightly different than Metal fmod()
@ -534,7 +532,7 @@ float4 composite(thread const float4& srcColor, thread const texture2d<float> de
return float4(((srcColor.xyz * (srcColor.w * (1.0 - destColor.w))) + (blendedRGB * (srcColor.w * destColor.w))) + (destColor.xyz * (1.0 - srcColor.w)), 1.0);
}
void calculateColor(thread const int& ctrl, thread texture2d<float> uMaskTexture0, thread const sampler uMaskTexture0Smplr, thread float3& vMaskTexCoord0, thread texture2d<float> uMaskTexture1, thread const sampler uMaskTexture1Smplr, thread float3& vMaskTexCoord1, thread float2& vColorTexCoord0, thread texture2d<float> uColorTexture0, thread const sampler uColorTexture0Smplr, thread texture2d<float> uGammaLUT, thread const sampler uGammaLUTSmplr, thread float2 uColorTexture0Size, thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread float4 uFilterParams0, thread float4 uFilterParams1, thread float4 uFilterParams2, thread texture2d<float> uColorTexture1, thread const sampler uColorTexture1Smplr, thread float2& vColorTexCoord1, thread texture2d<float> uDestTexture, thread const sampler uDestTextureSmplr, thread float4& oFragColor)
void calculateColor(thread const int& ctrl, thread texture2d<float> uMaskTexture0, thread const sampler uMaskTexture0Smplr, thread float3& vMaskTexCoord0, thread texture2d<float> uMaskTexture1, thread const sampler uMaskTexture1Smplr, thread float3& vMaskTexCoord1, thread float2& vColorTexCoord0, thread texture2d<float> uColorTexture0, thread const sampler uColorTexture0Smplr, thread texture2d<float> uGammaLUT, thread const sampler uGammaLUTSmplr, thread float2 uColorTexture0Size, thread float4& gl_FragCoord, thread float2 uFramebufferSize, thread float4 uFilterParams0, thread float4 uFilterParams1, thread float4 uFilterParams2, thread float& vOpacity, thread texture2d<float> uDestTexture, thread const sampler uDestTextureSmplr, thread float4& oFragColor)
{
int maskCtrl0 = (ctrl >> 0) & 3;
int maskCtrl1 = (ctrl >> 2) & 3;
@ -561,20 +559,15 @@ void calculateColor(thread const int& ctrl, thread texture2d<float> uMaskTexture
int param_13 = color0Filter;
color += filterColor(param_6, uColorTexture0, uColorTexture0Smplr, uGammaLUT, uGammaLUTSmplr, param_7, param_8, param_9, param_10, param_11, param_12, param_13);
}
if (((ctrl >> 7) & 1) != 0)
{
float2 param_14 = vColorTexCoord1;
color *= sampleColor(uColorTexture1, uColorTexture1Smplr, param_14);
}
color.w *= maskAlpha;
color.w *= (maskAlpha * vOpacity);
int compositeOp = (ctrl >> 8) & 15;
float4 param_15 = color;
float2 param_16 = uFramebufferSize;
float2 param_17 = gl_FragCoord.xy;
int param_18 = compositeOp;
color = composite(param_15, uDestTexture, uDestTextureSmplr, param_16, param_17, param_18);
float3 _1304 = color.xyz * color.w;
color = float4(_1304.x, _1304.y, _1304.z, color.w);
float4 param_14 = color;
float2 param_15 = uFramebufferSize;
float2 param_16 = gl_FragCoord.xy;
int param_17 = compositeOp;
color = composite(param_14, uDestTexture, uDestTextureSmplr, param_15, param_16, param_17);
float3 _1294 = color.xyz * color.w;
color = float4(_1294.x, _1294.y, _1294.z, color.w);
oFragColor = color;
}
@ -582,7 +575,7 @@ fragment main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuff
{
main0_out out = {};
int param = (*spvDescriptorSet0.uCtrl);
calculateColor(param, spvDescriptorSet0.uMaskTexture0, spvDescriptorSet0.uMaskTexture0Smplr, in.vMaskTexCoord0, spvDescriptorSet0.uMaskTexture1, spvDescriptorSet0.uMaskTexture1Smplr, in.vMaskTexCoord1, in.vColorTexCoord0, spvDescriptorSet0.uColorTexture0, spvDescriptorSet0.uColorTexture0Smplr, spvDescriptorSet0.uGammaLUT, spvDescriptorSet0.uGammaLUTSmplr, (*spvDescriptorSet0.uColorTexture0Size), gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), (*spvDescriptorSet0.uFilterParams0), (*spvDescriptorSet0.uFilterParams1), (*spvDescriptorSet0.uFilterParams2), spvDescriptorSet0.uColorTexture1, spvDescriptorSet0.uColorTexture1Smplr, in.vColorTexCoord1, spvDescriptorSet0.uDestTexture, spvDescriptorSet0.uDestTextureSmplr, out.oFragColor);
calculateColor(param, spvDescriptorSet0.uMaskTexture0, spvDescriptorSet0.uMaskTexture0Smplr, in.vMaskTexCoord0, spvDescriptorSet0.uMaskTexture1, spvDescriptorSet0.uMaskTexture1Smplr, in.vMaskTexCoord1, in.vColorTexCoord0, spvDescriptorSet0.uColorTexture0, spvDescriptorSet0.uColorTexture0Smplr, spvDescriptorSet0.uGammaLUT, spvDescriptorSet0.uGammaLUTSmplr, (*spvDescriptorSet0.uColorTexture0Size), gl_FragCoord, (*spvDescriptorSet0.uFramebufferSize), (*spvDescriptorSet0.uFilterParams0), (*spvDescriptorSet0.uFilterParams1), (*spvDescriptorSet0.uFilterParams2), in.vOpacity, spvDescriptorSet0.uDestTexture, spvDescriptorSet0.uDestTextureSmplr, out.oFragColor);
return out;
}

View File

@ -7,7 +7,10 @@ using namespace metal;
struct spvDescriptorSetBuffer0
{
constant float2* uTileSize [[id(0)]];
constant float4x4* uTransform [[id(1)]];
constant int2* uTextureMetadataSize [[id(1)]];
texture2d<float> uTextureMetadata [[id(2)]];
sampler uTextureMetadataSmplr [[id(3)]];
constant float4x4* uTransform [[id(4)]];
};
struct main0_out
@ -15,28 +18,38 @@ struct main0_out
float3 vMaskTexCoord0 [[user(locn0)]];
float3 vMaskTexCoord1 [[user(locn1)]];
float2 vColorTexCoord0 [[user(locn2)]];
float2 vColorTexCoord1 [[user(locn3)]];
float vOpacity [[user(locn3)]];
float4 gl_Position [[position]];
};
struct main0_in
{
int2 aTilePosition [[attribute(0)]];
float2 aColorTexCoord0 [[attribute(1)]];
float2 aColorTexCoord1 [[attribute(2)]];
float2 aMaskTexCoord0 [[attribute(3)]];
float2 aMaskTexCoord1 [[attribute(4)]];
int2 aMaskBackdrop [[attribute(5)]];
int2 aTileOffset [[attribute(0)]];
int2 aTileOrigin [[attribute(1)]];
uint2 aMaskTexCoord0 [[attribute(2)]];
uint2 aMaskTexCoord1 [[attribute(3)]];
int2 aMaskBackdrop [[attribute(4)]];
int aColor [[attribute(5)]];
};
vertex main0_out main0(main0_in in [[stage_in]], constant spvDescriptorSetBuffer0& spvDescriptorSet0 [[buffer(0)]])
{
main0_out out = {};
float2 position = float2(in.aTilePosition) * (*spvDescriptorSet0.uTileSize);
out.vColorTexCoord0 = in.aColorTexCoord0;
out.vColorTexCoord1 = in.aColorTexCoord1;
out.vMaskTexCoord0 = float3(in.aMaskTexCoord0, float(in.aMaskBackdrop.x));
out.vMaskTexCoord1 = float3(in.aMaskTexCoord1, float(in.aMaskBackdrop.y));
float2 tileOrigin = float2(in.aTileOrigin);
float2 tileOffset = float2(in.aTileOffset);
float2 position = (tileOrigin + tileOffset) * (*spvDescriptorSet0.uTileSize);
float2 maskTexCoord0 = (float2(in.aMaskTexCoord0) + tileOffset) / float2(256.0);
float2 maskTexCoord1 = (float2(in.aMaskTexCoord1) + tileOffset) / float2(256.0);
float2 textureMetadataScale = float2(1.0) / float2((*spvDescriptorSet0.uTextureMetadataSize));
float2 metadataEntryCoord = float2(int2((in.aColor % 256) * 2, in.aColor / 256));
float2 colorTexMatrix0Coord = (metadataEntryCoord + float2(0.5)) * textureMetadataScale;
float2 colorTexOffsetsCoord = (metadataEntryCoord + float2(1.5, 0.5)) * textureMetadataScale;
float4 colorTexMatrix0 = spvDescriptorSet0.uTextureMetadata.sample(spvDescriptorSet0.uTextureMetadataSmplr, colorTexMatrix0Coord, level(0.0));
float4 colorTexOffsets = spvDescriptorSet0.uTextureMetadata.sample(spvDescriptorSet0.uTextureMetadataSmplr, colorTexOffsetsCoord, level(0.0));
out.vColorTexCoord0 = (float2x2(float2(colorTexMatrix0.xy), float2(colorTexMatrix0.zw)) * position) + colorTexOffsets.xy;
out.vOpacity = colorTexOffsets.z;
out.vMaskTexCoord0 = float3(maskTexCoord0, float(in.aMaskBackdrop.x));
out.vMaskTexCoord1 = float3(maskTexCoord1, float(in.aMaskBackdrop.y));
out.gl_Position = (*spvDescriptorSet0.uTransform) * float4(position, 0.0, 1.0);
return out;
}

View File

@ -74,11 +74,9 @@ precision highp sampler2D;
#define COMBINER_CTRL_MASK_1_SHIFT 2
#define COMBINER_CTRL_COLOR_0_FILTER_SHIFT 4
#define COMBINER_CTRL_COLOR_0_ENABLE_SHIFT 6
#define COMBINER_CTRL_COLOR_1_ENABLE_SHIFT 7
#define COMBINER_CTRL_COMPOSITE_SHIFT 8
uniform sampler2D uColorTexture0;
uniform sampler2D uColorTexture1;
uniform sampler2D uMaskTexture0;
uniform sampler2D uMaskTexture1;
uniform sampler2D uDestTexture;
@ -93,7 +91,7 @@ uniform int uCtrl;
in vec3 vMaskTexCoord0;
in vec3 vMaskTexCoord1;
in vec2 vColorTexCoord0;
in vec2 vColorTexCoord1;
in float vOpacity;
out vec4 oFragColor;
@ -573,11 +571,9 @@ void calculateColor(int ctrl) {
uFilterParams2,
color0Filter);
}
if (((ctrl >> COMBINER_CTRL_COLOR_1_ENABLE_SHIFT) & COMBINER_CTRL_COLOR_ENABLE_MASK) != 0)
color *= sampleColor(uColorTexture1, vColorTexCoord1);
// Apply mask.
color.a *= maskAlpha;
// Apply mask and opacity.
color.a *= maskAlpha * vOpacity;
// Apply composite.
int compositeOp = (ctrl >> COMBINER_CTRL_COMPOSITE_SHIFT) & COMBINER_CTRL_COMPOSITE_MASK;

View File

@ -15,24 +15,38 @@ precision highp sampler2D;
uniform mat4 uTransform;
uniform vec2 uTileSize;
uniform sampler2D uTextureMetadata;
uniform ivec2 uTextureMetadataSize;
in ivec2 aTilePosition;
in vec2 aColorTexCoord0;
in vec2 aColorTexCoord1;
in vec2 aMaskTexCoord0;
in vec2 aMaskTexCoord1;
in ivec2 aTileOffset;
in ivec2 aTileOrigin;
in uvec2 aMaskTexCoord0;
in uvec2 aMaskTexCoord1;
in ivec2 aMaskBackdrop;
in int aColor;
out vec3 vMaskTexCoord0;
out vec3 vMaskTexCoord1;
out vec2 vColorTexCoord0;
out vec2 vColorTexCoord1;
out float vOpacity;
void main() {
vec2 position = vec2(aTilePosition) * uTileSize;
vColorTexCoord0 = aColorTexCoord0;
vColorTexCoord1 = aColorTexCoord1;
vMaskTexCoord0 = vec3(aMaskTexCoord0, float(aMaskBackdrop.x));
vMaskTexCoord1 = vec3(aMaskTexCoord1, float(aMaskBackdrop.y));
vec2 tileOrigin = vec2(aTileOrigin), tileOffset = vec2(aTileOffset);
vec2 position = (tileOrigin + tileOffset) * uTileSize;
vec2 maskTexCoord0 = (vec2(aMaskTexCoord0) + tileOffset) / 256.0;
vec2 maskTexCoord1 = (vec2(aMaskTexCoord1) + tileOffset) / 256.0;
vec2 textureMetadataScale = vec2(1.0) / vec2(uTextureMetadataSize);
vec2 metadataEntryCoord = ivec2(aColor % 256 * 2, aColor / 256);
vec2 colorTexMatrix0Coord = (metadataEntryCoord + vec2(0.5, 0.5)) * textureMetadataScale;
vec2 colorTexOffsetsCoord = (metadataEntryCoord + vec2(1.5, 0.5)) * textureMetadataScale;
vec4 colorTexMatrix0 = texture(uTextureMetadata, colorTexMatrix0Coord);
vec4 colorTexOffsets = texture(uTextureMetadata, colorTexOffsetsCoord);
vColorTexCoord0 = mat2(colorTexMatrix0) * position + colorTexOffsets.xy;
vOpacity = colorTexOffsets.z;
vMaskTexCoord0 = vec3(maskTexCoord0, float(aMaskBackdrop.x));
vMaskTexCoord1 = vec3(maskTexCoord1, float(aMaskBackdrop.y));
gl_Position = uTransform * vec4(position, 0.0, 1.0);
}

View File

@ -230,14 +230,16 @@ impl BuiltSVG {
opacity: Opacity,
fill_rule: UsvgFillRule) {
outline.transform(&state.transform);
let paint = Paint::from_svg_paint(paint, &state.transform, &mut self.result_flags);
let paint = Paint::from_svg_paint(paint,
&state.transform,
opacity,
&mut self.result_flags);
let style = self.scene.push_paint(&paint);
let fill_rule = FillRule::from_usvg_fill_rule(fill_rule);
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);
}
}
@ -287,6 +289,7 @@ impl Display for BuildResultFlags {
trait PaintExt {
fn from_svg_paint(svg_paint: &UsvgPaint,
transform: &Transform2F,
opacity: Opacity,
result_flags: &mut BuildResultFlags)
-> Self;
}
@ -295,6 +298,7 @@ impl PaintExt for Paint {
#[inline]
fn from_svg_paint(svg_paint: &UsvgPaint,
transform: &Transform2F,
opacity: Opacity,
result_flags: &mut BuildResultFlags)
-> Paint {
// TODO(pcwalton): Support gradients.
@ -307,6 +311,7 @@ impl PaintExt for Paint {
}
});
paint.apply_transform(transform);
paint.apply_opacity(opacity.value() as f32);
paint
}
}

View File

@ -35,7 +35,6 @@ pub trait SceneExt {
hinting_options: HintingOptions,
clip_path: Option<ClipPathId>,
blend_mode: BlendMode,
opacity: u8,
paint_id: PaintId)
-> Result<(), GlyphLoadingError>
where F: Loader;
@ -48,7 +47,6 @@ pub trait SceneExt {
hinting_options: HintingOptions,
clip_path: Option<ClipPathId>,
blend_mode: BlendMode,
opacity: u8,
paint_id: PaintId)
-> Result<(), GlyphLoadingError>;
@ -61,7 +59,6 @@ pub trait SceneExt {
hinting_options: HintingOptions,
clip_path: Option<ClipPathId>,
blend_mode: BlendMode,
opacity: u8,
paint_id: PaintId)
-> Result<(), GlyphLoadingError>;
}
@ -76,7 +73,6 @@ impl SceneExt for Scene {
hinting_options: HintingOptions,
clip_path: Option<ClipPathId>,
blend_mode: BlendMode,
opacity: u8,
paint_id: PaintId)
-> Result<(), GlyphLoadingError>
where F: Loader {
@ -93,7 +89,6 @@ impl SceneExt for Scene {
let mut path = DrawPath::new(outline, paint_id);
path.set_clip_path(clip_path);
path.set_blend_mode(blend_mode);
path.set_opacity(opacity);
self.push_path(path);
Ok(())
@ -107,7 +102,6 @@ impl SceneExt for Scene {
hinting_options: HintingOptions,
clip_path: Option<ClipPathId>,
blend_mode: BlendMode,
opacity: u8,
paint_id: PaintId)
-> Result<(), GlyphLoadingError> {
for glyph in &layout.glyphs {
@ -124,7 +118,6 @@ impl SceneExt for Scene {
hinting_options,
clip_path,
blend_mode,
opacity,
paint_id)?;
}
Ok(())
@ -140,7 +133,6 @@ impl SceneExt for Scene {
hinting_options: HintingOptions,
clip_path: Option<ClipPathId>,
blend_mode: BlendMode,
opacity: u8,
paint_id: PaintId)
-> Result<(), GlyphLoadingError> {
let layout = skribo::layout(style, collection, text);
@ -151,7 +143,6 @@ impl SceneExt for Scene {
hinting_options,
clip_path,
blend_mode,
opacity,
paint_id)
}
}