Try to optimize

This commit is contained in:
Michael Pfaff 2024-06-22 16:58:25 -04:00
parent 5fa9e8f883
commit ca750dda7b
13 changed files with 557 additions and 380 deletions

View File

@ -4,6 +4,9 @@ version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"] authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018" edition = "2018"
[features]
metal = ["dep:core-foundation", "dep:io-surface", "dep:metal", "dep:pathfinder_metal"]
[lib] [lib]
crate-type = ["staticlib", "cdylib"] crate-type = ["staticlib", "cdylib"]
name = "pathfinder" name = "pathfinder"
@ -51,10 +54,18 @@ path = "../simd"
[dependencies.pathfinder_svg] [dependencies.pathfinder_svg]
path = "../svg" path = "../svg"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies.core-foundation]
core-foundation = "0.6" version = "0.6"
io-surface = "0.12" optional = true
metal = "0.18"
[target.'cfg(target_os = "macos")'.dependencies.io-surface]
version = "0.12"
optional = true
[target.'cfg(target_os = "macos")'.dependencies.metal]
version = "0.18"
optional = true
[target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal] [target.'cfg(target_os = "macos")'.dependencies.pathfinder_metal]
path = "../metal" path = "../metal"
optional = true

File diff suppressed because it is too large Load Diff

View File

@ -78,10 +78,8 @@ pub struct Canvas {
impl Canvas { impl Canvas {
#[inline] #[inline]
pub fn new(size: Vector2F) -> Canvas { pub fn new() -> Canvas {
let mut scene = Scene::new(); Canvas::from_scene(Scene::new())
scene.set_view_box(RectF::new(Vector2F::zero(), size));
Canvas::from_scene(scene)
} }
#[inline] #[inline]
@ -130,10 +128,10 @@ impl Canvas {
self.scene.view_box().size().ceil().to_i32() self.scene.view_box().size().ceil().to_i32()
} }
pub fn set_size(&mut self, new_size: Vector2I) { /// This resets the canvas' bounds. Do not call this mid-draw.
let new_view_box = RectI::new(Vector2I::default(), new_size).to_f32(); pub fn set_size(&mut self, new_size: Vector2F) {
self.scene.set_bounds(new_view_box); self.scene.set_bounds(RectF::default());
self.scene.set_view_box(new_view_box); self.scene.set_view_box(RectF::new(Vector2F::zero(), new_size));
} }
} }

View File

@ -10,7 +10,7 @@
use crate::{CanvasRenderingContext2D, State, TextAlign, TextBaseline}; use crate::{CanvasRenderingContext2D, State, TextAlign, TextBaseline};
use font_kit::canvas::RasterizationOptions; use font_kit::canvas::RasterizationOptions;
use font_kit::error::{FontLoadingError, SelectionError}; use font_kit::error::{GlyphLoadingError, FontLoadingError, SelectionError};
use font_kit::family_name::FamilyName; use font_kit::family_name::FamilyName;
use font_kit::handle::Handle; use font_kit::handle::Handle;
use font_kit::hinting::HintingOptions; use font_kit::hinting::HintingOptions;
@ -36,10 +36,10 @@ impl CanvasRenderingContext2D {
/// fill the text that you passed into `measure_text()` with the layout-related style /// fill the text that you passed into `measure_text()` with the layout-related style
/// properties set at the time you called that function. This allows Pathfinder to skip having /// properties set at the time you called that function. This allows Pathfinder to skip having
/// to lay out the text again. /// to lay out the text again.
pub fn fill_text<T>(&mut self, text: &T, position: Vector2F) where T: ToTextLayout + ?Sized { pub fn fill_text<T>(&mut self, text: &T, position: Vector2F) -> Result<(), GlyphLoadingError> where T: ToTextLayout + ?Sized {
let paint = self.current_state.resolve_paint(&self.current_state.fill_paint); let paint = self.current_state.resolve_paint(&self.current_state.fill_paint);
let paint_id = self.canvas.scene.push_paint(&paint); let paint_id = self.canvas.scene.push_paint(&paint);
self.fill_or_stroke_text(text, position, paint_id, TextRenderMode::Fill); self.fill_or_stroke_text(text, position, paint_id, TextRenderMode::Fill)
} }
/// Strokes the given text using the current style. /// Strokes the given text using the current style.
@ -48,11 +48,11 @@ impl CanvasRenderingContext2D {
/// stroke the text that you passed into `measure_text()` with the layout-related style /// stroke the text that you passed into `measure_text()` with the layout-related style
/// properties set at the time you called that function. This allows Pathfinder to skip having /// properties set at the time you called that function. This allows Pathfinder to skip having
/// to lay out the text again. /// to lay out the text again.
pub fn stroke_text<T>(&mut self, text: &T, position: Vector2F) where T: ToTextLayout + ?Sized { pub fn stroke_text<T>(&mut self, text: &T, position: Vector2F) -> Result<(), GlyphLoadingError> where T: ToTextLayout + ?Sized {
let paint = self.current_state.resolve_paint(&self.current_state.stroke_paint); let paint = self.current_state.resolve_paint(&self.current_state.stroke_paint);
let paint_id = self.canvas.scene.push_paint(&paint); let paint_id = self.canvas.scene.push_paint(&paint);
let render_mode = TextRenderMode::Stroke(self.current_state.resolve_stroke_style()); let render_mode = TextRenderMode::Stroke(self.current_state.resolve_stroke_style());
self.fill_or_stroke_text(text, position, paint_id, render_mode); self.fill_or_stroke_text(text, position, paint_id, render_mode)
} }
/// Returns metrics of the given text using the current style. /// Returns metrics of the given text using the current style.
@ -68,7 +68,7 @@ impl CanvasRenderingContext2D {
text: &T, text: &T,
mut position: Vector2F, mut position: Vector2F,
paint_id: PaintId, paint_id: PaintId,
render_mode: TextRenderMode) render_mode: TextRenderMode) -> Result<(), GlyphLoadingError>
where T: ToTextLayout + ?Sized { where T: ToTextLayout + ?Sized {
let layout = text.layout(CanvasState(&self.current_state)); let layout = text.layout(CanvasState(&self.current_state));
@ -78,8 +78,7 @@ impl CanvasRenderingContext2D {
position += layout.text_origin(); position += layout.text_origin();
let transform = self.current_state.transform * Transform2F::from_translation(position); let transform = self.current_state.transform * Transform2F::from_translation(position);
// TODO(pcwalton): Report errors. self.canvas_font_context
drop(self.canvas_font_context
.0 .0
.borrow_mut() .borrow_mut()
.font_context .font_context
@ -93,7 +92,9 @@ impl CanvasRenderingContext2D {
clip_path, clip_path,
blend_mode, blend_mode,
paint_id, paint_id,
})); })?;
Ok(())
} }
// Text styles // Text styles

View File

@ -12,7 +12,7 @@ egl = "0.2"
log = "0.4" log = "0.4"
smallvec = "1.2" smallvec = "1.2"
glutin = { version = "0.23", optional = true } glutin = { version = "0.23", optional = true }
crossbeam-channel = "0.4" flume = { version = "0.11", default-features = false, features = ["eventual-fairness"] }
[lib] [lib]
crate-type = ["cdylib"] crate-type = ["cdylib"]

View File

@ -66,8 +66,8 @@ mod magicleap;
mod mocked_c_api; mod mocked_c_api;
struct ImmersiveApp { struct ImmersiveApp {
sender: crossbeam_channel::Sender<Event>, sender: flume::Sender<Event>,
receiver: crossbeam_channel::Receiver<Event>, receiver: flume::Receiver<Event>,
demo: DemoApp<MagicLeapWindow>, demo: DemoApp<MagicLeapWindow>,
} }
@ -96,7 +96,7 @@ pub extern "C" fn magicleap_pathfinder_demo_init(egl_display: EGLDisplay, egl_co
let demo = DemoApp::new(window, window_size, options); let demo = DemoApp::new(window, window_size, options);
info!("Initialized app"); info!("Initialized app");
let (sender, receiver) = crossbeam_channel::unbounded(); let (sender, receiver) = flume::unbounded();
Box::into_raw(Box::new(ImmersiveApp { sender, receiver, demo })) as *mut c_void Box::into_raw(Box::new(ImmersiveApp { sender, receiver, demo })) as *mut c_void
} }

View File

@ -785,7 +785,7 @@ impl Device for GLDevice {
} }
fn end_commands(&self) { fn end_commands(&self) {
unsafe { gl::Flush(); } //unsafe { gl::Flush(); }
} }
fn draw_arrays(&self, index_count: u32, render_state: &RenderState<Self>) { fn draw_arrays(&self, index_count: u32, render_state: &RenderState<Self>) {

View File

@ -12,7 +12,7 @@ homepage = "https://github.com/servo/pathfinder"
bitflags = "1.0" bitflags = "1.0"
byte-slice-cast = "0.3" byte-slice-cast = "0.3"
byteorder = "1.2" byteorder = "1.2"
crossbeam-channel = "0.4" flume = { version = "0.11", default-features = false, features = ["eventual-fairness"] }
fxhash = "0.2" fxhash = "0.2"
half = "1.5" half = "1.5"
hashbrown = "0.7" hashbrown = "0.7"

View File

@ -25,7 +25,7 @@ use crate::gpu::renderer::Renderer;
use crate::gpu_data::RenderCommand; use crate::gpu_data::RenderCommand;
use crate::options::{BuildOptions, RenderCommandListener}; use crate::options::{BuildOptions, RenderCommandListener};
use crate::scene::{Scene, SceneSink}; use crate::scene::{Scene, SceneSink};
use crossbeam_channel::{self, Receiver, Sender}; use flume::{self, Receiver, Sender};
use pathfinder_geometry::rect::RectF; use pathfinder_geometry::rect::RectF;
use pathfinder_gpu::Device; use pathfinder_gpu::Device;
use std::thread; use std::thread;
@ -60,9 +60,9 @@ impl SceneProxy {
-> SceneProxy -> SceneProxy
where E: Executor + Send + 'static { where E: Executor + Send + 'static {
let (main_to_worker_sender, main_to_worker_receiver) = let (main_to_worker_sender, main_to_worker_receiver) =
crossbeam_channel::bounded(MAX_MESSAGES_IN_FLIGHT); flume::bounded(MAX_MESSAGES_IN_FLIGHT);
let (worker_to_main_sender, worker_to_main_receiver) = let (worker_to_main_sender, worker_to_main_receiver) =
crossbeam_channel::bounded(MAX_MESSAGES_IN_FLIGHT); flume::bounded(MAX_MESSAGES_IN_FLIGHT);
let listener = RenderCommandListener::new(Box::new(move |command| { let listener = RenderCommandListener::new(Box::new(move |command| {
drop(worker_to_main_sender.send(command)) drop(worker_to_main_sender.send(command))
})); }));
@ -122,7 +122,7 @@ impl SceneProxy {
/// Returns a copy of the wrapped scene. /// 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) = flume::bounded(MAX_MESSAGES_IN_FLIGHT);
self.sender.send(MainToWorkerMsg::CopyScene(sender)).unwrap(); self.sender.send(MainToWorkerMsg::CopyScene(sender)).unwrap();
receiver.recv().unwrap() receiver.recv().unwrap()
} }

View File

@ -646,7 +646,7 @@ impl<D> Renderer<D> where D: Device {
location: TextureLocation { page: TexturePageId(!0), rect: RectI::default() }, location: TextureLocation { page: TexturePageId(!0), rect: RectI::default() },
}); });
} }
let mut render_target = let render_target =
&mut self.core.render_targets[render_target_id.render_target as usize]; &mut self.core.render_targets[render_target_id.render_target as usize];
debug_assert_eq!(render_target.location.page, TexturePageId(!0)); debug_assert_eq!(render_target.location.page, TexturePageId(!0));
render_target.location = location; render_target.location = location;

View File

@ -49,7 +49,8 @@ impl<'a> RenderCommandListener<'a> {
} }
/// Options that influence scene building. /// Options that influence scene building.
#[derive(Clone, Default)] #[derive(Clone, Copy, Default)]
#[repr(C)]
pub struct BuildOptions { pub struct BuildOptions {
/// A global transform to be applied to the scene. /// A global transform to be applied to the scene.
pub transform: RenderTransform, pub transform: RenderTransform,
@ -71,7 +72,7 @@ impl BuildOptions {
} }
/// A global transform to apply to the scene. /// A global transform to apply to the scene.
#[derive(Clone)] #[derive(Clone, Copy)]
pub enum RenderTransform { pub enum RenderTransform {
/// A 2D transform. /// A 2D transform.
Transform2D(Transform2F), Transform2D(Transform2F),

View File

@ -587,7 +587,7 @@ impl Palette {
texture_manager: &mut PaintTextureManager, texture_manager: &mut PaintTextureManager,
render_transform: Transform2F) { render_transform: Transform2F) {
for (paint, metadata) in self.paints.iter().zip(paint_metadata.iter_mut()) { for (paint, metadata) in self.paints.iter().zip(paint_metadata.iter_mut()) {
let mut color_texture_metadata = match metadata.color_texture_metadata { let color_texture_metadata = match metadata.color_texture_metadata {
None => continue, None => continue,
Some(ref mut color_texture_metadata) => color_texture_metadata, Some(ref mut color_texture_metadata) => color_texture_metadata,
}; };
@ -843,7 +843,7 @@ impl GradientTileBuilder {
}) })
} }
let mut data = self.tiles.last_mut().unwrap(); let data = self.tiles.last_mut().unwrap();
let location = TextureLocation { let location = TextureLocation {
page: data.page, page: data.page,
rect: RectI::new(vec2i(0, data.next_index as i32), rect: RectI::new(vec2i(0, data.next_index as i32),

View File

@ -34,6 +34,8 @@ use std::u64;
static NEXT_SCENE_ID: AtomicUsize = AtomicUsize::new(0); static NEXT_SCENE_ID: AtomicUsize = AtomicUsize::new(0);
const MAX_MESSAGES_IN_FLIGHT: usize = 1024;
/// The vector scene to be rendered. /// The vector scene to be rendered.
#[derive(Clone)] #[derive(Clone)]
pub struct Scene { pub struct Scene {
@ -370,11 +372,29 @@ impl Scene {
renderer: &mut Renderer<D>, renderer: &mut Renderer<D>,
build_options: BuildOptions, build_options: BuildOptions,
executor: E) executor: E)
where D: Device, E: Executor { where D: Device, E: Executor + Send {
let commands = self.build_into_vector(renderer, build_options, executor); std::thread::scope(move |scope| {
renderer.begin_scene(); let (tx, rx) = flume::bounded(MAX_MESSAGES_IN_FLIGHT);
commands.into_iter().for_each(|command| renderer.render_command(&command));
renderer.end_scene(); let level = renderer.mode().level;
// TODO: avoid this auxiliary thread
scope.spawn(move || {
let listener = RenderCommandListener::new(Box::new(move |command| {
tx.send(command).unwrap()
}));
let mut sink = SceneSink::new(listener, level);
self.build(build_options, &mut sink, &executor);
});
renderer.begin_scene();
for command in rx {
renderer.render_command(&command);
}
renderer.end_scene();
});
} }
} }