// pathfinder/renderer/src/z_buffer.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. //! Software occlusion culling. use crate::gpu_data::{BuiltObject, SolidTileScenePrimitive}; use crate::scene; use crate::tiles; use euclid::Rect; use pathfinder_geometry::basic::rect::RectF32; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; pub struct ZBuffer { buffer: Vec, tile_rect: Rect, } impl ZBuffer { pub fn new(view_box: RectF32) -> ZBuffer { let tile_rect = tiles::round_rect_out_to_tile_bounds(view_box); let tile_area = tile_rect.size.width as usize * tile_rect.size.height as usize; ZBuffer { buffer: (0..tile_area).map(|_| AtomicUsize::new(0)).collect(), tile_rect, } } pub fn test(&self, scene_tile_index: u32, object_index: u32) -> bool { let existing_depth = self.buffer[scene_tile_index as usize].load(AtomicOrdering::SeqCst); existing_depth < object_index as usize + 1 } pub fn update(&self, tile_x: i16, tile_y: i16, object_index: u16) { let scene_tile_index = scene::scene_tile_index(tile_x, tile_y, self.tile_rect) as usize; let mut old_depth = self.buffer[scene_tile_index].load(AtomicOrdering::SeqCst); let new_depth = (object_index + 1) as usize; while old_depth < new_depth { let prev_depth = self.buffer[scene_tile_index].compare_and_swap( old_depth, new_depth, AtomicOrdering::SeqCst, ); if prev_depth == old_depth { // Successfully written. return; } old_depth = prev_depth; } } pub fn build_solid_tiles( &self, objects: &[BuiltObject], tile_rect: &Rect, ) -> Vec { let mut solid_tiles = vec![]; for scene_tile_y in 0..tile_rect.size.height { for scene_tile_x in 0..tile_rect.size.width { let scene_tile_index = scene_tile_y as usize * tile_rect.size.width as usize + scene_tile_x as usize; let depth = self.buffer[scene_tile_index].load(AtomicOrdering::Relaxed); if depth == 0 { continue; } let object_index = (depth - 1) as usize; solid_tiles.push(SolidTileScenePrimitive { tile_x: scene_tile_x + tile_rect.origin.x, tile_y: scene_tile_y + tile_rect.origin.y, shader: objects[object_index].shader, }); } } solid_tiles } }