// pathfinder/renderer/src/builder.rs // // Copyright © 2019 The Pathfinder Project Developers. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Packs data onto the GPU. use crate::concurrent::executor::Executor; use crate::gpu_data::{AlphaTileBatchPrimitive, RenderCommand}; use crate::options::{PreparedRenderOptions, RenderCommandListener}; use crate::scene::Scene; use crate::tiles::Tiler; use crate::z_buffer::ZBuffer; use pathfinder_geometry::basic::rect::RectF32; use std::sync::atomic::AtomicUsize; use std::time::Instant; use std::u16; pub struct SceneBuilder<'a> { scene: &'a Scene, built_options: &'a PreparedRenderOptions, pub(crate) next_alpha_tile_index: AtomicUsize, pub(crate) z_buffer: ZBuffer, pub(crate) listener: Box, } impl<'a> SceneBuilder<'a> { pub fn new( scene: &'a Scene, built_options: &'a PreparedRenderOptions, listener: Box, ) -> SceneBuilder<'a> { let effective_view_box = scene.effective_view_box(built_options); SceneBuilder { scene, built_options, next_alpha_tile_index: AtomicUsize::new(0), z_buffer: ZBuffer::new(effective_view_box), listener, } } pub fn build(&mut self, executor: &E) where E: Executor { let start_time = Instant::now(); let bounding_quad = self.built_options.bounding_quad(); let object_count = self.scene.objects.len(); self.listener.send(RenderCommand::Start { bounding_quad, object_count }); self.listener.send(RenderCommand::AddShaders(self.scene.build_shaders())); let effective_view_box = self.scene.effective_view_box(self.built_options); let alpha_tiles = executor.flatten_into_vector(object_count, |object_index| { self.build_object(object_index, effective_view_box, &self.built_options, &self.scene) }); self.finish_building(alpha_tiles); let build_time = Instant::now() - start_time; self.listener.send(RenderCommand::Finish { build_time }); } fn build_object( &self, object_index: usize, view_box: RectF32, built_options: &PreparedRenderOptions, scene: &Scene, ) -> Vec { let object = &scene.objects[object_index]; let outline = scene.apply_render_options(object.outline(), built_options); let mut tiler = Tiler::new(self, &outline, view_box, object_index as u16); tiler.generate_tiles(); self.listener.send(RenderCommand::AddFills(tiler.built_object.fills)); tiler.built_object.alpha_tiles } fn cull_alpha_tiles(&self, alpha_tiles: &mut Vec) { for alpha_tile in alpha_tiles { let alpha_tile_coords = alpha_tile.tile_coords(); if self .z_buffer .test(alpha_tile_coords, alpha_tile.object_index as u32) { continue; } // FIXME(pcwalton): Clean this up. alpha_tile.tile_x_lo = 0xff; alpha_tile.tile_y_lo = 0xff; alpha_tile.tile_hi = 0xff; } } fn pack_alpha_tiles(&mut self, alpha_tiles: Vec) { let object_count = self.scene.objects.len() as u32; let solid_tiles = self.z_buffer.build_solid_tiles(0..object_count); if !solid_tiles.is_empty() { self.listener.send(RenderCommand::SolidTile(solid_tiles)); } if !alpha_tiles.is_empty() { self.listener.send(RenderCommand::AlphaTile(alpha_tiles)); } } fn finish_building(&mut self, mut alpha_tiles: Vec) { self.listener.send(RenderCommand::FlushFills); self.cull_alpha_tiles(&mut alpha_tiles); self.pack_alpha_tiles(alpha_tiles); } } #[derive(Clone, Copy, Debug, Default)] pub struct TileStats { pub solid_tile_count: u32, pub alpha_tile_count: u32, }