Skip to content

Commit

Permalink
📀 Make wgpu an optional dependency
Browse files Browse the repository at this point in the history
Jasper-Bekkers committed Sep 11, 2023
1 parent 2a35227 commit bb456c3
Showing 7 changed files with 62 additions and 14 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -23,6 +23,8 @@ jobs:
- run: cargo check --workspace
# Check vello (the default crate) without the features used by `with_winit` for debugging
- run: cargo check
# Check vello (the default crate) without wgpu
- run: cargo check --no-default-features
# --exclude with_bevy # for when bevy has an outdated wgpu version
# -Dwarnings # for when we have fixed unused code warnings

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -37,14 +37,15 @@ edition.workspace = true
repository.workspace = true

[features]
default = ["wgpu"]
hot_reload = []
buffer_labels = []

[dependencies]
bytemuck = { workspace = true }
fello = { workspace = true }
peniko = { workspace = true }
wgpu = { workspace = true }
wgpu = { workspace = true, optional = true }
raw-window-handle = "0.5"
futures-intrusive = "0.5.0"
vello_encoding = { path = "crates/encoding" }
@@ -54,7 +55,9 @@ wgpu-profiler = { workspace = true, optional = true }
bytemuck = { version = "1.12.1", features = ["derive"] }
fello = { git = "https://github.com/dfrg/fount", rev = "dadbcf75695f035ca46766bfd60555d05bd421b1" }
peniko = { git = "https://github.com/linebender/peniko", rev = "cafdac9a211a0fb2fec5656bd663d1ac770bcc81" }
wgpu = "0.17" # NOTE: Make sure to keep this in sync with the version badge in README.md

# NOTE: Make sure to keep this in sync with the version badge in README.md
wgpu = { version = "0.17" }


# Used for examples
34 changes: 25 additions & 9 deletions src/engine.rs
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ use std::{
sync::atomic::{AtomicU64, Ordering},
};

#[cfg(feature = "wgpu")]
use wgpu::{
BindGroup, BindGroupLayout, Buffer, BufferUsages, CommandEncoderDescriptor, ComputePipeline,
Device, Queue, Texture, TextureAspect, TextureUsages, TextureView, TextureViewDimension,
@@ -29,20 +30,22 @@ use wgpu::{
pub type Error = Box<dyn std::error::Error>;

#[derive(Clone, Copy)]
pub struct ShaderId(usize);
pub struct ShaderId(pub usize);

#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct Id(NonZeroU64);
pub struct Id(pub NonZeroU64);

static ID_COUNTER: AtomicU64 = AtomicU64::new(0);

#[cfg(feature = "wgpu")]
pub struct Engine {
shaders: Vec<Shader>,
pool: ResourcePool,
bind_map: BindMap,
downloads: HashMap<Id, Buffer>,
}

#[cfg(feature = "wgpu")]
struct Shader {
pipeline: ComputePipeline,
bind_group_layout: BindGroupLayout,
@@ -56,9 +59,9 @@ pub struct Recording {

#[derive(Clone, Copy)]
pub struct BufProxy {
size: u64,
id: Id,
name: &'static str,
pub size: u64,
pub id: Id,
pub name: &'static str,
}

#[derive(Copy, Clone, PartialEq, Eq)]
@@ -70,10 +73,10 @@ pub enum ImageFormat {

#[derive(Clone, Copy)]
pub struct ImageProxy {
width: u32,
height: u32,
format: ImageFormat,
id: Id,
pub width: u32,
pub height: u32,
pub format: ImageFormat,
pub id: Id,
}

#[derive(Clone, Copy)]
@@ -82,6 +85,7 @@ pub enum ResourceProxy {
Image(ImageProxy),
}

#[cfg(feature = "wgpu")]
pub enum ExternalResource<'a> {
#[allow(unused)]
Buf(BufProxy, &'a Buffer),
@@ -119,19 +123,22 @@ pub enum BindType {
// TODO: Uniform, Sampler, maybe others
}

#[cfg(feature = "wgpu")]
struct BindMapBuffer {
buffer: Buffer,
#[cfg_attr(not(feature = "buffer_labels"), allow(unused))]
label: &'static str,
}

#[derive(Default)]
#[cfg(feature = "wgpu")]
struct BindMap {
buf_map: HashMap<Id, BindMapBuffer>,
image_map: HashMap<Id, (Texture, TextureView)>,
}

#[derive(Hash, PartialEq, Eq)]
#[cfg(feature = "wgpu")]
struct BufferProperties {
size: u64,
usages: BufferUsages,
@@ -140,10 +147,12 @@ struct BufferProperties {
}

#[derive(Default)]
#[cfg(feature = "wgpu")]
struct ResourcePool {
bufs: HashMap<BufferProperties, Vec<Buffer>>,
}

#[cfg(feature = "wgpu")]
impl Engine {
pub fn new() -> Engine {
Engine {
@@ -534,6 +543,10 @@ impl Recording {
ResourceProxy::Image(image) => self.free_image(image),
}
}

pub fn into_commands(self) -> Vec<Command> {
self.commands
}
}

impl BufProxy {
@@ -548,6 +561,7 @@ impl BufProxy {
}

impl ImageFormat {
#[cfg(feature = "wgpu")]
pub fn to_wgpu(self) -> wgpu::TextureFormat {
match self {
Self::Rgba8 => wgpu::TextureFormat::Rgba8Unorm,
@@ -612,6 +626,7 @@ impl Id {
}
}

#[cfg(feature = "wgpu")]
impl BindMap {
fn insert_buf(&mut self, proxy: &BufProxy, buffer: Buffer) {
self.buf_map.insert(
@@ -810,6 +825,7 @@ impl BindMap {

const SIZE_CLASS_BITS: u32 = 1;

#[cfg(feature = "wgpu")]
impl ResourcePool {
/// Get a buffer from the pool or create one.
fn get_buf(
19 changes: 17 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -28,17 +28,25 @@ pub use peniko::kurbo;
pub use fello;

pub mod glyph;

#[cfg(feature = "wgpu")]
pub mod util;

use render::Render;
pub use render::Render;
pub use scene::{DrawGlyphs, Scene, SceneBuilder, SceneFragment};
#[cfg(feature = "wgpu")]
pub use util::block_on_wgpu;

use engine::{Engine, ExternalResource, Recording};
pub use engine::{
BufProxy, Command, Id, ImageFormat, ImageProxy, Recording, ResourceProxy, ShaderId,
};
#[cfg(feature = "wgpu")]
use engine::{Engine, ExternalResource};
use shaders::FullShaders;

/// Temporary export, used in with_winit for stats
pub use vello_encoding::BumpAllocators;
#[cfg(feature = "wgpu")]
use wgpu::{Device, Queue, SurfaceTexture, TextureFormat, TextureView};
#[cfg(feature = "wgpu-profiler")]
use wgpu_profiler::GpuProfiler;
@@ -50,6 +58,7 @@ pub type Error = Box<dyn std::error::Error>;
pub type Result<T> = std::result::Result<T, Error>;

/// Renders a scene into a texture or surface.
#[cfg(feature = "wgpu")]
pub struct Renderer {
engine: Engine,
shaders: FullShaders,
@@ -72,6 +81,7 @@ pub struct RenderParams {
pub height: u32,
}

#[cfg(feature = "wgpu")]
pub struct RendererOptions {
/// The format of the texture used for surfaces with this renderer/device
/// If None, the renderer cannot be used with surfaces
@@ -81,6 +91,7 @@ pub struct RendererOptions {
pub timestamp_period: f32,
}

#[cfg(feature = "wgpu")]
impl Renderer {
/// Creates a new renderer for the specified device.
pub fn new(device: &Device, render_options: &RendererOptions) -> Result<Self> {
@@ -351,12 +362,14 @@ impl Renderer {
}
}

#[cfg(feature = "wgpu")]
struct TargetTexture {
view: TextureView,
width: u32,
height: u32,
}

#[cfg(feature = "wgpu")]
impl TargetTexture {
pub fn new(device: &Device, width: u32, height: u32) -> Self {
let texture = device.create_texture(&wgpu::TextureDescriptor {
@@ -382,11 +395,13 @@ impl TargetTexture {
}
}

#[cfg(feature = "wgpu")]
struct BlitPipeline {
bind_layout: wgpu::BindGroupLayout,
pipeline: wgpu::RenderPipeline,
}

#[cfg(feature = "wgpu")]
impl BlitPipeline {
fn new(device: &Device, format: TextureFormat) -> Self {
const SHADERS: &str = r#"
6 changes: 6 additions & 0 deletions src/render.rs
Original file line number Diff line number Diff line change
@@ -51,6 +51,12 @@ pub fn render_encoding_full(
(recording, out_image.into())
}

impl Default for Render {
fn default() -> Self {
Self::new()
}
}

impl Render {
pub fn new() -> Self {
Render {
7 changes: 6 additions & 1 deletion src/shaders.rs
Original file line number Diff line number Diff line change
@@ -20,9 +20,13 @@ mod preprocess;

use std::collections::HashSet;

#[cfg(feature = "wgpu")]
use wgpu::Device;

use crate::engine::{BindType, Engine, Error, ImageFormat, ShaderId};
#[cfg(feature = "wgpu")]
use crate::engine::{BindType, Engine, Error, ImageFormat};

use crate::engine::ShaderId;

macro_rules! shader {
($name:expr) => {&{
@@ -71,6 +75,7 @@ pub struct FullShaders {
pub fine: ShaderId,
}

#[cfg(feature = "wgpu")]
pub fn full_shaders(device: &Device, engine: &mut Engine) -> Result<FullShaders, Error> {
let imports = SHARED_SHADERS
.iter()
1 change: 1 addition & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -175,6 +175,7 @@ impl std::task::Wake for NullWake {
/// Block on a future, polling the device as needed.
///
/// This will deadlock if the future is awaiting anything other than GPU progress.
#[cfg(feature = "wgpu")]
pub fn block_on_wgpu<F: Future>(device: &Device, mut fut: F) -> F::Output {
let waker = std::task::Waker::from(std::sync::Arc::new(NullWake));
let mut context = std::task::Context::from_waker(&waker);

0 comments on commit bb456c3

Please sign in to comment.