Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion desktop/src/render/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub(crate) struct RenderState {
impl RenderState {
pub(crate) fn new(window: &Window, context: WgpuContext, present_mode: Option<PresentMode>) -> Self {
let size = window.surface_size();
let surface = window.create_surface(context.instance.clone());
let surface = window.create_surface(&context.instance);

let surface_caps = surface.get_capabilities(&context.adapter);
let surface_format = surface_caps.formats.iter().find(|f| f.is_srgb()).copied().unwrap_or(surface_caps.formats[0]);
Expand Down
2 changes: 1 addition & 1 deletion desktop/src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ impl Window {
self.winit_window.request_redraw();
}

pub(crate) fn create_surface(&self, instance: Arc<wgpu::Instance>) -> wgpu::Surface<'static> {
pub(crate) fn create_surface(&self, instance: &wgpu::Instance) -> wgpu::Surface<'static> {
instance.create_surface(self.winit_window.clone()).unwrap()
}

Expand Down
2 changes: 1 addition & 1 deletion node-graph/graph-craft/src/application_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub use graphene_application_io::ApplicationIo;
#[derive(Default)]
pub struct PlatformApplicationIo {
#[cfg(feature = "wgpu")]
pub(crate) gpu_executor: Option<WgpuExecutor>,
gpu_executor: Option<WgpuExecutor>,
resources: Option<Box<dyn resource::LoadResource>>,
}

Expand Down
2 changes: 1 addition & 1 deletion node-graph/graphene-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ async fn main() -> Result<(), Box<dyn Error>> {

// Get reference to wgpu executor and clone device handle
let wgpu_executor_ref = application_io_arc.gpu_executor().unwrap();
let device = wgpu_executor_ref.context.device.clone();
let device = wgpu_executor_ref.context().device.clone();

let preferences = EditorPreferences {
max_render_region_size: EditorPreferences::default().max_render_region_size,
Expand Down
4 changes: 4 additions & 0 deletions node-graph/interpreted-executor/src/node_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => ListDyn, Context => graphene_std::ContextFeatures]),
#[cfg(target_family = "wasm")]
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => CanvasHandle, Context => graphene_std::ContextFeatures]),
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => wgpu_executor::WgpuPipelineCache, Context => graphene_std::ContextFeatures]),
async_node!(graphene_core::context_modification::ContextModificationNode<_, _>, input: Context, fn_params: [Context => &wgpu_executor::WgpuExecutor, Context => graphene_std::ContextFeatures]),
// ==========
// MEMO NODES
// ==========
Expand Down Expand Up @@ -286,6 +288,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => graphene_std::transform::ScaleType]),
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::InterpolationDistribution]),
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => RenderIntermediate]),
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => wgpu_executor::WgpuPipelineCache]),
async_node!(graphene_core::memo::MemoizeNode<_, _>, input: Context, fn_params: [Context => &wgpu_executor::WgpuExecutor]),
];
// =============
// CONVERT NODES
Expand Down
34 changes: 15 additions & 19 deletions node-graph/interpreted-executor/src/util.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use graph_craft::ProtoNodeIdentifier;
use graph_craft::application_io::PlatformEditorApi;
use graph_craft::concrete;
use graph_craft::document::value::TaggedValue;
Expand All @@ -8,7 +7,6 @@ use graphene_std::Context;
use graphene_std::ContextFeatures;
use graphene_std::uuid::NodeId;
use std::sync::Arc;
use wgpu_executor::WgpuExecutor;

pub fn wrap_network_in_scope(network: NodeNetwork, editor_api: Arc<PlatformEditorApi>) -> NodeNetwork {
let inner_network = DocumentNode {
Expand Down Expand Up @@ -40,7 +38,7 @@ pub fn wrap_network_in_scope(network: NodeNetwork, editor_api: Arc<PlatformEdito
},
DocumentNode {
call_argument: concrete!(Context),
inputs: vec![NodeInput::scope("editor-api"), NodeInput::node(NodeId(0), 0)],
inputs: vec![NodeInput::scope(graphene_std::platform_application_io::wgpu_executor::IDENTIFIER), NodeInput::node(NodeId(0), 0)],
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::render::IDENTIFIER),
context_features: graphene_std::ContextDependencies {
extract: ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
Expand All @@ -50,7 +48,11 @@ pub fn wrap_network_in_scope(network: NodeNetwork, editor_api: Arc<PlatformEdito
},
DocumentNode {
call_argument: concrete!(Context),
inputs: vec![NodeInput::scope("editor-api"), NodeInput::node(NodeId(1), 0)],
inputs: vec![
NodeInput::scope(graphene_std::platform_application_io::wgpu_executor::IDENTIFIER),
NodeInput::scope("editor-api"),
NodeInput::node(NodeId(1), 0),
],
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_cache::render_output_cache::IDENTIFIER),
context_features: graphene_std::ContextDependencies {
extract: ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
Expand All @@ -60,8 +62,8 @@ pub fn wrap_network_in_scope(network: NodeNetwork, editor_api: Arc<PlatformEdito
},
DocumentNode {
call_argument: concrete!(Context),
inputs: vec![NodeInput::scope("editor-api"), NodeInput::node(NodeId(2), 0)],
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::pixel_preview::pixel_preview::IDENTIFIER),
inputs: vec![NodeInput::scope(graphene_std::render_pixel_preview::pixel_preview_pipeline::IDENTIFIER), NodeInput::node(NodeId(2), 0)],
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_pixel_preview::render_pixel_preview::IDENTIFIER),
context_features: graphene_std::ContextDependencies {
extract: ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
inject: ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
Expand All @@ -70,8 +72,11 @@ pub fn wrap_network_in_scope(network: NodeNetwork, editor_api: Arc<PlatformEdito
},
DocumentNode {
call_argument: concrete!(Context),
inputs: vec![NodeInput::scope("editor-api"), NodeInput::node(NodeId(3), 0)],
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_node::render_background::IDENTIFIER),
inputs: vec![
NodeInput::scope(graphene_std::render_background::background_compositor_pipeline::IDENTIFIER),
NodeInput::node(NodeId(3), 0),
],
implementation: DocumentNodeImplementation::ProtoNode(graphene_std::render_background::render_background::IDENTIFIER),
context_features: graphene_std::ContextDependencies {
extract: ContextFeatures::FOOTPRINT | ContextFeatures::VARARGS,
inject: ContextFeatures::empty(),
Expand Down Expand Up @@ -100,7 +105,7 @@ pub fn wrap_network_in_scope(network: NodeNetwork, editor_api: Arc<PlatformEdito
};

// wrap the inner network in a scope
let mut nodes = vec![
let nodes = vec![
inner_network,
render_node,
DocumentNode {
Expand All @@ -109,16 +114,7 @@ pub fn wrap_network_in_scope(network: NodeNetwork, editor_api: Arc<PlatformEdito
..Default::default()
},
];
let mut scope_injections = vec![("editor-api".to_string(), (NodeId(2), concrete!(&PlatformEditorApi)))];

if cfg!(feature = "gpu") {
nodes.push(DocumentNode {
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<&WgpuExecutor>")),
inputs: vec![NodeInput::node(NodeId(2), 0)],
..Default::default()
});
scope_injections.push(("wgpu-executor".to_string(), (NodeId(3), concrete!(&WgpuExecutor))));
}
let scope_injections = vec![("editor-api".to_string(), (NodeId(2), concrete!(&PlatformEditorApi)))];

NodeNetwork {
exports: vec![NodeInput::node(NodeId(1), 0)],
Expand Down
12 changes: 7 additions & 5 deletions node-graph/libraries/canvas-utils/src/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl CanvasSurfaceHandle {
if self.1.is_none() {
let canvas = self.0.get().canvas.clone();
let surface = executor
.context
.context()
.instance
.create_surface(wgpu::SurfaceTarget::Canvas(canvas))
.expect("Failed to create surface from canvas");
Expand All @@ -86,21 +86,23 @@ impl Canvas for CanvasSurfaceHandle {
#[cfg(feature = "wgpu")]
impl CanvasSurface for CanvasSurfaceHandle {
fn present(&mut self, image_texture: &ImageTexture, executor: &WgpuExecutor) {
let context = executor.context();

let source_texture: &wgpu::Texture = image_texture.as_ref();

let surface = self.surface(executor);

// Blit the texture to the surface
let mut encoder = executor.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
let mut encoder = context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Texture to Surface Blit"),
});

let size = source_texture.size();

// Configure the surface at physical resolution (for HiDPI displays)
let surface_caps = surface.get_capabilities(&executor.context.adapter);
let surface_caps = surface.get_capabilities(&context.adapter);
surface.configure(
&executor.context.device,
&context.device,
&wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST,
format: wgpu::TextureFormat::Rgba8Unorm,
Expand Down Expand Up @@ -134,7 +136,7 @@ impl CanvasSurface for CanvasSurfaceHandle {
source_texture.size(),
);

executor.context.queue.submit([encoder.finish()]);
context.queue.submit([encoder.finish()]);
surface_texture.present();
}
}
Expand Down
6 changes: 6 additions & 0 deletions node-graph/libraries/core-types/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,12 @@ impl ProtoNodeIdentifier {
}
}

impl From<ProtoNodeIdentifier> for Cow<'static, str> {
fn from(val: ProtoNodeIdentifier) -> Self {
val.name
}
}

impl Display for ProtoNodeIdentifier {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("ProtoNodeIdentifier").field(&self.name).finish()
Expand Down
23 changes: 6 additions & 17 deletions node-graph/libraries/wgpu-executor/src/context.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
use std::sync::Arc;
use wgpu::{Adapter, Backends, Device, Features, Instance, Queue};

#[derive(Debug, Clone)]
pub struct Context {
pub device: Arc<Device>,
pub queue: Arc<Queue>,
pub instance: Arc<Instance>,
pub adapter: Arc<Adapter>,
pub device: Device,
pub queue: Queue,
pub instance: Instance,
pub adapter: Adapter,
}

impl Context {
Expand Down Expand Up @@ -58,12 +57,7 @@ impl ContextBuilder {
let instance = self.build_instance();
let adapter = self.request_adapter(&instance).await?;
let (device, queue) = self.request_device(&adapter).await?;
Some(Context {
device: Arc::new(device),
queue: Arc::new(queue),
adapter: Arc::new(adapter),
instance: Arc::new(instance),
})
Some(Context { device, queue, adapter, instance })
}
}
impl ContextBuilder {
Expand Down Expand Up @@ -113,12 +107,7 @@ impl ContextBuilder {
let adapter = if let Some(adapter) = selected_adapter { adapter } else { self.request_adapter(&instance).await? };

let (device, queue) = self.request_device(&adapter).await?;
Some(Context {
device: Arc::new(device),
queue: Arc::new(queue),
adapter: Arc::new(adapter),
instance: Arc::new(instance),
})
Some(Context { device, queue, adapter, instance })
}
async fn select_adapter<S>(&self, instance: &Instance, select: S) -> Option<Adapter>
where
Expand Down
68 changes: 35 additions & 33 deletions node-graph/libraries/wgpu-executor/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,46 +1,59 @@
mod background; // TODO: Think about where to place this. Likely inlined in the node. Requires refactor of wgpu pipline usage.
mod context;
mod resample;
mod pipeline;
pub mod shader_runtime;
mod texture_cache;
pub mod texture_conversion;

use std::sync::Arc;

use crate::background::BackgroundCompositor;
use crate::resample::Resampler;
use crate::shader_runtime::ShaderRuntime;
use crate::texture_cache::TextureCache;
use anyhow::Result;
use core_types::Color;
use core_types::color::SRGBA8;
use futures::lock::Mutex;
use glam::{Affine2, UVec2};
use glam::UVec2;
use graphene_application_io::{ApplicationIo, EditorApi};
use vello::{AaConfig, AaSupport, RenderParams, Renderer, RendererOptions, Scene};
use wgpu::{Origin3d, TextureAspect};

pub use context::Context as WgpuContext;
pub use context::ContextBuilder as WgpuContextBuilder;
pub use pipeline::AsyncPipeline as AsyncWgpuPipeline;
pub use pipeline::Pipeline as WgpuPipeline;
pub use pipeline::PipelineCache as WgpuPipelineCache;
pub use rendering::RenderContext;
pub use wgpu::Backends as WgpuBackends;
pub use wgpu::Features as WgpuFeatures;

const TEXTURE_CACHE_SIZE: u64 = 256 * 1024 * 1024; // 256 MiB

#[derive(dyn_any::DynAny)]
#[derive(dyn_any::DynAny, Clone)]
pub struct WgpuExecutor {
pub context: WgpuContext,
inner: Arc<WgpuExecutorInner>,
}

impl WgpuExecutor {
pub fn context(&self) -> &WgpuContext {
&self.inner.context
}

pub fn shader_runtime(&self) -> &ShaderRuntime {
&self.inner.shader_runtime
}
}

#[derive(dyn_any::DynAny)]
pub struct WgpuExecutorInner {
context: WgpuContext,
texture_cache: Mutex<TextureCache>,
vello_renderer: Mutex<Renderer>,
resampler: Resampler,
background_compositor: BackgroundCompositor,
pub shader_runtime: ShaderRuntime,
shader_runtime: ShaderRuntime,
}

impl std::fmt::Debug for WgpuExecutor {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("WgpuExecutor").field("context", &self.context).finish()
f.debug_struct("WgpuExecutor").field("context", &self.context()).finish()
}
}

Expand All @@ -65,7 +78,7 @@ impl WgpuExecutor {
};

{
let mut renderer = self.vello_renderer.lock().await;
let mut renderer = self.inner.vello_renderer.lock().await;
for (image_brush, texture) in context.resource_overrides.iter() {
let texture_view = wgpu::TexelCopyTextureInfoBase {
texture: texture.clone(),
Expand All @@ -75,7 +88,7 @@ impl WgpuExecutor {
};
renderer.override_image(&image_brush.image, Some(texture_view));
}
renderer.render_to_texture(&self.context.device, &self.context.queue, scene, &texture_view, &render_params)?;
renderer.render_to_texture(&self.context().device, &self.context().queue, scene, &texture_view, &render_params)?;
for (image_brush, _) in context.resource_overrides.iter() {
renderer.override_image(&image_brush.image, None);
}
Expand All @@ -84,21 +97,12 @@ impl WgpuExecutor {
Ok(texture)
}

pub async fn resample_texture(&self, source: &wgpu::Texture, size: UVec2, transform: &glam::DAffine2) -> Arc<wgpu::Texture> {
let out = self.request_texture(size).await;
self.resampler.resample(&self.context, source, transform, &out);
out
}

pub async fn composite_background(&self, foreground: &wgpu::Texture, backgrounds: &[rendering::Background], document_to_screen: Affine2, zoom: f32) -> Arc<wgpu::Texture> {
let size = foreground.size();
let output = self.request_texture(UVec2::new(size.width, size.height)).await;
self.background_compositor.composite(&self.context, foreground, &output, backgrounds, document_to_screen, zoom);
output
pub fn pipeline_init<P: WgpuPipeline>(&self, pipeline: &WgpuPipelineCache) {
pipeline.init::<P>(self);
}

pub async fn request_texture(&self, size: UVec2) -> Arc<wgpu::Texture> {
self.texture_cache.lock().await.request_texture(&self.context.device, size)
self.inner.texture_cache.lock().await.request_texture(&self.context().device, size)
}
}

Expand All @@ -122,17 +126,15 @@ impl WgpuExecutor {

let texture_cache = TextureCache::new(TEXTURE_CACHE_SIZE);

let resampler = Resampler::new(&context.device);
let background_compositor = BackgroundCompositor::new(&context.device);
let shader_runtime = ShaderRuntime::new(&context);

Some(Self {
context,
texture_cache: texture_cache.into(),
vello_renderer: vello_renderer.into(),
resampler,
background_compositor,
shader_runtime,
inner: Arc::new(WgpuExecutorInner {
context,
texture_cache: texture_cache.into(),
vello_renderer: vello_renderer.into(),
shader_runtime,
}),
})
}
}
Loading
Loading