| // Copyright 2023 the Vello Authors | |
| // SPDX-License-Identifier: Apache-2.0 OR MIT | |
| //! Support for CPU implementations of compute shaders. | |
| //! | |
| //! Note that while this CPU implementation is useful for testing and debugging, | |
| //! a full CPU fallback as an alternative to GPU shaders is not provided. | |
| // Allow un-idiomatic Rust to more closely match shaders | |
| #![expect( | |
| clippy::needless_range_loop, | |
| reason = "Keeps code easily comparable to GPU shaders" | |
| )] | |
| mod backdrop; | |
| mod bbox_clear; | |
| mod binning; | |
| mod clip_leaf; | |
| mod clip_reduce; | |
| mod coarse; | |
| mod draw_leaf; | |
| mod draw_reduce; | |
| mod euler; | |
| mod fine; | |
| mod flatten; | |
| mod path_count; | |
| mod path_count_setup; | |
| mod path_tiling; | |
| mod path_tiling_setup; | |
| mod pathtag_reduce; | |
| mod pathtag_scan; | |
| mod tile_alloc; | |
| mod util; | |
| pub use backdrop::backdrop; | |
| pub use bbox_clear::bbox_clear; | |
| pub use binning::binning; | |
| pub use clip_leaf::clip_leaf; | |
| pub use clip_reduce::clip_reduce; | |
| pub use coarse::coarse; | |
| pub use draw_leaf::draw_leaf; | |
| pub use draw_reduce::draw_reduce; | |
| pub use flatten::flatten; | |
| pub use path_count::path_count; | |
| pub use path_count_setup::path_count_setup; | |
| pub use path_tiling::path_tiling; | |
| pub use path_tiling_setup::path_tiling_setup; | |
| pub use pathtag_reduce::pathtag_reduce; | |
| pub use pathtag_scan::pathtag_scan; | |
| pub use tile_alloc::tile_alloc; | |
| use std::cell::{Ref, RefCell, RefMut}; | |
| use std::ops::{Deref, DerefMut}; | |
| use bytemuck::Pod; | |
| #[derive(Clone, Copy)] | |
| pub enum CpuBinding<'a> { | |
| Buffer(&'a [u8]), | |
| BufferRW(&'a RefCell<Vec<u8>>), | |
| Texture(&'a CpuTexture), | |
| } | |
| pub enum TypedBufGuard<'a, T: ?Sized> { | |
| Slice(&'a T), | |
| Interior(Ref<'a, T>), | |
| } | |
| pub enum TypedBufGuardMut<'a, T: ?Sized> { | |
| Slice(&'a mut T), | |
| Interior(RefMut<'a, T>), | |
| } | |
| impl<T: ?Sized> Deref for TypedBufGuard<'_, T> { | |
| type Target = T; | |
| fn deref(&self) -> &Self::Target { | |
| match self { | |
| TypedBufGuard::Slice(s) => s, | |
| TypedBufGuard::Interior(r) => r, | |
| } | |
| } | |
| } | |
| impl<T: ?Sized> Deref for TypedBufGuardMut<'_, T> { | |
| type Target = T; | |
| fn deref(&self) -> &Self::Target { | |
| match self { | |
| TypedBufGuardMut::Slice(s) => s, | |
| TypedBufGuardMut::Interior(r) => r, | |
| } | |
| } | |
| } | |
| impl<T: ?Sized> DerefMut for TypedBufGuardMut<'_, T> { | |
| fn deref_mut(&mut self) -> &mut Self::Target { | |
| match self { | |
| TypedBufGuardMut::Slice(s) => s, | |
| TypedBufGuardMut::Interior(r) => r, | |
| } | |
| } | |
| } | |
| impl CpuBinding<'_> { | |
| pub fn as_typed<T: Pod>(&self) -> TypedBufGuard<'_, T> { | |
| match self { | |
| CpuBinding::Buffer(b) => TypedBufGuard::Slice(bytemuck::from_bytes(b)), | |
| CpuBinding::BufferRW(b) => { | |
| TypedBufGuard::Interior(Ref::map(b.borrow(), |buf| bytemuck::from_bytes(buf))) | |
| } | |
| _ => panic!("resource type mismatch"), | |
| } | |
| } | |
| pub fn as_typed_mut<T: Pod>(&self) -> TypedBufGuardMut<'_, T> { | |
| match self { | |
| CpuBinding::Buffer(_) => panic!("can't borrow external buffer mutably"), | |
| CpuBinding::BufferRW(b) => { | |
| TypedBufGuardMut::Interior(RefMut::map(b.borrow_mut(), |buf| { | |
| bytemuck::from_bytes_mut(buf) | |
| })) | |
| } | |
| _ => panic!("resource type mismatch"), | |
| } | |
| } | |
| pub fn as_slice<T: Pod>(&self) -> TypedBufGuard<'_, [T]> { | |
| match self { | |
| CpuBinding::Buffer(b) => TypedBufGuard::Slice(bytemuck::cast_slice(b)), | |
| CpuBinding::BufferRW(b) => { | |
| TypedBufGuard::Interior(Ref::map(b.borrow(), |buf| bytemuck::cast_slice(buf))) | |
| } | |
| _ => panic!("resource type mismatch"), | |
| } | |
| } | |
| pub fn as_slice_mut<T: Pod>(&self) -> TypedBufGuardMut<'_, [T]> { | |
| match self { | |
| CpuBinding::Buffer(_) => panic!("can't borrow external buffer mutably"), | |
| CpuBinding::BufferRW(b) => { | |
| TypedBufGuardMut::Interior(RefMut::map(b.borrow_mut(), |buf| { | |
| bytemuck::cast_slice_mut(buf) | |
| })) | |
| } | |
| _ => panic!("resource type mismatch"), | |
| } | |
| } | |
| // TODO: same guard as buf to make mutable | |
| pub fn as_tex(&self) -> &CpuTexture { | |
| match self { | |
| CpuBinding::Texture(t) => t, | |
| _ => panic!("resource type mismatch"), | |
| } | |
| } | |
| } | |
| /// Structure used for binding textures to CPU shaders. | |
| pub struct CpuTexture { | |
| pub width: usize, | |
| pub height: usize, | |
| // In RGBA format. May expand in the future. | |
| pub pixels: Vec<u32>, | |
| } | |
| // Common internal definitions | |
| const PTCL_INITIAL_ALLOC: u32 = 64; | |
| // Tags for PTCL commands | |
| const CMD_END: u32 = 0; | |
| const CMD_FILL: u32 = 1; | |
| //const CMD_STROKE: u32 = 2; | |
| const CMD_SOLID: u32 = 3; | |
| const CMD_COLOR: u32 = 5; | |
| const CMD_LIN_GRAD: u32 = 6; | |
| const CMD_RAD_GRAD: u32 = 7; | |
| const CMD_SWEEP_GRAD: u32 = 8; | |
| const CMD_IMAGE: u32 = 9; | |
| const CMD_BEGIN_CLIP: u32 = 10; | |
| const CMD_END_CLIP: u32 = 11; | |
| const CMD_JUMP: u32 = 12; | |
| const CMD_BLUR_RECT: u32 = 13; | |
| // The following are computed in draw_leaf from the generic gradient parameters | |
| // encoded in the scene, and stored in the gradient's info struct, for | |
| // consumption during fine rasterization. | |
| // Radial gradient kinds | |
| const RAD_GRAD_KIND_CIRCULAR: u32 = 1; | |
| const RAD_GRAD_KIND_STRIP: u32 = 2; | |
| const RAD_GRAD_KIND_FOCAL_ON_CIRCLE: u32 = 3; | |
| const RAD_GRAD_KIND_CONE: u32 = 4; | |
| // Radial gradient flags | |
| const RAD_GRAD_SWAPPED: u32 = 1; |