Skip to content

Commit

Permalink
Merge pull request #360 from linebender/indirect
Browse files Browse the repository at this point in the history
Add indirect dispatch and CPU shaders
  • Loading branch information
raphlinus authored Sep 19, 2023
2 parents d4192ec + 00f1966 commit 56753e0
Show file tree
Hide file tree
Showing 9 changed files with 540 additions and 190 deletions.
1 change: 1 addition & 0 deletions examples/headless/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ async fn render(mut scenes: SceneSet, index: usize, args: &Args) -> Result<()> {
&RendererOptions {
surface_format: None,
timestamp_period: queue.get_timestamp_period(),
use_cpu: false,
},
)
.or_else(|_| bail!("Got non-Send/Sync error from creating renderer"))?;
Expand Down
1 change: 1 addition & 0 deletions examples/with_winit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ console_error_panic_hook = "0.1.7"
console_log = "1"
wasm-bindgen-futures = "0.4.33"
web-sys = { version = "0.3.60", features = [ "HtmlCollection", "Text" ] }
getrandom = { version = "0.2.10", features = ["js"] }
6 changes: 6 additions & 0 deletions examples/with_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ struct Args {
scene: Option<i32>,
#[command(flatten)]
args: scenes::Arguments,
#[arg(long)]
/// Whether to use CPU shaders
use_cpu: bool,
}

struct RenderState {
Expand All @@ -70,6 +73,7 @@ fn run(
let mut render_cx = render_cx;
#[cfg(not(target_arch = "wasm32"))]
let mut render_state = None::<RenderState>;
let use_cpu = args.use_cpu;
// The design of `RenderContext` forces delayed renderer initialisation to
// not work on wasm, as WASM futures effectively must be 'static.
// Otherwise, this could work by sending the result to event_loop.proxy
Expand All @@ -84,6 +88,7 @@ fn run(
&RendererOptions {
surface_format: Some(render_state.surface.format),
timestamp_period: render_cx.devices[id].queue.get_timestamp_period(),
use_cpu: use_cpu,
},
)
.expect("Could create renderer"),
Expand Down Expand Up @@ -492,6 +497,7 @@ fn run(
timestamp_period: render_cx.devices[id]
.queue
.get_timestamp_period(),
use_cpu,
},
)
.expect("Could create renderer")
Expand Down
72 changes: 72 additions & 0 deletions src/cpu_dispatch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright 2023 The Vello authors
// SPDX-License-Identifier: Apache-2.0 OR MIT

//! Support for CPU implementations of compute shaders.

use std::{
cell::{RefCell, RefMut},
ops::Deref,
};

#[derive(Clone, Copy)]
pub enum CpuBinding<'a> {
Buffer(&'a [u8]),
BufferRW(&'a RefCell<Vec<u8>>),
#[allow(unused)]
Texture(&'a CpuTexture),
}

pub enum CpuBufGuard<'a> {
Slice(&'a [u8]),
Interior(RefMut<'a, Vec<u8>>),
}

impl<'a> Deref for CpuBufGuard<'a> {
type Target = [u8];

fn deref(&self) -> &Self::Target {
match self {
CpuBufGuard::Slice(s) => s,
CpuBufGuard::Interior(r) => r,
}
}
}

impl<'a> CpuBufGuard<'a> {
/// Get a mutable reference to the buffer.
///
/// Panics if the underlying resource is read-only.
pub fn as_mut(&mut self) -> &mut [u8] {
match self {
CpuBufGuard::Interior(r) => &mut *r,
_ => panic!("tried to borrow immutable buffer as mutable"),
}
}
}

impl<'a> CpuBinding<'a> {
pub fn as_buf(&self) -> CpuBufGuard {
match self {
CpuBinding::Buffer(b) => CpuBufGuard::Slice(b),
CpuBinding::BufferRW(b) => CpuBufGuard::Interior(b.borrow_mut()),
_ => panic!("resource type mismatch"),
}
}

// TODO: same guard as buf to make mutable
#[allow(unused)]
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>,
}
8 changes: 8 additions & 0 deletions src/cpu_shader/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// Copyright 2023 The Vello authors
// SPDX-License-Identifier: Apache-2.0 OR MIT

//! CPU implementations of shader stages.

mod pathtag_reduce;

pub use pathtag_reduce::pathtag_reduce;
35 changes: 35 additions & 0 deletions src/cpu_shader/pathtag_reduce.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2023 The Vello authors
// SPDX-License-Identifier: Apache-2.0 OR MIT

use vello_encoding::{ConfigUniform, Monoid, PathMonoid};

use crate::cpu_dispatch::CpuBinding;

const WG_SIZE: usize = 256;

fn pathtag_reduce_main(
n_wg: u32,
config: &ConfigUniform,
scene: &[u32],
reduced: &mut [PathMonoid],
) {
let pathtag_base = config.layout.path_tag_base;
for i in 0..n_wg {
let mut m = PathMonoid::default();
for j in 0..WG_SIZE {
let tag = scene[(pathtag_base + i * WG_SIZE as u32) as usize + j];
m = m.combine(&PathMonoid::new(tag));
}
reduced[i as usize] = m;
}
}

pub fn pathtag_reduce(n_wg: u32, resources: &[CpuBinding]) {
let r0 = resources[0].as_buf();
let r1 = resources[1].as_buf();
let mut r2 = resources[2].as_buf();
let config = bytemuck::from_bytes(&r0);
let scene = bytemuck::cast_slice(&r1);
let reduced = bytemuck::cast_slice_mut(r2.as_mut());
pathtag_reduce_main(n_wg, config, scene, reduced);
}
Loading

0 comments on commit 56753e0

Please sign in to comment.