Auto merge of #390 - pcwalton:docs-renderer, r=pcwalton

Add API docs for the renderer and associated types
This commit is contained in:
bors-servo 2020-07-13 19:19:07 -04:00 committed by GitHub
commit d4ec17554b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 470 additions and 309 deletions

View File

@ -54,7 +54,7 @@ fn export_svg<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
view_box.size().y() view_box.size().y()
)?; )?;
for &DrawPath { paint: paint_id, ref outline, ref name, .. } in scene.draw_paths() { for &DrawPath { paint: paint_id, ref outline, ref name, .. } in scene.draw_paths() {
let paint = scene.palette().paints.get(paint_id.0 as usize).unwrap(); let paint = scene.get_paint(paint_id);
write!(writer, " <path")?; write!(writer, " <path")?;
if !name.is_empty() { if !name.is_empty() {
write!(writer, " id=\"{}\"", name)?; write!(writer, " id=\"{}\"", name)?;
@ -78,7 +78,7 @@ fn export_pdf<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
for &DrawPath { paint: paint_id, ref outline, .. } in scene.draw_paths() { for &DrawPath { paint: paint_id, ref outline, .. } in scene.draw_paths() {
// TODO(pcwalton): Gradients and patterns. // TODO(pcwalton): Gradients and patterns.
let paint = scene.palette().paints.get(paint_id.0 as usize).unwrap(); let paint = scene.get_paint(paint_id);
if paint.is_color() { if paint.is_color() {
pdf.set_fill_color(paint.base_color()); pdf.set_fill_color(paint.base_color());
} }
@ -182,7 +182,7 @@ fn export_ps<W: Write>(scene: &Scene, writer: &mut W) -> io::Result<()> {
} }
// TODO(pcwalton): Gradients and patterns. // TODO(pcwalton): Gradients and patterns.
let paint = scene.palette().paints.get(paint_id.0 as usize).unwrap(); let paint = scene.get_paint(paint_id);
if paint.is_color() { if paint.is_color() {
let color = paint.base_color(); let color = paint.base_color();
writeln!(writer, "{} {} {} setrgbcolor", color.r, color.g, color.b)?; writeln!(writer, "{} {} {} setrgbcolor", color.r, color.g, color.b)?;

View File

@ -21,6 +21,7 @@ pub trait Executor {
where T: Send, F: Fn(usize) -> T + Send + Sync; where T: Send, F: Fn(usize) -> T + Send + Sync;
} }
/// An executor that simply executes tasks sequentially in the same thread.
pub struct SequentialExecutor; pub struct SequentialExecutor;
impl Executor for SequentialExecutor { impl Executor for SequentialExecutor {

View File

@ -8,11 +8,12 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! An implementation of the executor using the Rayon library. //! An executor that parallelizes tasks across all CPUs using the Rayon library.
use crate::concurrent::executor::Executor; use crate::concurrent::executor::Executor;
use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::iter::{IntoParallelIterator, ParallelIterator};
/// An executor that parallelizes tasks across all CPUs using the Rayon library.
pub struct RayonExecutor; pub struct RayonExecutor;
impl Executor for RayonExecutor { impl Executor for RayonExecutor {

View File

@ -32,17 +32,30 @@ use std::thread;
const MAX_MESSAGES_IN_FLIGHT: usize = 1024; const MAX_MESSAGES_IN_FLIGHT: usize = 1024;
/// A version of `Scene` that proxies all method calls out to a separate thread.
pub struct SceneProxy { pub struct SceneProxy {
sender: Sender<MainToWorkerMsg>, sender: Sender<MainToWorkerMsg>,
receiver: Receiver<RenderCommand>, receiver: Receiver<RenderCommand>,
} }
impl SceneProxy { impl SceneProxy {
/// Creates a new scene proxy using the given renderer GPU API level and executor to execute
/// CPU tasks.
///
/// If you want to use multiple threads, you typically pass in a `RayonExecutor` here. If you
/// want to use a single thread (perhaps because you're in a WebAssembly environment), pass a
/// `SequentialExecutor`.
pub fn new<E>(renderer_level: RendererLevel, executor: E) -> SceneProxy pub fn new<E>(renderer_level: RendererLevel, executor: E) -> SceneProxy
where E: Executor + Send + 'static { where E: Executor + Send + 'static {
SceneProxy::from_scene(Scene::new(), renderer_level, executor) SceneProxy::from_scene(Scene::new(), renderer_level, executor)
} }
/// Wraps an existing scene in a scene proxy using the given renderer GPU API level an executor
/// to execute CPU tasks.
///
/// If you want to use multiple threads, you typically pass in a `RayonExecutor` here. If you
/// want to use a single thread (perhaps because you're in a WebAssembly environment), pass a
/// `SequentialExecutor`.
pub fn from_scene<E>(scene: Scene, renderer_level: RendererLevel, executor: E) pub fn from_scene<E>(scene: Scene, renderer_level: RendererLevel, executor: E)
-> SceneProxy -> SceneProxy
where E: Executor + Send + 'static { where E: Executor + Send + 'static {
@ -58,22 +71,25 @@ impl SceneProxy {
SceneProxy { sender: main_to_worker_sender, receiver: worker_to_main_receiver } SceneProxy { sender: main_to_worker_sender, receiver: worker_to_main_receiver }
} }
/// Replaces the wrapped scene with a new one, discarding the old scene.
#[inline] #[inline]
pub fn replace_scene(&self, new_scene: Scene) { pub fn replace_scene(&self, new_scene: Scene) {
self.sender.send(MainToWorkerMsg::ReplaceScene(new_scene)).unwrap(); self.sender.send(MainToWorkerMsg::ReplaceScene(new_scene)).unwrap();
} }
/// Sets the view box of the scene, which defines the visible rectangle.
#[inline] #[inline]
pub fn set_view_box(&self, new_view_box: RectF) { pub fn set_view_box(&self, new_view_box: RectF) {
self.sender.send(MainToWorkerMsg::SetViewBox(new_view_box)).unwrap(); self.sender.send(MainToWorkerMsg::SetViewBox(new_view_box)).unwrap();
} }
/// Constructs a scene and queues up the commands needed to render it.
#[inline] #[inline]
pub fn build(&self, options: BuildOptions) { pub fn build(&self, options: BuildOptions) {
self.sender.send(MainToWorkerMsg::Build(options)).unwrap(); self.sender.send(MainToWorkerMsg::Build(options)).unwrap();
} }
/// Sends all queued commands to the given renderer. /// Sends all queued commands to the given renderer to render the wrapped scene.
#[inline] #[inline]
pub fn render<D>(&mut self, renderer: &mut Renderer<D>) where D: Device { pub fn render<D>(&mut self, renderer: &mut Renderer<D>) where D: Device {
renderer.begin_scene(); renderer.begin_scene();
@ -104,6 +120,7 @@ impl SceneProxy {
self.render(renderer); self.render(renderer);
} }
/// Returns a copy of the wrapped scene.
#[inline] #[inline]
pub fn copy_scene(&self) -> Scene { pub fn copy_scene(&self) -> Scene {
let (sender, receiver) = crossbeam_channel::bounded(MAX_MESSAGES_IN_FLIGHT); let (sender, receiver) = crossbeam_channel::bounded(MAX_MESSAGES_IN_FLIGHT);

View File

@ -8,5 +8,9 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! A GPU compute-based renderer that uses functionality available in Direct3D 11.
//!
//! This renderer supports OpenGL at least 4.3, OpenGL ES at least 3.1, and Metal of any version.
pub mod renderer; pub mod renderer;
pub mod shaders; pub mod shaders;

View File

@ -8,6 +8,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! A GPU compute-based renderer that uses functionality available in Direct3D 11.
//!
//! This renderer supports OpenGL at least 4.3, OpenGL ES at least 3.1, and Metal of any version.
use crate::gpu::d3d11::shaders::{BOUND_WORKGROUP_SIZE, DICE_WORKGROUP_SIZE}; use crate::gpu::d3d11::shaders::{BOUND_WORKGROUP_SIZE, DICE_WORKGROUP_SIZE};
use crate::gpu::d3d11::shaders::{PROPAGATE_WORKGROUP_SIZE, ProgramsD3D11, SORT_WORKGROUP_SIZE}; use crate::gpu::d3d11::shaders::{PROPAGATE_WORKGROUP_SIZE, ProgramsD3D11, SORT_WORKGROUP_SIZE};
use crate::gpu::perf::TimeCategory; use crate::gpu::perf::TimeCategory;

View File

@ -8,29 +8,31 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Shaders and vertex specifications for the Direct3D 11-level renderer.
use crate::gpu::shaders::TileProgramCommon; use crate::gpu::shaders::TileProgramCommon;
use crate::tiles::{TILE_HEIGHT, TILE_WIDTH}; use crate::tiles::{TILE_HEIGHT, TILE_WIDTH};
use pathfinder_gpu::{ComputeDimensions, Device}; use pathfinder_gpu::{ComputeDimensions, Device};
use pathfinder_resources::ResourceLoader; use pathfinder_resources::ResourceLoader;
pub const BOUND_WORKGROUP_SIZE: u32 = 64; pub(crate) const BOUND_WORKGROUP_SIZE: u32 = 64;
pub const DICE_WORKGROUP_SIZE: u32 = 64; pub(crate) const DICE_WORKGROUP_SIZE: u32 = 64;
pub const BIN_WORKGROUP_SIZE: u32 = 64; pub(crate) const BIN_WORKGROUP_SIZE: u32 = 64;
pub const PROPAGATE_WORKGROUP_SIZE: u32 = 64; pub(crate) const PROPAGATE_WORKGROUP_SIZE: u32 = 64;
pub const SORT_WORKGROUP_SIZE: u32 = 64; pub(crate) const SORT_WORKGROUP_SIZE: u32 = 64;
pub struct ProgramsD3D11<D> where D: Device { pub(crate) struct ProgramsD3D11<D> where D: Device {
pub bound_program: BoundProgramD3D11<D>, pub(crate) bound_program: BoundProgramD3D11<D>,
pub dice_program: DiceProgramD3D11<D>, pub(crate) dice_program: DiceProgramD3D11<D>,
pub bin_program: BinProgramD3D11<D>, pub(crate) bin_program: BinProgramD3D11<D>,
pub propagate_program: PropagateProgramD3D11<D>, pub(crate) propagate_program: PropagateProgramD3D11<D>,
pub sort_program: SortProgramD3D11<D>, pub(crate) sort_program: SortProgramD3D11<D>,
pub fill_program: FillProgramD3D11<D>, pub(crate) fill_program: FillProgramD3D11<D>,
pub tile_program: TileProgramD3D11<D>, pub(crate) tile_program: TileProgramD3D11<D>,
} }
impl<D> ProgramsD3D11<D> where D: Device { impl<D> ProgramsD3D11<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsD3D11<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsD3D11<D> {
ProgramsD3D11 { ProgramsD3D11 {
bound_program: BoundProgramD3D11::new(device, resources), bound_program: BoundProgramD3D11::new(device, resources),
dice_program: DiceProgramD3D11::new(device, resources), dice_program: DiceProgramD3D11::new(device, resources),
@ -43,23 +45,23 @@ impl<D> ProgramsD3D11<D> where D: Device {
} }
} }
pub struct PropagateProgramD3D11<D> where D: Device { pub(crate) struct PropagateProgramD3D11<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub framebuffer_tile_size_uniform: D::Uniform, pub(crate) framebuffer_tile_size_uniform: D::Uniform,
pub column_count_uniform: D::Uniform, pub(crate) column_count_uniform: D::Uniform,
pub first_alpha_tile_index_uniform: D::Uniform, pub(crate) first_alpha_tile_index_uniform: D::Uniform,
pub draw_metadata_storage_buffer: D::StorageBuffer, pub(crate) draw_metadata_storage_buffer: D::StorageBuffer,
pub clip_metadata_storage_buffer: D::StorageBuffer, pub(crate) clip_metadata_storage_buffer: D::StorageBuffer,
pub backdrops_storage_buffer: D::StorageBuffer, pub(crate) backdrops_storage_buffer: D::StorageBuffer,
pub draw_tiles_storage_buffer: D::StorageBuffer, pub(crate) draw_tiles_storage_buffer: D::StorageBuffer,
pub clip_tiles_storage_buffer: D::StorageBuffer, pub(crate) clip_tiles_storage_buffer: D::StorageBuffer,
pub z_buffer_storage_buffer: D::StorageBuffer, pub(crate) z_buffer_storage_buffer: D::StorageBuffer,
pub first_tile_map_storage_buffer: D::StorageBuffer, pub(crate) first_tile_map_storage_buffer: D::StorageBuffer,
pub alpha_tiles_storage_buffer: D::StorageBuffer, pub(crate) alpha_tiles_storage_buffer: D::StorageBuffer,
} }
impl<D> PropagateProgramD3D11<D> where D: Device { impl<D> PropagateProgramD3D11<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> PropagateProgramD3D11<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> PropagateProgramD3D11<D> {
let mut program = device.create_compute_program(resources, "d3d11/propagate"); let mut program = device.create_compute_program(resources, "d3d11/propagate");
let local_size = ComputeDimensions { x: PROPAGATE_WORKGROUP_SIZE, y: 1, z: 1 }; let local_size = ComputeDimensions { x: PROPAGATE_WORKGROUP_SIZE, y: 1, z: 1 };
device.set_compute_program_local_size(&mut program, local_size); device.set_compute_program_local_size(&mut program, local_size);
@ -93,18 +95,18 @@ impl<D> PropagateProgramD3D11<D> where D: Device {
} }
} }
pub struct FillProgramD3D11<D> where D: Device { pub(crate) struct FillProgramD3D11<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub dest_image: D::ImageParameter, pub(crate) dest_image: D::ImageParameter,
pub area_lut_texture: D::TextureParameter, pub(crate) area_lut_texture: D::TextureParameter,
pub alpha_tile_range_uniform: D::Uniform, pub(crate) alpha_tile_range_uniform: D::Uniform,
pub fills_storage_buffer: D::StorageBuffer, pub(crate) fills_storage_buffer: D::StorageBuffer,
pub tiles_storage_buffer: D::StorageBuffer, pub(crate) tiles_storage_buffer: D::StorageBuffer,
pub alpha_tiles_storage_buffer: D::StorageBuffer, pub(crate) alpha_tiles_storage_buffer: D::StorageBuffer,
} }
impl<D> FillProgramD3D11<D> where D: Device { impl<D> FillProgramD3D11<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> FillProgramD3D11<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> FillProgramD3D11<D> {
let mut program = device.create_compute_program(resources, "d3d11/fill"); let mut program = device.create_compute_program(resources, "d3d11/fill");
let local_size = ComputeDimensions { x: TILE_WIDTH, y: TILE_HEIGHT / 4, z: 1 }; let local_size = ComputeDimensions { x: TILE_WIDTH, y: TILE_HEIGHT / 4, z: 1 };
device.set_compute_program_local_size(&mut program, local_size); device.set_compute_program_local_size(&mut program, local_size);
@ -128,14 +130,14 @@ impl<D> FillProgramD3D11<D> where D: Device {
} }
} }
pub struct TileProgramD3D11<D> where D: Device { pub(crate) struct TileProgramD3D11<D> where D: Device {
pub common: TileProgramCommon<D>, pub(crate) common: TileProgramCommon<D>,
pub load_action_uniform: D::Uniform, pub(crate) load_action_uniform: D::Uniform,
pub clear_color_uniform: D::Uniform, pub(crate) clear_color_uniform: D::Uniform,
pub framebuffer_tile_size_uniform: D::Uniform, pub(crate) framebuffer_tile_size_uniform: D::Uniform,
pub dest_image: D::ImageParameter, pub(crate) dest_image: D::ImageParameter,
pub tiles_storage_buffer: D::StorageBuffer, pub(crate) tiles_storage_buffer: D::StorageBuffer,
pub first_tile_map_storage_buffer: D::StorageBuffer, pub(crate) first_tile_map_storage_buffer: D::StorageBuffer,
} }
impl<D> TileProgramD3D11<D> where D: Device { impl<D> TileProgramD3D11<D> where D: Device {
@ -164,20 +166,20 @@ impl<D> TileProgramD3D11<D> where D: Device {
} }
} }
pub struct BinProgramD3D11<D> where D: Device { pub(crate) struct BinProgramD3D11<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub microline_count_uniform: D::Uniform, pub(crate) microline_count_uniform: D::Uniform,
pub max_fill_count_uniform: D::Uniform, pub(crate) max_fill_count_uniform: D::Uniform,
pub microlines_storage_buffer: D::StorageBuffer, pub(crate) microlines_storage_buffer: D::StorageBuffer,
pub metadata_storage_buffer: D::StorageBuffer, pub(crate) metadata_storage_buffer: D::StorageBuffer,
pub indirect_draw_params_storage_buffer: D::StorageBuffer, pub(crate) indirect_draw_params_storage_buffer: D::StorageBuffer,
pub fills_storage_buffer: D::StorageBuffer, pub(crate) fills_storage_buffer: D::StorageBuffer,
pub tiles_storage_buffer: D::StorageBuffer, pub(crate) tiles_storage_buffer: D::StorageBuffer,
pub backdrops_storage_buffer: D::StorageBuffer, pub(crate) backdrops_storage_buffer: D::StorageBuffer,
} }
impl<D> BinProgramD3D11<D> where D: Device { impl<D> BinProgramD3D11<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> BinProgramD3D11<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> BinProgramD3D11<D> {
let mut program = device.create_compute_program(resources, "d3d11/bin"); let mut program = device.create_compute_program(resources, "d3d11/bin");
let dimensions = ComputeDimensions { x: BIN_WORKGROUP_SIZE, y: 1, z: 1 }; let dimensions = ComputeDimensions { x: BIN_WORKGROUP_SIZE, y: 1, z: 1 };
device.set_compute_program_local_size(&mut program, dimensions); device.set_compute_program_local_size(&mut program, dimensions);
@ -207,22 +209,22 @@ impl<D> BinProgramD3D11<D> where D: Device {
} }
} }
pub struct DiceProgramD3D11<D> where D: Device { pub(crate) struct DiceProgramD3D11<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub transform_uniform: D::Uniform, pub(crate) transform_uniform: D::Uniform,
pub translation_uniform: D::Uniform, pub(crate) translation_uniform: D::Uniform,
pub path_count_uniform: D::Uniform, pub(crate) path_count_uniform: D::Uniform,
pub last_batch_segment_index_uniform: D::Uniform, pub(crate) last_batch_segment_index_uniform: D::Uniform,
pub max_microline_count_uniform: D::Uniform, pub(crate) max_microline_count_uniform: D::Uniform,
pub compute_indirect_params_storage_buffer: D::StorageBuffer, pub(crate) compute_indirect_params_storage_buffer: D::StorageBuffer,
pub dice_metadata_storage_buffer: D::StorageBuffer, pub(crate) dice_metadata_storage_buffer: D::StorageBuffer,
pub points_storage_buffer: D::StorageBuffer, pub(crate) points_storage_buffer: D::StorageBuffer,
pub input_indices_storage_buffer: D::StorageBuffer, pub(crate) input_indices_storage_buffer: D::StorageBuffer,
pub microlines_storage_buffer: D::StorageBuffer, pub(crate) microlines_storage_buffer: D::StorageBuffer,
} }
impl<D> DiceProgramD3D11<D> where D: Device { impl<D> DiceProgramD3D11<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> DiceProgramD3D11<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> DiceProgramD3D11<D> {
let mut program = device.create_compute_program(resources, "d3d11/dice"); let mut program = device.create_compute_program(resources, "d3d11/dice");
let dimensions = ComputeDimensions { x: DICE_WORKGROUP_SIZE, y: 1, z: 1 }; let dimensions = ComputeDimensions { x: DICE_WORKGROUP_SIZE, y: 1, z: 1 };
device.set_compute_program_local_size(&mut program, dimensions); device.set_compute_program_local_size(&mut program, dimensions);
@ -257,16 +259,16 @@ impl<D> DiceProgramD3D11<D> where D: Device {
} }
} }
pub struct BoundProgramD3D11<D> where D: Device { pub(crate) struct BoundProgramD3D11<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub path_count_uniform: D::Uniform, pub(crate) path_count_uniform: D::Uniform,
pub tile_count_uniform: D::Uniform, pub(crate) tile_count_uniform: D::Uniform,
pub tile_path_info_storage_buffer: D::StorageBuffer, pub(crate) tile_path_info_storage_buffer: D::StorageBuffer,
pub tiles_storage_buffer: D::StorageBuffer, pub(crate) tiles_storage_buffer: D::StorageBuffer,
} }
impl<D> BoundProgramD3D11<D> where D: Device { impl<D> BoundProgramD3D11<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> BoundProgramD3D11<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> BoundProgramD3D11<D> {
let mut program = device.create_compute_program(resources, "d3d11/bound"); let mut program = device.create_compute_program(resources, "d3d11/bound");
let dimensions = ComputeDimensions { x: BOUND_WORKGROUP_SIZE, y: 1, z: 1 }; let dimensions = ComputeDimensions { x: BOUND_WORKGROUP_SIZE, y: 1, z: 1 };
device.set_compute_program_local_size(&mut program, dimensions); device.set_compute_program_local_size(&mut program, dimensions);
@ -287,16 +289,16 @@ impl<D> BoundProgramD3D11<D> where D: Device {
} }
} }
pub struct SortProgramD3D11<D> where D: Device { pub(crate) struct SortProgramD3D11<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub tile_count_uniform: D::Uniform, pub(crate) tile_count_uniform: D::Uniform,
pub tiles_storage_buffer: D::StorageBuffer, pub(crate) tiles_storage_buffer: D::StorageBuffer,
pub first_tile_map_storage_buffer: D::StorageBuffer, pub(crate) first_tile_map_storage_buffer: D::StorageBuffer,
pub z_buffer_storage_buffer: D::StorageBuffer, pub(crate) z_buffer_storage_buffer: D::StorageBuffer,
} }
impl<D> SortProgramD3D11<D> where D: Device { impl<D> SortProgramD3D11<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> SortProgramD3D11<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> SortProgramD3D11<D> {
let mut program = device.create_compute_program(resources, "d3d11/sort"); let mut program = device.create_compute_program(resources, "d3d11/sort");
let dimensions = ComputeDimensions { x: SORT_WORKGROUP_SIZE, y: 1, z: 1 }; let dimensions = ComputeDimensions { x: SORT_WORKGROUP_SIZE, y: 1, z: 1 };
device.set_compute_program_local_size(&mut program, dimensions); device.set_compute_program_local_size(&mut program, dimensions);

View File

@ -8,5 +8,10 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! A hybrid CPU-GPU renderer that only relies on functionality available in Direct3D 9.
//!
//! This renderer supports OpenGL at least 3.0, OpenGL ES at least 3.0, Metal of any version, and
//! WebGL at least 2.0.
pub mod renderer; pub mod renderer;
pub mod shaders; pub mod shaders;

View File

@ -8,6 +8,11 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! A hybrid CPU-GPU renderer that only relies on functionality available in Direct3D 9.
//!
//! This renderer supports OpenGL at least 3.0, OpenGL ES at least 3.0, Metal of any version, and
//! WebGL at least 2.0.
use crate::gpu::blend::{BlendModeExt, ToBlendState}; use crate::gpu::blend::{BlendModeExt, ToBlendState};
use crate::gpu::perf::TimeCategory; use crate::gpu::perf::TimeCategory;
use crate::gpu::renderer::{FramebufferFlags, MASK_FRAMEBUFFER_HEIGHT, MASK_FRAMEBUFFER_WIDTH}; use crate::gpu::renderer::{FramebufferFlags, MASK_FRAMEBUFFER_HEIGHT, MASK_FRAMEBUFFER_WIDTH};

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Shaders and vertex specifications for the Direct3D 9-level renderer.
use crate::gpu::shaders::{TILE_INSTANCE_SIZE, TileProgramCommon}; use crate::gpu::shaders::{TILE_INSTANCE_SIZE, TileProgramCommon};
use pathfinder_gpu::{BufferTarget, Device, VertexAttrClass, VertexAttrDescriptor, VertexAttrType}; use pathfinder_gpu::{BufferTarget, Device, VertexAttrClass, VertexAttrDescriptor, VertexAttrType};
use pathfinder_resources::ResourceLoader; use pathfinder_resources::ResourceLoader;
@ -15,17 +17,17 @@ use pathfinder_resources::ResourceLoader;
const FILL_INSTANCE_SIZE: usize = 12; const FILL_INSTANCE_SIZE: usize = 12;
const CLIP_TILE_INSTANCE_SIZE: usize = 16; const CLIP_TILE_INSTANCE_SIZE: usize = 16;
pub struct FillVertexArrayD3D9<D> where D: Device { pub(crate) struct FillVertexArrayD3D9<D> where D: Device {
pub vertex_array: D::VertexArray, pub(crate) vertex_array: D::VertexArray,
} }
impl<D> FillVertexArrayD3D9<D> where D: Device { impl<D> FillVertexArrayD3D9<D> where D: Device {
pub fn new(device: &D, pub(crate) fn new(device: &D,
fill_program: &FillProgramD3D9<D>, fill_program: &FillProgramD3D9<D>,
vertex_buffer: &D::Buffer, vertex_buffer: &D::Buffer,
quad_vertex_positions_buffer: &D::Buffer, quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer) quad_vertex_indices_buffer: &D::Buffer)
-> FillVertexArrayD3D9<D> { -> FillVertexArrayD3D9<D> {
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let tess_coord_attr = device.get_vertex_attr(&fill_program.program, "TessCoord").unwrap(); let tess_coord_attr = device.get_vertex_attr(&fill_program.program, "TessCoord").unwrap();
@ -68,17 +70,17 @@ impl<D> FillVertexArrayD3D9<D> where D: Device {
} }
} }
pub struct TileVertexArrayD3D9<D> where D: Device { pub(crate) struct TileVertexArrayD3D9<D> where D: Device {
pub vertex_array: D::VertexArray, pub(crate) vertex_array: D::VertexArray,
} }
impl<D> TileVertexArrayD3D9<D> where D: Device { impl<D> TileVertexArrayD3D9<D> where D: Device {
pub fn new(device: &D, pub(crate) fn new(device: &D,
tile_program: &TileProgramD3D9<D>, tile_program: &TileProgramD3D9<D>,
tile_vertex_buffer: &D::Buffer, tile_vertex_buffer: &D::Buffer,
quad_vertex_positions_buffer: &D::Buffer, quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer) quad_vertex_indices_buffer: &D::Buffer)
-> TileVertexArrayD3D9<D> { -> TileVertexArrayD3D9<D> {
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let tile_offset_attr = let tile_offset_attr =
@ -155,17 +157,17 @@ impl<D> TileVertexArrayD3D9<D> where D: Device {
} }
} }
pub struct ClipTileCopyVertexArrayD3D9<D> where D: Device { pub(crate) struct ClipTileCopyVertexArrayD3D9<D> where D: Device {
pub vertex_array: D::VertexArray, pub(crate) vertex_array: D::VertexArray,
} }
impl<D> ClipTileCopyVertexArrayD3D9<D> where D: Device { impl<D> ClipTileCopyVertexArrayD3D9<D> where D: Device {
pub fn new(device: &D, pub(crate) fn new(device: &D,
clip_tile_copy_program: &ClipTileCopyProgramD3D9<D>, clip_tile_copy_program: &ClipTileCopyProgramD3D9<D>,
vertex_buffer: &D::Buffer, vertex_buffer: &D::Buffer,
quad_vertex_positions_buffer: &D::Buffer, quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer) quad_vertex_indices_buffer: &D::Buffer)
-> ClipTileCopyVertexArrayD3D9<D> { -> ClipTileCopyVertexArrayD3D9<D> {
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let tile_offset_attr = let tile_offset_attr =
@ -199,17 +201,17 @@ impl<D> ClipTileCopyVertexArrayD3D9<D> where D: Device {
} }
} }
pub struct ClipTileCombineVertexArrayD3D9<D> where D: Device { pub(crate) struct ClipTileCombineVertexArrayD3D9<D> where D: Device {
pub vertex_array: D::VertexArray, pub(crate) vertex_array: D::VertexArray,
} }
impl<D> ClipTileCombineVertexArrayD3D9<D> where D: Device { impl<D> ClipTileCombineVertexArrayD3D9<D> where D: Device {
pub fn new(device: &D, pub(crate) fn new(device: &D,
clip_tile_combine_program: &ClipTileCombineProgramD3D9<D>, clip_tile_combine_program: &ClipTileCombineProgramD3D9<D>,
vertex_buffer: &D::Buffer, vertex_buffer: &D::Buffer,
quad_vertex_positions_buffer: &D::Buffer, quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer) quad_vertex_indices_buffer: &D::Buffer)
-> ClipTileCombineVertexArrayD3D9<D> { -> ClipTileCombineVertexArrayD3D9<D> {
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let tile_offset_attr = let tile_offset_attr =
@ -276,16 +278,16 @@ impl<D> ClipTileCombineVertexArrayD3D9<D> where D: Device {
} }
} }
pub struct CopyTileVertexArray<D> where D: Device { pub(crate) struct CopyTileVertexArray<D> where D: Device {
pub vertex_array: D::VertexArray, pub(crate) vertex_array: D::VertexArray,
} }
impl<D> CopyTileVertexArray<D> where D: Device { impl<D> CopyTileVertexArray<D> where D: Device {
pub fn new(device: &D, pub(crate) fn new(device: &D,
copy_tile_program: &CopyTileProgram<D>, copy_tile_program: &CopyTileProgram<D>,
copy_tile_vertex_buffer: &D::Buffer, copy_tile_vertex_buffer: &D::Buffer,
quads_vertex_indices_buffer: &D::Buffer) quads_vertex_indices_buffer: &D::Buffer)
-> CopyTileVertexArray<D> { -> CopyTileVertexArray<D> {
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let tile_position_attr = let tile_position_attr =
@ -307,11 +309,11 @@ impl<D> CopyTileVertexArray<D> where D: Device {
} }
} }
pub struct FillProgramD3D9<D> where D: Device { pub(crate) struct FillProgramD3D9<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub framebuffer_size_uniform: D::Uniform, pub(crate) framebuffer_size_uniform: D::Uniform,
pub tile_size_uniform: D::Uniform, pub(crate) tile_size_uniform: D::Uniform,
pub area_lut_texture: D::TextureParameter, pub(crate) area_lut_texture: D::TextureParameter,
} }
impl<D> FillProgramD3D9<D> where D: Device { impl<D> FillProgramD3D9<D> where D: Device {
@ -329,10 +331,10 @@ impl<D> FillProgramD3D9<D> where D: Device {
} }
} }
pub struct TileProgramD3D9<D> where D: Device { pub(crate) struct TileProgramD3D9<D> where D: Device {
pub common: TileProgramCommon<D>, pub(crate) common: TileProgramCommon<D>,
pub dest_texture: D::TextureParameter, pub(crate) dest_texture: D::TextureParameter,
pub transform_uniform: D::Uniform, pub(crate) transform_uniform: D::Uniform,
} }
impl<D> TileProgramD3D9<D> where D: Device { impl<D> TileProgramD3D9<D> where D: Device {
@ -345,14 +347,15 @@ impl<D> TileProgramD3D9<D> where D: Device {
} }
} }
pub struct ClipTileCombineProgramD3D9<D> where D: Device { pub(crate) struct ClipTileCombineProgramD3D9<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub src_texture: D::TextureParameter, pub(crate) src_texture: D::TextureParameter,
pub framebuffer_size_uniform: D::Uniform, pub(crate) framebuffer_size_uniform: D::Uniform,
} }
impl<D> ClipTileCombineProgramD3D9<D> where D: Device { impl<D> ClipTileCombineProgramD3D9<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ClipTileCombineProgramD3D9<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader)
-> ClipTileCombineProgramD3D9<D> {
let program = device.create_raster_program(resources, "d3d9/tile_clip_combine"); let program = device.create_raster_program(resources, "d3d9/tile_clip_combine");
let src_texture = device.get_texture_parameter(&program, "Src"); let src_texture = device.get_texture_parameter(&program, "Src");
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
@ -360,14 +363,14 @@ impl<D> ClipTileCombineProgramD3D9<D> where D: Device {
} }
} }
pub struct ClipTileCopyProgramD3D9<D> where D: Device { pub(crate) struct ClipTileCopyProgramD3D9<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub src_texture: D::TextureParameter, pub(crate) src_texture: D::TextureParameter,
pub framebuffer_size_uniform: D::Uniform, pub(crate) framebuffer_size_uniform: D::Uniform,
} }
impl<D> ClipTileCopyProgramD3D9<D> where D: Device { impl<D> ClipTileCopyProgramD3D9<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ClipTileCopyProgramD3D9<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ClipTileCopyProgramD3D9<D> {
let program = device.create_raster_program(resources, "d3d9/tile_clip_copy"); let program = device.create_raster_program(resources, "d3d9/tile_clip_copy");
let src_texture = device.get_texture_parameter(&program, "Src"); let src_texture = device.get_texture_parameter(&program, "Src");
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
@ -375,16 +378,16 @@ impl<D> ClipTileCopyProgramD3D9<D> where D: Device {
} }
} }
pub struct CopyTileProgram<D> where D: Device { pub(crate) struct CopyTileProgram<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub transform_uniform: D::Uniform, pub(crate) transform_uniform: D::Uniform,
pub tile_size_uniform: D::Uniform, pub(crate) tile_size_uniform: D::Uniform,
pub framebuffer_size_uniform: D::Uniform, pub(crate) framebuffer_size_uniform: D::Uniform,
pub src_texture: D::TextureParameter, pub(crate) src_texture: D::TextureParameter,
} }
impl<D> CopyTileProgram<D> where D: Device { impl<D> CopyTileProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> CopyTileProgram<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> CopyTileProgram<D> {
let program = device.create_raster_program(resources, "d3d9/tile_copy"); let program = device.create_raster_program(resources, "d3d9/tile_copy");
let transform_uniform = device.get_uniform(&program, "Transform"); let transform_uniform = device.get_uniform(&program, "Transform");
let tile_size_uniform = device.get_uniform(&program, "TileSize"); let tile_size_uniform = device.get_uniform(&program, "TileSize");
@ -400,36 +403,16 @@ impl<D> CopyTileProgram<D> where D: Device {
} }
} }
pub struct D3D9Programs<D> where D: Device { pub(crate) struct ProgramsD3D9<D> where D: Device {
pub fill_program: FillProgramD3D9<D>, pub(crate) fill_program: FillProgramD3D9<D>,
pub tile_program: TileProgramD3D9<D>, pub(crate) tile_program: TileProgramD3D9<D>,
pub tile_clip_combine_program: ClipTileCombineProgramD3D9<D>, pub(crate) tile_clip_copy_program: ClipTileCopyProgramD3D9<D>,
pub tile_clip_copy_program: ClipTileCopyProgramD3D9<D>, pub(crate) tile_clip_combine_program: ClipTileCombineProgramD3D9<D>,
pub tile_copy_program: CopyTileProgram<D>, pub(crate) tile_copy_program: CopyTileProgram<D>,
}
impl<D> D3D9Programs<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> D3D9Programs<D> {
D3D9Programs {
fill_program: FillProgramD3D9::new(device, resources),
tile_program: TileProgramD3D9::new(device, resources),
tile_clip_combine_program: ClipTileCombineProgramD3D9::new(device, resources),
tile_clip_copy_program: ClipTileCopyProgramD3D9::new(device, resources),
tile_copy_program: CopyTileProgram::new(device, resources),
}
}
}
pub struct ProgramsD3D9<D> where D: Device {
pub fill_program: FillProgramD3D9<D>,
pub tile_program: TileProgramD3D9<D>,
pub tile_clip_copy_program: ClipTileCopyProgramD3D9<D>,
pub tile_clip_combine_program: ClipTileCombineProgramD3D9<D>,
pub tile_copy_program: CopyTileProgram<D>,
} }
impl<D> ProgramsD3D9<D> where D: Device { impl<D> ProgramsD3D9<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsD3D9<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsD3D9<D> {
ProgramsD3D9 { ProgramsD3D9 {
fill_program: FillProgramD3D9::new(device, resources), fill_program: FillProgramD3D9::new(device, resources),
tile_program: TileProgramD3D9::new(device, resources), tile_program: TileProgramD3D9::new(device, resources),

View File

@ -39,8 +39,13 @@ const PERFORMANCE_WINDOW_HEIGHT_D3D11: i32 = LINE_HEIGHT * 10 + PADDING + 2;
const INFO_WINDOW_WIDTH: i32 = 425; const INFO_WINDOW_WIDTH: i32 = 425;
const INFO_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 2 + PADDING + 2; const INFO_WINDOW_HEIGHT: i32 = LINE_HEIGHT * 2 + PADDING + 2;
/// Manages the debug UI.
pub struct DebugUIPresenter<D> where D: Device { pub struct DebugUIPresenter<D> where D: Device {
/// The general UI presenter object.
///
/// You can use this to draw your own application-specific debug widgets.
pub ui_presenter: UIPresenter<D>, pub ui_presenter: UIPresenter<D>,
cpu_samples: SampleBuffer<RenderStats>, cpu_samples: SampleBuffer<RenderStats>,
gpu_samples: SampleBuffer<RenderTime>, gpu_samples: SampleBuffer<RenderTime>,
backend_name: &'static str, backend_name: &'static str,
@ -49,11 +54,11 @@ pub struct DebugUIPresenter<D> where D: Device {
} }
impl<D> DebugUIPresenter<D> where D: Device { impl<D> DebugUIPresenter<D> where D: Device {
pub fn new(device: &D, pub(crate) fn new(device: &D,
resources: &dyn ResourceLoader, resources: &dyn ResourceLoader,
framebuffer_size: Vector2I, framebuffer_size: Vector2I,
renderer_level: RendererLevel) renderer_level: RendererLevel)
-> DebugUIPresenter<D> { -> DebugUIPresenter<D> {
let ui_presenter = UIPresenter::new(device, resources, framebuffer_size); let ui_presenter = UIPresenter::new(device, resources, framebuffer_size);
DebugUIPresenter { DebugUIPresenter {
ui_presenter, ui_presenter,
@ -65,19 +70,19 @@ impl<D> DebugUIPresenter<D> where D: Device {
} }
} }
pub fn add_sample(&mut self, stats: RenderStats, rendering_time: RenderTime) { pub(crate) fn add_sample(&mut self, stats: RenderStats, rendering_time: RenderTime) {
self.cpu_samples.push(stats); self.cpu_samples.push(stats);
self.gpu_samples.push(rendering_time); self.gpu_samples.push(rendering_time);
} }
pub fn draw(&self, device: &D, allocator: &mut GPUMemoryAllocator<D>) { pub(crate) fn draw(&self, device: &D, allocator: &mut GPUMemoryAllocator<D>) {
self.draw_stats_window(device, allocator); self.draw_stats_window(device, allocator);
self.draw_performance_window(device, allocator); self.draw_performance_window(device, allocator);
self.draw_info_window(device, allocator); self.draw_info_window(device, allocator);
} }
#[inline] #[inline]
pub fn set_framebuffer_size(&mut self, new_framebuffer_size: Vector2I) { pub(crate) fn set_framebuffer_size(&mut self, new_framebuffer_size: Vector2I) {
self.ui_presenter.set_framebuffer_size(new_framebuffer_size) self.ui_presenter.set_framebuffer_size(new_framebuffer_size)
} }

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! Various options that control how the renderer behaves.
use pathfinder_color::ColorF; use pathfinder_color::ColorF;
use pathfinder_geometry::rect::RectI; use pathfinder_geometry::rect::RectI;
use pathfinder_geometry::vector::Vector2I; use pathfinder_geometry::vector::Vector2I;
@ -57,6 +59,7 @@ impl<D> Default for RendererOptions<D> where D: Device {
} }
impl RendererLevel { impl RendererLevel {
/// Returns a suitable renderer level for the given device.
pub fn default_for_device<D>(device: &D) -> RendererLevel where D: Device { pub fn default_for_device<D>(device: &D) -> RendererLevel where D: Device {
match device.feature_level() { match device.feature_level() {
FeatureLevel::D3D10 => RendererLevel::D3D9, FeatureLevel::D3D10 => RendererLevel::D3D9,
@ -65,12 +68,17 @@ impl RendererLevel {
} }
} }
/// Where the rendered content should go.
#[derive(Clone)] #[derive(Clone)]
pub enum DestFramebuffer<D> where D: Device { pub enum DestFramebuffer<D> where D: Device {
/// The rendered content should go to the default framebuffer (e.g. the window in OpenGL).
Default { Default {
/// The rectangle within the window to draw in, in device pixels.
viewport: RectI, viewport: RectI,
/// The total size of the window in device pixels.
window_size: Vector2I, window_size: Vector2I,
}, },
/// The rendered content should go to a non-default framebuffer (off-screen, typically).
Other(D::Framebuffer), Other(D::Framebuffer),
} }
@ -81,16 +89,18 @@ impl<D> Default for DestFramebuffer<D> where D: Device {
} }
} }
impl<D> DestFramebuffer<D> impl<D> DestFramebuffer<D> where D: Device {
where /// Returns a `DestFramebuffer` object that renders to the entire contents of the default
D: Device, /// framebuffer.
{ ///
/// The `window_size` parameter specifies the size of the window in device pixels.
#[inline] #[inline]
pub fn full_window(window_size: Vector2I) -> DestFramebuffer<D> { pub fn full_window(window_size: Vector2I) -> DestFramebuffer<D> {
let viewport = RectI::new(Vector2I::default(), window_size); let viewport = RectI::new(Vector2I::default(), window_size);
DestFramebuffer::Default { viewport, window_size } DestFramebuffer::Default { viewport, window_size }
} }
/// Returns the size of the destination buffer, in device pixels.
#[inline] #[inline]
pub fn window_size(&self, device: &D) -> Vector2I { pub fn window_size(&self, device: &D) -> Vector2I {
match *self { match *self {

View File

@ -16,15 +16,30 @@ use std::mem;
use std::ops::{Add, Div}; use std::ops::{Add, Div};
use std::time::Duration; use std::time::Duration;
/// Various GPU-side statistics about rendering.
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
pub struct RenderStats { pub struct RenderStats {
/// The total number of path objects in the scene.
pub path_count: usize, pub path_count: usize,
/// The number of fill operations it took to render the scene.
///
/// A fill operation is a single edge in a 16x16 device pixel tile.
pub fill_count: usize, pub fill_count: usize,
/// The total number of 16x16 device pixel tile masks generated.
pub alpha_tile_count: usize, pub alpha_tile_count: usize,
/// The total number of 16x16 tiles needed to render the scene, including both alpha tiles and
/// solid-color tiles.
pub total_tile_count: usize, pub total_tile_count: usize,
/// The amount of CPU time it took to build the scene.
pub cpu_build_time: Duration, pub cpu_build_time: Duration,
/// The number of GPU API draw calls it took to render the scene.
pub drawcall_count: u32, pub drawcall_count: u32,
/// The number of bytes of VRAM Pathfinder has allocated.
///
/// This may be higher than `gpu_bytes_committed` because Pathfinder caches some data for
/// faster reuse.
pub gpu_bytes_allocated: u64, pub gpu_bytes_allocated: u64,
/// The number of bytes of VRAM Pathfinder actually used for the frame.
pub gpu_bytes_committed: u64, pub gpu_bytes_committed: u64,
} }
@ -203,16 +218,28 @@ fn total_time_of_timer_futures<D>(futures: &[TimerFuture<D>]) -> Option<Duration
Some(total) Some(total)
} }
/// The amount of GPU time it took to render the scene, broken up into stages.
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct RenderTime { pub struct RenderTime {
/// How much GPU time it took to divide all edges in the scene into small lines.
///
/// This will be zero in the D3D9-level backend, since in that backend dicing is done on CPU.
pub dice_time: Duration, pub dice_time: Duration,
/// How much GPU time it took to assign those diced microlines to tiles.
///
/// This will be zero in the D3D9-level backend, since in that backend binning is done on CPU.
pub bin_time: Duration, pub bin_time: Duration,
/// How much GPU time it took to draw fills (i.e. render edges) to masks.
pub fill_time: Duration, pub fill_time: Duration,
/// How much GPU time it took to draw the contents of the tiles to the output.
pub composite_time: Duration, pub composite_time: Duration,
/// How much GPU time it took to execute miscellaneous tasks other than dicing, binning,
/// filling, and compositing.
pub other_time: Duration, pub other_time: Duration,
} }
impl RenderTime { impl RenderTime {
/// The total GPU time it took to render the scene.
#[inline] #[inline]
pub fn total_time(&self) -> Duration { pub fn total_time(&self) -> Duration {
self.dice_time + self.bin_time + self.fill_time + self.composite_time + self.other_time self.dice_time + self.bin_time + self.fill_time + self.composite_time + self.other_time

View File

@ -144,6 +144,23 @@ pub(crate) struct MaskStorage {
} }
impl<D> Renderer<D> where D: Device { impl<D> Renderer<D> where D: Device {
/// Creates a new renderer ready to render Pathfinder content.
///
/// Arguments:
///
/// * `device`: The GPU device to render with. This effectively specifies the system GPU API
/// Pathfinder will use (OpenGL, Metal, etc.)
///
/// * `resources`: Where Pathfinder should find shaders, lookup tables, and other data.
/// This is typically either an `EmbeddedResourceLoader` to use resources included in the
/// Pathfinder library or (less commonly) a `FilesystemResourceLoader` to use resources
/// stored in a directory on disk.
///
/// * `mode`: Renderer options that can't be changed after the renderer is created. Most
/// notably, this specifies the API level (D3D9 or D3D11).
///
/// * `options`: Renderer options that can be changed after the renderer is created. Most
/// importantly, this specifies where the output should go (to a window or off-screen).
pub fn new(device: D, pub fn new(device: D,
resources: &dyn ResourceLoader, resources: &dyn ResourceLoader,
mode: RendererMode, mode: RendererMode,
@ -290,10 +307,14 @@ impl<D> Renderer<D> where D: Device {
} }
} }
/// Destroys this renderer and returns the embedded GPU device.
pub fn destroy(self) -> D { pub fn destroy(self) -> D {
self.core.device self.core.device
} }
/// Performs work necessary to begin rendering a scene.
///
/// This must be called before `render_command()`.
pub fn begin_scene(&mut self) { pub fn begin_scene(&mut self) {
self.core.framebuffer_flags = FramebufferFlags::empty(); self.core.framebuffer_flags = FramebufferFlags::empty();
@ -304,6 +325,11 @@ impl<D> Renderer<D> where D: Device {
self.core.alpha_tile_count = 0; self.core.alpha_tile_count = 0;
} }
/// Issues a rendering command to the renderer.
///
/// These commands are generated from methods like `Scene::build()`.
///
/// `begin_scene()` must have been called first.
pub fn render_command(&mut self, command: &RenderCommand) { pub fn render_command(&mut self, command: &RenderCommand) {
debug!("render command: {:?}", command); debug!("render command: {:?}", command);
match *command { match *command {
@ -352,6 +378,13 @@ impl<D> Renderer<D> where D: Device {
} }
} }
/// Finishes rendering a scene.
///
/// `begin_scene()` and all `render_command()` calls must have been issued before calling this
/// method.
///
/// Note that, after calling this method, you might need to flush the output to the screen via
/// `swap_buffers()`, `present()`, or a similar method that your windowing library offers.
pub fn end_scene(&mut self) { pub fn end_scene(&mut self) {
self.clear_dest_framebuffer_if_necessary(); self.clear_dest_framebuffer_if_necessary();
self.blit_intermediate_dest_framebuffer_if_necessary(); self.blit_intermediate_dest_framebuffer_if_necessary();
@ -451,34 +484,69 @@ impl<D> Renderer<D> where D: Device {
self.last_rendering_time = None; self.last_rendering_time = None;
} }
/// Returns GPU timing information for the last frame, if present.
pub fn last_rendering_time(&self) -> Option<RenderTime> { pub fn last_rendering_time(&self) -> Option<RenderTime> {
self.last_rendering_time self.last_rendering_time
} }
/// Returns a reference to the GPU device.
///
/// This can be useful to issue GPU commands manually via the low-level `pathfinder_gpu`
/// abstraction. (Of course, you can also use your platform API such as OpenGL directly
/// alongside Pathfinder.)
#[inline] #[inline]
pub fn device(&self) -> &D { pub fn device(&self) -> &D {
&self.core.device &self.core.device
} }
/// Returns a mutable reference to the GPU device.
///
/// This can be useful to issue GPU commands manually via the low-level `pathfinder_gpu`
/// abstraction. (Of course, you can also use your platform API such as OpenGL directly
/// alongside Pathfinder.)
#[inline] #[inline]
pub fn device_mut(&mut self) -> &mut D { pub fn device_mut(&mut self) -> &mut D {
&mut self.core.device &mut self.core.device
} }
/// Returns the `RendererMode` this renderer was created with.
#[inline] #[inline]
pub fn mode(&self) -> &RendererMode { pub fn mode(&self) -> &RendererMode {
&self.core.mode &self.core.mode
} }
/// Returns the current rendering options.
#[inline] #[inline]
pub fn options(&self) -> &RendererOptions<D> { pub fn options(&self) -> &RendererOptions<D> {
&self.core.options &self.core.options
} }
/// Returns a mutable reference to the current rendering options, allowing them to be changed.
///
/// Among other things, you can use this function to change the destination of rendering
/// output without having to recreate the renderer.
///
/// After changing the destination framebuffer size, you must call
/// `dest_framebuffer_size_changed()`.
pub fn options_mut(&mut self) -> &mut RendererOptions<D> { pub fn options_mut(&mut self) -> &mut RendererOptions<D> {
&mut self.core.options &mut self.core.options
} }
/// Notifies Pathfinder that the size of the output framebuffer has changed.
///
/// You must call this function after changing the `dest_framebuffer` member of
/// `RendererOptions` to a target with a different size.
#[inline]
pub fn dest_framebuffer_size_changed(&mut self) {
let new_framebuffer_size = self.core.main_viewport().size();
if let Some(ref mut debug_ui_presenter) = self.debug_ui_presenter {
debug_ui_presenter.ui_presenter.set_framebuffer_size(new_framebuffer_size);
}
}
/// Returns a mutable reference to the debug UI.
///
/// You can use this function to draw custom debug widgets on screen, as the demo does.
#[inline] #[inline]
pub fn debug_ui_presenter_mut(&mut self) -> DebugUIPresenterInfo<D> { pub fn debug_ui_presenter_mut(&mut self) -> DebugUIPresenterInfo<D> {
DebugUIPresenterInfo { DebugUIPresenterInfo {
@ -488,34 +556,38 @@ impl<D> Renderer<D> where D: Device {
} }
} }
/// Turns off Pathfinder's use of the depth buffer.
#[inline] #[inline]
pub fn dest_framebuffer_size_changed(&mut self) { #[deprecated]
let new_framebuffer_size = self.core.main_viewport().size();
if let Some(ref mut debug_ui_presenter) = self.debug_ui_presenter {
debug_ui_presenter.ui_presenter.set_framebuffer_size(new_framebuffer_size);
}
}
#[inline]
pub fn disable_depth(&mut self) { pub fn disable_depth(&mut self) {
self.core.renderer_flags.remove(RendererFlags::USE_DEPTH); self.core.renderer_flags.remove(RendererFlags::USE_DEPTH);
} }
/// Turns on Pathfinder's use of the depth buffer.
#[inline] #[inline]
#[deprecated]
pub fn enable_depth(&mut self) { pub fn enable_depth(&mut self) {
self.core.renderer_flags.insert(RendererFlags::USE_DEPTH); self.core.renderer_flags.insert(RendererFlags::USE_DEPTH);
} }
/// Returns various GPU-side statistics about rendering, averaged over the last few frames.
#[inline] #[inline]
pub fn stats(&self) -> &RenderStats { pub fn stats(&self) -> &RenderStats {
&self.core.stats &self.core.stats
} }
/// Returns a GPU-side vertex buffer containing 2D vertices of a unit square.
///
/// This can be handy for custom rendering.
#[inline] #[inline]
pub fn quad_vertex_positions_buffer(&self) -> &D::Buffer { pub fn quad_vertex_positions_buffer(&self) -> &D::Buffer {
self.core.allocator.get_general_buffer(self.core.quad_vertex_positions_buffer_id) self.core.allocator.get_general_buffer(self.core.quad_vertex_positions_buffer_id)
} }
/// Returns a GPU-side 32-bit unsigned index buffer of triangles necessary to render a quad
/// with the buffer returned by `quad_vertex_positions_buffer()`.
///
/// This can be handy for custom rendering.
#[inline] #[inline]
pub fn quad_vertex_indices_buffer(&self) -> &D::Buffer { pub fn quad_vertex_indices_buffer(&self) -> &D::Buffer {
self.core.allocator.get_index_buffer(self.core.quad_vertex_indices_buffer_id) self.core.allocator.get_index_buffer(self.core.quad_vertex_indices_buffer_id)
@ -684,6 +756,10 @@ impl<D> Renderer<D> where D: Device {
self.core.stats.drawcall_count += 1; self.core.stats.drawcall_count += 1;
} }
/// Draws a texture that was originally drawn with `old_transform` with `new_transform` by
/// transforming in screen space.
#[deprecated]
pub fn reproject_texture(&mut self, pub fn reproject_texture(&mut self,
texture: &D::Texture, texture: &D::Texture,
old_transform: &Transform4F, old_transform: &Transform4F,
@ -814,21 +890,19 @@ impl<D> Renderer<D> where D: Device {
self.core.stats.drawcall_count += 1; self.core.stats.drawcall_count += 1;
} }
/// Returns the output viewport in the destination framebuffer, as specified in the render
/// options.
#[inline] #[inline]
pub fn draw_viewport(&self) -> RectI { pub fn draw_viewport(&self) -> RectI {
self.core.draw_viewport() self.core.draw_viewport()
} }
/// Returns the destination framebuffer, wrapped in a render target.
#[inline] #[inline]
pub fn draw_render_target(&self) -> RenderTarget<D> { pub fn draw_render_target(&self) -> RenderTarget<D> {
self.core.draw_render_target() self.core.draw_render_target()
} }
#[inline]
pub fn render_stats(&self) -> &RenderStats {
&self.core.stats
}
fn compute_filter_params(&self, fn compute_filter_params(&self,
filter: &Filter, filter: &Filter,
blend_mode: BlendMode, blend_mode: BlendMode,
@ -1085,14 +1159,14 @@ impl<D> RendererCore<D> where D: Device {
} }
} }
pub fn draw_viewport(&self) -> RectI { pub(crate) fn draw_viewport(&self) -> RectI {
match self.render_target_stack.last() { match self.render_target_stack.last() {
Some(&render_target_id) => self.render_target_location(render_target_id).rect, Some(&render_target_id) => self.render_target_location(render_target_id).rect,
None => self.main_viewport(), None => self.main_viewport(),
} }
} }
pub fn draw_render_target(&self) -> RenderTarget<D> { pub(crate) fn draw_render_target(&self) -> RenderTarget<D> {
match self.render_target_stack.last() { match self.render_target_stack.last() {
Some(&render_target_id) => { Some(&render_target_id) => {
let texture_page_id = self.render_target_location(render_target_id).page; let texture_page_id = self.render_target_location(render_target_id).page;
@ -1248,8 +1322,14 @@ pub(crate) struct PatternTexturePage {
pub(crate) must_preserve_contents: bool, pub(crate) must_preserve_contents: bool,
} }
/// A mutable reference to the debug UI presenter.
///
/// You can use this structure to draw custom debug widgets on screen, as the demo does.
pub struct DebugUIPresenterInfo<'a, D> where D: Device { pub struct DebugUIPresenterInfo<'a, D> where D: Device {
/// The GPU device.
pub device: &'a mut D, pub device: &'a mut D,
/// The GPU memory allocator.
pub allocator: &'a mut GPUMemoryAllocator<D>, pub allocator: &'a mut GPUMemoryAllocator<D>,
/// The debug UI presenter, useful for drawing custom debug widgets on screen.
pub debug_ui_presenter: &'a mut DebugUIPresenter<D>, pub debug_ui_presenter: &'a mut DebugUIPresenter<D>,
} }

View File

@ -15,16 +15,16 @@ use pathfinder_resources::ResourceLoader;
// TODO(pcwalton): Replace with `mem::size_of` calls? // TODO(pcwalton): Replace with `mem::size_of` calls?
pub(crate) const TILE_INSTANCE_SIZE: usize = 16; pub(crate) const TILE_INSTANCE_SIZE: usize = 16;
pub struct BlitVertexArray<D> where D: Device { pub(crate) struct BlitVertexArray<D> where D: Device {
pub vertex_array: D::VertexArray, pub(crate) vertex_array: D::VertexArray,
} }
impl<D> BlitVertexArray<D> where D: Device { impl<D> BlitVertexArray<D> where D: Device {
pub fn new(device: &D, pub(crate) fn new(device: &D,
blit_program: &BlitProgram<D>, blit_program: &BlitProgram<D>,
quad_vertex_positions_buffer: &D::Buffer, quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer) quad_vertex_indices_buffer: &D::Buffer)
-> BlitVertexArray<D> { -> BlitVertexArray<D> {
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&blit_program.program, "Position").unwrap(); let position_attr = device.get_vertex_attr(&blit_program.program, "Position").unwrap();
@ -44,12 +44,12 @@ impl<D> BlitVertexArray<D> where D: Device {
} }
} }
pub struct VertexArraysCore<D> where D: Device { pub(crate) struct VertexArraysCore<D> where D: Device {
pub blit_vertex_array: BlitVertexArray<D>, pub(crate) blit_vertex_array: BlitVertexArray<D>,
} }
impl<D> VertexArraysCore<D> where D: Device { impl<D> VertexArraysCore<D> where D: Device {
pub fn new(device: &D, pub(crate) fn new(device: &D,
programs: &ProgramsCore<D>, programs: &ProgramsCore<D>,
quad_vertex_positions_buffer: &D::Buffer, quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer) quad_vertex_indices_buffer: &D::Buffer)
@ -63,16 +63,16 @@ impl<D> VertexArraysCore<D> where D: Device {
} }
} }
pub struct ClearVertexArray<D> where D: Device { pub(crate) struct ClearVertexArray<D> where D: Device {
pub vertex_array: D::VertexArray, pub(crate) vertex_array: D::VertexArray,
} }
impl<D> ClearVertexArray<D> where D: Device { impl<D> ClearVertexArray<D> where D: Device {
pub fn new(device: &D, pub(crate) fn new(device: &D,
clear_program: &ClearProgram<D>, clear_program: &ClearProgram<D>,
quad_vertex_positions_buffer: &D::Buffer, quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_indices_buffer: &D::Buffer) quad_vertex_indices_buffer: &D::Buffer)
-> ClearVertexArray<D> { -> ClearVertexArray<D> {
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&clear_program.program, "Position").unwrap(); let position_attr = device.get_vertex_attr(&clear_program.program, "Position").unwrap();
@ -92,15 +92,15 @@ impl<D> ClearVertexArray<D> where D: Device {
} }
} }
pub struct BlitProgram<D> where D: Device { pub(crate) struct BlitProgram<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub dest_rect_uniform: D::Uniform, pub(crate) dest_rect_uniform: D::Uniform,
pub framebuffer_size_uniform: D::Uniform, pub(crate) framebuffer_size_uniform: D::Uniform,
pub src_texture: D::TextureParameter, pub(crate) src_texture: D::TextureParameter,
} }
impl<D> BlitProgram<D> where D: Device { impl<D> BlitProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> BlitProgram<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> BlitProgram<D> {
let program = device.create_raster_program(resources, "blit"); let program = device.create_raster_program(resources, "blit");
let dest_rect_uniform = device.get_uniform(&program, "DestRect"); let dest_rect_uniform = device.get_uniform(&program, "DestRect");
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
@ -109,27 +109,27 @@ impl<D> BlitProgram<D> where D: Device {
} }
} }
pub struct ProgramsCore<D> where D: Device { pub(crate) struct ProgramsCore<D> where D: Device {
pub blit_program: BlitProgram<D>, pub(crate) blit_program: BlitProgram<D>,
} }
impl<D> ProgramsCore<D> where D: Device { impl<D> ProgramsCore<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsCore<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ProgramsCore<D> {
ProgramsCore { ProgramsCore {
blit_program: BlitProgram::new(device, resources), blit_program: BlitProgram::new(device, resources),
} }
} }
} }
pub struct ClearProgram<D> where D: Device { pub(crate) struct ClearProgram<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub rect_uniform: D::Uniform, pub(crate) rect_uniform: D::Uniform,
pub framebuffer_size_uniform: D::Uniform, pub(crate) framebuffer_size_uniform: D::Uniform,
pub color_uniform: D::Uniform, pub(crate) color_uniform: D::Uniform,
} }
impl<D> ClearProgram<D> where D: Device { impl<D> ClearProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ClearProgram<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ClearProgram<D> {
let program = device.create_raster_program(resources, "clear"); let program = device.create_raster_program(resources, "clear");
let rect_uniform = device.get_uniform(&program, "Rect"); let rect_uniform = device.get_uniform(&program, "Rect");
let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize"); let framebuffer_size_uniform = device.get_uniform(&program, "FramebufferSize");
@ -138,20 +138,20 @@ impl<D> ClearProgram<D> where D: Device {
} }
} }
pub struct TileProgramCommon<D> where D: Device { pub(crate) struct TileProgramCommon<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub tile_size_uniform: D::Uniform, pub(crate) tile_size_uniform: D::Uniform,
pub texture_metadata_texture: D::TextureParameter, pub(crate) texture_metadata_texture: D::TextureParameter,
pub texture_metadata_size_uniform: D::Uniform, pub(crate) texture_metadata_size_uniform: D::Uniform,
pub z_buffer_texture: D::TextureParameter, pub(crate) z_buffer_texture: D::TextureParameter,
pub z_buffer_texture_size_uniform: D::Uniform, pub(crate) z_buffer_texture_size_uniform: D::Uniform,
pub color_texture_0: D::TextureParameter, pub(crate) color_texture_0: D::TextureParameter,
pub color_texture_size_0_uniform: D::Uniform, pub(crate) color_texture_size_0_uniform: D::Uniform,
pub color_texture_1: D::TextureParameter, pub(crate) color_texture_1: D::TextureParameter,
pub mask_texture_0: D::TextureParameter, pub(crate) mask_texture_0: D::TextureParameter,
pub mask_texture_size_0_uniform: D::Uniform, pub(crate) mask_texture_size_0_uniform: D::Uniform,
pub gamma_lut_texture: D::TextureParameter, pub(crate) gamma_lut_texture: D::TextureParameter,
pub framebuffer_size_uniform: D::Uniform, pub(crate) framebuffer_size_uniform: D::Uniform,
} }
impl<D> TileProgramCommon<D> where D: Device { impl<D> TileProgramCommon<D> where D: Device {
@ -187,25 +187,25 @@ impl<D> TileProgramCommon<D> where D: Device {
} }
} }
pub struct StencilProgram<D> where D: Device { pub(crate) struct StencilProgram<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
} }
impl<D> StencilProgram<D> where D: Device { impl<D> StencilProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> StencilProgram<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> StencilProgram<D> {
let program = device.create_raster_program(resources, "stencil"); let program = device.create_raster_program(resources, "stencil");
StencilProgram { program } StencilProgram { program }
} }
} }
pub struct StencilVertexArray<D> where D: Device { pub(crate) struct StencilVertexArray<D> where D: Device {
pub vertex_array: D::VertexArray, pub(crate) vertex_array: D::VertexArray,
pub vertex_buffer: D::Buffer, pub(crate) vertex_buffer: D::Buffer,
pub index_buffer: D::Buffer, pub(crate) index_buffer: D::Buffer,
} }
impl<D> StencilVertexArray<D> where D: Device { impl<D> StencilVertexArray<D> where D: Device {
pub fn new(device: &D, stencil_program: &StencilProgram<D>) -> StencilVertexArray<D> { pub(crate) fn new(device: &D, stencil_program: &StencilProgram<D>) -> StencilVertexArray<D> {
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let vertex_buffer = device.create_buffer(BufferUploadMode::Static); let vertex_buffer = device.create_buffer(BufferUploadMode::Static);
let index_buffer = device.create_buffer(BufferUploadMode::Static); let index_buffer = device.create_buffer(BufferUploadMode::Static);
@ -228,15 +228,15 @@ impl<D> StencilVertexArray<D> where D: Device {
} }
} }
pub struct ReprojectionProgram<D> where D: Device { pub(crate) struct ReprojectionProgram<D> where D: Device {
pub program: D::Program, pub(crate) program: D::Program,
pub old_transform_uniform: D::Uniform, pub(crate) old_transform_uniform: D::Uniform,
pub new_transform_uniform: D::Uniform, pub(crate) new_transform_uniform: D::Uniform,
pub texture: D::TextureParameter, pub(crate) texture: D::TextureParameter,
} }
impl<D> ReprojectionProgram<D> where D: Device { impl<D> ReprojectionProgram<D> where D: Device {
pub fn new(device: &D, resources: &dyn ResourceLoader) -> ReprojectionProgram<D> { pub(crate) fn new(device: &D, resources: &dyn ResourceLoader) -> ReprojectionProgram<D> {
let program = device.create_raster_program(resources, "reproject"); let program = device.create_raster_program(resources, "reproject");
let old_transform_uniform = device.get_uniform(&program, "OldTransform"); let old_transform_uniform = device.get_uniform(&program, "OldTransform");
let new_transform_uniform = device.get_uniform(&program, "NewTransform"); let new_transform_uniform = device.get_uniform(&program, "NewTransform");
@ -245,17 +245,16 @@ impl<D> ReprojectionProgram<D> where D: Device {
} }
} }
pub struct ReprojectionVertexArray<D> where D: Device { pub(crate) struct ReprojectionVertexArray<D> where D: Device {
pub vertex_array: D::VertexArray, pub(crate) vertex_array: D::VertexArray,
} }
impl<D> ReprojectionVertexArray<D> where D: Device { impl<D> ReprojectionVertexArray<D> where D: Device {
pub fn new( pub(crate) fn new(device: &D,
device: &D, reprojection_program: &ReprojectionProgram<D>,
reprojection_program: &ReprojectionProgram<D>, quad_vertex_positions_buffer: &D::Buffer,
quad_vertex_positions_buffer: &D::Buffer, quad_vertex_indices_buffer: &D::Buffer)
quad_vertex_indices_buffer: &D::Buffer, -> ReprojectionVertexArray<D> {
) -> ReprojectionVertexArray<D> {
let vertex_array = device.create_vertex_array(); let vertex_array = device.create_vertex_array();
let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position") let position_attr = device.get_vertex_attr(&reprojection_program.program, "Position")
.unwrap(); .unwrap();

View File

@ -17,13 +17,13 @@ extern crate log;
pub mod concurrent; pub mod concurrent;
pub mod gpu; pub mod gpu;
pub mod gpu_data;
pub mod options; pub mod options;
pub mod paint; pub mod paint;
pub mod scene; pub mod scene;
mod allocator; mod allocator;
mod builder; mod builder;
mod gpu_data;
mod tile_map; mod tile_map;
mod tiler; mod tiler;
mod tiles; mod tiles;

View File

@ -18,20 +18,30 @@ use pathfinder_geometry::transform3d::Perspective;
use pathfinder_geometry::vector::{Vector2F, Vector4F}; use pathfinder_geometry::vector::{Vector2F, Vector4F};
use pathfinder_content::clip::PolygonClipper3D; use pathfinder_content::clip::PolygonClipper3D;
/// A sink for the render commands that scenes build.
///
/// In single-threaded operation, this object typically buffers commands into an array and then,
/// once scene building is complete, commands are all sent to the output at once. In multithreaded
/// operation, on the other hand, commands are sent to the renderer on the fly as they're built.
/// The latter is generally preferable for performance, because it allows the CPU and GPU to run
/// concurrently. However, it requires a multithreaded environment, which may not always be
/// available.
pub struct RenderCommandListener<'a> { pub struct RenderCommandListener<'a> {
send_fn: RenderCommandSendFunction<'a>, send_fn: RenderCommandSendFunction<'a>,
} }
/// The callback function that receives the render commands from the scene builder.
pub type RenderCommandSendFunction<'a> = Box<dyn Fn(RenderCommand) + Send + Sync + 'a>; pub type RenderCommandSendFunction<'a> = Box<dyn Fn(RenderCommand) + Send + Sync + 'a>;
impl<'a> RenderCommandListener<'a> { impl<'a> RenderCommandListener<'a> {
/// Wraps a render command callback in a `RenderCommandListener`.
#[inline] #[inline]
pub fn new(send_fn: RenderCommandSendFunction<'a>) -> RenderCommandListener<'a> { pub fn new(send_fn: RenderCommandSendFunction<'a>) -> RenderCommandListener<'a> {
RenderCommandListener { send_fn } RenderCommandListener { send_fn }
} }
#[inline] #[inline]
pub fn send(&self, render_command: RenderCommand) { pub(crate) fn send(&self, render_command: RenderCommand) {
(self.send_fn)(render_command) (self.send_fn)(render_command)
} }
} }
@ -39,8 +49,12 @@ impl<'a> RenderCommandListener<'a> {
/// Options that influence scene building. /// Options that influence scene building.
#[derive(Clone, Default)] #[derive(Clone, Default)]
pub struct BuildOptions { pub struct BuildOptions {
/// A global transform to be applied to the scene.
pub transform: RenderTransform, pub transform: RenderTransform,
/// Expands outlines by the given number of device pixels. This is useful to perform *stem
/// darkening* for fonts, to mitigate the thinness of gamma-corrected fonts.
pub dilation: Vector2F, pub dilation: Vector2F,
/// True if subpixel antialiasing for LCD screens is to be performed.
pub subpixel_aa_enabled: bool, pub subpixel_aa_enabled: bool,
} }
@ -54,9 +68,12 @@ impl BuildOptions {
} }
} }
/// A global transform to apply to the scene.
#[derive(Clone)] #[derive(Clone)]
pub enum RenderTransform { pub enum RenderTransform {
/// A 2D transform.
Transform2D(Transform2F), Transform2D(Transform2F),
/// A perspective transform. (This will soon be removed in favor of a revised 3D approach.)
Perspective(Perspective), Perspective(Perspective),
} }

View File

@ -34,8 +34,8 @@ use std::sync::Arc;
const GRADIENT_TILE_LENGTH: u32 = 256; const GRADIENT_TILE_LENGTH: u32 = 256;
#[derive(Clone)] #[derive(Clone)]
pub struct Palette { pub(crate) struct Palette {
pub paints: Vec<Paint>, pub(crate) paints: Vec<Paint>,
render_targets: Vec<RenderTargetData>, render_targets: Vec<RenderTargetData>,
cache: HashMap<Paint, PaintId>, cache: HashMap<Paint, PaintId>,
allocator: TextureAllocator, allocator: TextureAllocator,
@ -90,7 +90,7 @@ impl Debug for PaintContents {
impl Palette { impl Palette {
#[inline] #[inline]
pub fn new(scene_id: SceneId) -> Palette { pub(crate) fn new(scene_id: SceneId) -> Palette {
Palette { Palette {
paints: vec![], paints: vec![],
render_targets: vec![], render_targets: vec![],
@ -266,62 +266,62 @@ impl PaintOverlay {
} }
} }
pub struct PaintInfo { pub(crate) struct PaintInfo {
/// The render commands needed to prepare the textures. /// The render commands needed to prepare the textures.
pub render_commands: Vec<RenderCommand>, pub(crate) render_commands: Vec<RenderCommand>,
/// The metadata for each paint. /// The metadata for each paint.
/// ///
/// The indices of this vector are paint IDs. /// The indices of this vector are paint IDs.
pub paint_metadata: Vec<PaintMetadata>, pub(crate) paint_metadata: Vec<PaintMetadata>,
/// The metadata for each render target. /// The metadata for each render target.
/// ///
/// The indices of this vector are render target IDs. /// The indices of this vector are render target IDs.
pub render_target_metadata: Vec<RenderTargetMetadata>, pub(crate) render_target_metadata: Vec<RenderTargetMetadata>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct PaintMetadata { pub(crate) struct PaintMetadata {
/// Metadata associated with the color texture, if applicable. /// Metadata associated with the color texture, if applicable.
pub color_texture_metadata: Option<PaintColorTextureMetadata>, pub(crate) color_texture_metadata: Option<PaintColorTextureMetadata>,
/// The base color that the color texture gets mixed into. /// The base color that the color texture gets mixed into.
pub base_color: ColorU, pub(crate) base_color: ColorU,
pub blend_mode: BlendMode, pub(crate) blend_mode: BlendMode,
/// True if this paint is fully opaque. /// True if this paint is fully opaque.
pub is_opaque: bool, pub(crate) is_opaque: bool,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct PaintColorTextureMetadata { pub(crate) struct PaintColorTextureMetadata {
/// The location of the paint. /// The location of the paint.
pub location: TextureLocation, pub(crate) location: TextureLocation,
/// The scale for the page this paint is on. /// The scale for the page this paint is on.
pub page_scale: Vector2F, pub(crate) page_scale: Vector2F,
/// The transform to apply to screen coordinates to translate them into UVs. /// The transform to apply to screen coordinates to translate them into UVs.
pub transform: Transform2F, pub(crate) transform: Transform2F,
/// The sampling mode for the texture. /// The sampling mode for the texture.
pub sampling_flags: TextureSamplingFlags, pub(crate) sampling_flags: TextureSamplingFlags,
/// The filter to be applied to this paint. /// The filter to be applied to this paint.
pub filter: PaintFilter, pub(crate) filter: PaintFilter,
/// How the color texture is to be composited over the base color. /// How the color texture is to be composited over the base color.
pub composite_op: PaintCompositeOp, pub(crate) composite_op: PaintCompositeOp,
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct RadialGradientMetadata { pub(crate) struct RadialGradientMetadata {
/// The line segment that connects the two circles. /// The line segment that connects the two circles.
pub line: LineSegment2F, pub(crate) line: LineSegment2F,
/// The radii of the two circles. /// The radii of the two circles.
pub radii: F32x2, pub(crate) radii: F32x2,
} }
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct RenderTargetMetadata { pub(crate) struct RenderTargetMetadata {
/// The location of the render target. /// The location of the render target.
pub location: TextureLocation, pub(crate) location: TextureLocation,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum PaintFilter { pub(crate) enum PaintFilter {
None, None,
RadialGradient { RadialGradient {
/// The line segment that connects the two circles. /// The line segment that connects the two circles.
@ -334,7 +334,7 @@ pub enum PaintFilter {
impl Palette { impl Palette {
#[allow(clippy::trivially_copy_pass_by_ref)] #[allow(clippy::trivially_copy_pass_by_ref)]
pub fn push_paint(&mut self, paint: &Paint) -> PaintId { pub(crate) fn push_paint(&mut self, paint: &Paint) -> PaintId {
if let Some(paint_id) = self.cache.get(paint) { if let Some(paint_id) = self.cache.get(paint) {
return *paint_id; return *paint_id;
} }
@ -345,7 +345,7 @@ impl Palette {
paint_id paint_id
} }
pub fn push_render_target(&mut self, render_target: RenderTarget) -> RenderTargetId { pub(crate) fn push_render_target(&mut self, render_target: RenderTarget) -> RenderTargetId {
let id = self.render_targets.len() as u32; let id = self.render_targets.len() as u32;
let metadata = RenderTargetMetadata { let metadata = RenderTargetMetadata {
@ -356,7 +356,7 @@ impl Palette {
RenderTargetId { scene: self.scene_id.0, render_target: id } RenderTargetId { scene: self.scene_id.0, render_target: id }
} }
pub fn build_paint_info(&mut self, render_transform: Transform2F) -> PaintInfo { pub(crate) fn build_paint_info(&mut self, render_transform: Transform2F) -> PaintInfo {
let mut paint_metadata = vec![]; let mut paint_metadata = vec![];
// Assign paint locations. // Assign paint locations.

View File

@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
//! A set of paths to be rendered. //! The vector scene to be rendered.
use crate::builder::SceneBuilder; use crate::builder::SceneBuilder;
use crate::concurrent::executor::Executor; use crate::concurrent::executor::Executor;
@ -34,6 +34,7 @@ use std::u64;
static NEXT_SCENE_ID: AtomicUsize = AtomicUsize::new(0); static NEXT_SCENE_ID: AtomicUsize = AtomicUsize::new(0);
/// The vector scene to be rendered.
#[derive(Clone)] #[derive(Clone)]
pub struct Scene { pub struct Scene {
display_list: Vec<DisplayItem>, display_list: Vec<DisplayItem>,
@ -156,7 +157,7 @@ impl Scene {
} }
#[inline] #[inline]
pub fn build_paint_info(&mut self, render_transform: Transform2F) -> PaintInfo { pub(crate) fn build_paint_info(&mut self, render_transform: Transform2F) -> PaintInfo {
self.palette.build_paint_info(render_transform) self.palette.build_paint_info(render_transform)
} }
@ -281,8 +282,8 @@ impl Scene {
} }
#[inline] #[inline]
pub fn palette(&self) -> &Palette { pub fn get_paint(&self, paint_id: PaintId) -> &Paint {
&self.palette self.palette.paints.get(paint_id.0 as usize).expect("No paint with that ID!")
} }
#[inline] #[inline]