mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 23:08:05 +08:00
Replace borrowed scope injections with arcs
This commit is contained in:
@@ -259,12 +259,12 @@ macro_rules! tagged_value {
|
||||
Self::NodeIdPath(_) => concrete!(List<NodeId>),
|
||||
Self::DocumentNode(_) => concrete!(DocumentNode),
|
||||
Self::ContextFeatures(_) => concrete!(ContextFeatures),
|
||||
Self::EditorApi(_) => concrete!(&PlatformEditorApi),
|
||||
Self::EditorApi(_) => concrete!(Arc<PlatformEditorApi>),
|
||||
Self::ResourceHash(_) => concrete!(ResourceHash),
|
||||
}
|
||||
}
|
||||
|
||||
/// Materializes the value exactly as [`Self::to_dynany`] does and wraps it in a `ClonedNode` behind an [`EdgeHandle`], whose type matches [`Self::ty`].
|
||||
/// Materializes the value as [`Self::to_dynany`] does, wrapped in a `ClonedNode` edge typed by [`Self::ty`].
|
||||
pub fn to_edge(self) -> Result<EdgeHandle, String> {
|
||||
match self {
|
||||
// ===============
|
||||
@@ -309,12 +309,12 @@ macro_rules! tagged_value {
|
||||
}
|
||||
Self::DocumentNode(node) => Ok(value_edge(node)),
|
||||
Self::ContextFeatures(features) => Ok(value_edge(features)),
|
||||
Self::EditorApi(_) => Err("EditorApi values are wired by the executor, not as value edges".to_string()),
|
||||
Self::EditorApi(x) => Ok(value_edge(x)),
|
||||
Self::ResourceHash(x) => Ok(value_edge(x)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Evaluates a typed edge and converts the landed value into a tagged value; the eval-boundary companion of [`Self::to_edge`] with the coverage of [`Self::try_from_any`].
|
||||
/// Evaluates a typed edge and converts the landed value into a tagged value, with the coverage of [`Self::try_from_any`].
|
||||
pub fn from_edge(handle: EdgeHandle, ctx: &Context) -> Result<GPoll<Self>, String> {
|
||||
let ty = handle.ty().clone();
|
||||
// ===============
|
||||
|
||||
@@ -17,7 +17,7 @@ use std::sync::{Arc, Mutex, PoisonError};
|
||||
|
||||
const ARENA_CAPACITY: usize = 1 << 20;
|
||||
|
||||
/// Dropped tasks never complete; replaced by the host spawner when the runtime scope wiring lands.
|
||||
/// Dropped tasks never complete.
|
||||
pub struct NoopSpawner;
|
||||
|
||||
impl Spawner for NoopSpawner {
|
||||
|
||||
@@ -23,7 +23,7 @@ use graphene_std::{Artboard, Context, Graphic, ProtoNodeIdentifier, SourceId, co
|
||||
use node_registry_macros::{async_node, convert_node, into_node};
|
||||
use std::collections::HashMap;
|
||||
#[cfg(feature = "gpu")]
|
||||
use wgpu_executor::WgpuExecutor;
|
||||
use wgpu_executor::WgpuExecutorHandle;
|
||||
|
||||
fn node_registry() -> HashMap<ProtoNodeIdentifier, Vec<RegistryEntry>> {
|
||||
let mut node_types: Vec<(ProtoNodeIdentifier, RegistryEntry)> = vec![
|
||||
@@ -90,8 +90,6 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, Vec<RegistryEntry>> {
|
||||
convert_node!(from: List<Raster<GPU>>, to: AttributeValueDyn),
|
||||
convert_node!(from: List<Graphic>, to: AttributeValueDyn),
|
||||
// into_node!(from: List<Raster<CPU>>, to: List<Raster<SRGBA8>>),
|
||||
#[cfg(feature = "gpu")]
|
||||
into_node!(from: &PlatformEditorApi, to: &WgpuExecutor),
|
||||
convert_node!(from: DVec2, to: DVec2),
|
||||
convert_node!(from: List<Vector>, to: List<Vector>),
|
||||
convert_node!(from: DVec2, to: List<Vector>),
|
||||
@@ -101,13 +99,13 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, Vec<RegistryEntry>> {
|
||||
convert_node!(from: IVec2, to: String),
|
||||
convert_node!(from: DAffine2, to: String),
|
||||
#[cfg(feature = "gpu")]
|
||||
convert_node!(from: List<Raster<CPU>>, to: List<Raster<CPU>>, converter: &WgpuExecutor),
|
||||
convert_node!(from: List<Raster<CPU>>, to: List<Raster<CPU>>, converter: WgpuExecutorHandle),
|
||||
#[cfg(feature = "gpu")]
|
||||
convert_node!(from: List<Raster<CPU>>, to: List<Raster<GPU>>, converter: &WgpuExecutor),
|
||||
convert_node!(from: List<Raster<CPU>>, to: List<Raster<GPU>>, converter: WgpuExecutorHandle),
|
||||
#[cfg(feature = "gpu")]
|
||||
convert_node!(from: List<Raster<GPU>>, to: List<Raster<GPU>>, converter: &WgpuExecutor),
|
||||
convert_node!(from: List<Raster<GPU>>, to: List<Raster<GPU>>, converter: WgpuExecutorHandle),
|
||||
#[cfg(feature = "gpu")]
|
||||
convert_node!(from: List<Raster<GPU>>, to: List<Raster<CPU>>, converter: &WgpuExecutor, async),
|
||||
convert_node!(from: List<Raster<GPU>>, to: List<Raster<CPU>>, converter: WgpuExecutorHandle, async),
|
||||
// =============
|
||||
// MONITOR NODES
|
||||
// =============
|
||||
|
||||
@@ -114,7 +114,7 @@ pub fn wrap_network_in_scope(network: NodeNetwork, editor_api: Arc<PlatformEdito
|
||||
..Default::default()
|
||||
},
|
||||
];
|
||||
let scope_injections = vec![("editor-api".to_string(), (NodeId(2), concrete!(&PlatformEditorApi)))];
|
||||
let scope_injections = vec![("editor-api".to_string(), (NodeId(2), concrete!(std::sync::Arc<PlatformEditorApi>)))];
|
||||
|
||||
NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(1), 0)],
|
||||
|
||||
@@ -31,7 +31,7 @@ pub trait GNode<Input> {
|
||||
GPoll::Final(Extent::Free)
|
||||
}
|
||||
|
||||
/// Introspection access to node-resident records, for example the monitor's captured io; `None` for ordinary nodes.
|
||||
/// Introspection access to node-resident records; `None` for ordinary nodes.
|
||||
fn serialize(&self) -> Option<std::sync::Arc<dyn std::any::Any + Send + Sync>> {
|
||||
None
|
||||
}
|
||||
|
||||
@@ -47,9 +47,7 @@ pub trait Convert<T, C>: Sized {
|
||||
fn convert(self, footprint: Footprint, converter: C) -> T;
|
||||
}
|
||||
|
||||
/// The genuinely asynchronous counterpart of [`Convert`], for conversions whose work completes outside
|
||||
/// the evaluation, such as the GPU-to-CPU texture readback. Consumed by the `convert_async` kernel on
|
||||
/// the async source tier; a conversion pair implements exactly one of the two traits.
|
||||
/// The asynchronous counterpart of [`Convert`]; a conversion pair implements exactly one of the two traits.
|
||||
pub trait ConvertAsync<T, C>: Sized {
|
||||
#[must_use]
|
||||
fn convert(self, footprint: Footprint, converter: C) -> crate::runtime::SourceFuture<T>;
|
||||
|
||||
@@ -180,8 +180,7 @@ impl std::fmt::Debug for EdgeHandle {
|
||||
}
|
||||
}
|
||||
|
||||
// SAFETY: wasm is single threaded, so the marker-free payload never actually crosses a thread;
|
||||
// mirrors the old NodeContainer assertion that let the executor live in a sync static.
|
||||
// SAFETY: wasm is single threaded, so the marker-free payload never actually crosses a thread.
|
||||
#[cfg(target_family = "wasm")]
|
||||
unsafe impl Send for EdgeHandle {}
|
||||
// SAFETY: as in Send.
|
||||
|
||||
@@ -60,6 +60,18 @@ impl std::fmt::Debug for WgpuExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
/// Owned Arc handle carrying the executor as an ordinary wire value.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct WgpuExecutorHandle(pub std::sync::Arc<WgpuExecutor>);
|
||||
|
||||
impl std::ops::Deref for WgpuExecutorHandle {
|
||||
type Target = WgpuExecutor;
|
||||
|
||||
fn deref(&self) -> &WgpuExecutor {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ApplicationIo<Executor = WgpuExecutor>> From<&'a EditorApi<T>> for &'a WgpuExecutor {
|
||||
fn from(editor_api: &'a EditorApi<T>) -> Self {
|
||||
editor_api.application_io.as_ref().unwrap().gpu_executor().unwrap()
|
||||
|
||||
@@ -8,6 +8,7 @@ use core_types::runtime::SourceFuture;
|
||||
use core_types::transform::Footprint;
|
||||
use raster_types::Image;
|
||||
use raster_types::{CPU, GPU, Raster};
|
||||
use crate::WgpuExecutorHandle;
|
||||
use wgpu::util::{DeviceExt, TextureDataOrder};
|
||||
use wgpu::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages};
|
||||
|
||||
@@ -41,15 +42,15 @@ fn upload_to_texture(device: &wgpu::Device, queue: &wgpu::Queue, image: &Raster<
|
||||
|
||||
|
||||
/// Passthrough conversion for GPU `List`s - no conversion needed
|
||||
impl<'i> Convert<List<Raster<GPU>>, &'i WgpuExecutor> for List<Raster<GPU>> {
|
||||
fn convert(self, _: Footprint, _converter: &'i WgpuExecutor) -> List<Raster<GPU>> {
|
||||
impl Convert<List<Raster<GPU>>, WgpuExecutorHandle> for List<Raster<GPU>> {
|
||||
fn convert(self, _: Footprint, _converter: WgpuExecutorHandle) -> List<Raster<GPU>> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `List<Raster<CPU>>` to `List<Raster<GPU>>` by uploading each image to a texture
|
||||
impl<'i> Convert<List<Raster<GPU>>, &'i WgpuExecutor> for List<Raster<CPU>> {
|
||||
fn convert(self, _: Footprint, executor: &'i WgpuExecutor) -> List<Raster<GPU>> {
|
||||
impl Convert<List<Raster<GPU>>, WgpuExecutorHandle> for List<Raster<CPU>> {
|
||||
fn convert(self, _: Footprint, executor: WgpuExecutorHandle) -> List<Raster<GPU>> {
|
||||
let device = &executor.context().device;
|
||||
let queue = executor.context().queue.lock();
|
||||
let list = self
|
||||
@@ -68,8 +69,8 @@ impl<'i> Convert<List<Raster<GPU>>, &'i WgpuExecutor> for List<Raster<CPU>> {
|
||||
}
|
||||
|
||||
/// Converts single CPU raster to GPU by uploading to texture
|
||||
impl<'i> Convert<Raster<GPU>, &'i WgpuExecutor> for Raster<CPU> {
|
||||
fn convert(self, _: Footprint, executor: &'i WgpuExecutor) -> Raster<GPU> {
|
||||
impl Convert<Raster<GPU>, WgpuExecutorHandle> for Raster<CPU> {
|
||||
fn convert(self, _: Footprint, executor: WgpuExecutorHandle) -> Raster<GPU> {
|
||||
let device = &executor.context().device;
|
||||
let queue = executor.context().queue.lock();
|
||||
let texture = upload_to_texture(device, &queue, &self);
|
||||
@@ -80,8 +81,8 @@ impl<'i> Convert<Raster<GPU>, &'i WgpuExecutor> for Raster<CPU> {
|
||||
}
|
||||
|
||||
/// Passthrough conversion for CPU `List`s - no conversion needed
|
||||
impl<'i> Convert<List<Raster<CPU>>, &'i WgpuExecutor> for List<Raster<CPU>> {
|
||||
fn convert(self, _: Footprint, _converter: &'i WgpuExecutor) -> List<Raster<CPU>> {
|
||||
impl Convert<List<Raster<CPU>>, WgpuExecutorHandle> for List<Raster<CPU>> {
|
||||
fn convert(self, _: Footprint, _converter: WgpuExecutorHandle) -> List<Raster<CPU>> {
|
||||
self
|
||||
}
|
||||
}
|
||||
@@ -191,8 +192,8 @@ impl RasterGpuToRasterCpuConverter {
|
||||
}
|
||||
|
||||
/// Converts a `List<Raster<GPU>>` to `List<Raster<CPU>>` by downloading texture data in one go then asynchronously maps all buffers and processes the results.
|
||||
impl<'i> ConvertAsync<List<Raster<CPU>>, &'i WgpuExecutor> for List<Raster<GPU>> {
|
||||
fn convert(self, _: Footprint, executor: &'i WgpuExecutor) -> SourceFuture<List<Raster<CPU>>> {
|
||||
impl ConvertAsync<List<Raster<CPU>>, WgpuExecutorHandle> for List<Raster<GPU>> {
|
||||
fn convert(self, _: Footprint, executor: WgpuExecutorHandle) -> SourceFuture<List<Raster<CPU>>> {
|
||||
let device = executor.context().device.clone();
|
||||
let queue = executor.context().queue.lock();
|
||||
|
||||
@@ -235,8 +236,8 @@ impl<'i> ConvertAsync<List<Raster<CPU>>, &'i WgpuExecutor> for List<Raster<GPU>>
|
||||
}
|
||||
|
||||
/// Converts single GPU raster to CPU by downloading texture data
|
||||
impl<'i> ConvertAsync<Raster<CPU>, &'i WgpuExecutor> for Raster<GPU> {
|
||||
fn convert(self, _: Footprint, executor: &'i WgpuExecutor) -> SourceFuture<Raster<CPU>> {
|
||||
impl ConvertAsync<Raster<CPU>, WgpuExecutorHandle> for Raster<GPU> {
|
||||
fn convert(self, _: Footprint, executor: WgpuExecutorHandle) -> SourceFuture<Raster<CPU>> {
|
||||
let device = executor.context().device.clone();
|
||||
let queue = executor.context().queue.lock();
|
||||
|
||||
@@ -256,10 +257,10 @@ impl<'i> ConvertAsync<Raster<CPU>, &'i WgpuExecutor> for Raster<GPU> {
|
||||
///
|
||||
/// Accepts either individual raster data or a `List` of raster elements and converts it to the GPU format using the WgpuExecutor's device and queue.
|
||||
#[node_macro::node(category(""))]
|
||||
pub fn upload_texture<'a, T: Convert<List<Raster<GPU>>, &'a WgpuExecutor>>(
|
||||
pub fn upload_texture<T: Convert<List<Raster<GPU>>, WgpuExecutorHandle>>(
|
||||
_: impl Ctx,
|
||||
#[implementations(List<Raster<CPU>>, List<Raster<GPU>>)] input: T,
|
||||
executor: &'a WgpuExecutor,
|
||||
executor: WgpuExecutorHandle,
|
||||
) -> List<Raster<GPU>> {
|
||||
input.convert(Footprint::DEFAULT, executor)
|
||||
}
|
||||
|
||||
@@ -264,12 +264,12 @@ where
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""), inject_scope)]
|
||||
pub fn editor_api<'a>(_: impl Ctx, #[scope("editor-api")] editor_api: &'a PlatformEditorApi) -> &'a PlatformEditorApi {
|
||||
pub fn editor_api(_: impl Ctx, #[scope("editor-api")] editor_api: Arc<PlatformEditorApi>) -> Arc<PlatformEditorApi> {
|
||||
editor_api
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""))]
|
||||
pub fn resource<'a>(_: impl Ctx, hash: ResourceHash, #[scope(editor_api::IDENTIFIER)] editor_api: &'a PlatformEditorApi) -> SourceFuture<GPoll<Resource>> {
|
||||
pub fn resource(_: impl Ctx, hash: ResourceHash, #[scope(editor_api::IDENTIFIER)] editor_api: Arc<PlatformEditorApi>) -> SourceFuture<GPoll<Resource>> {
|
||||
let application_io = editor_api.application_io.clone();
|
||||
Box::pin(async move {
|
||||
let Some(application_io) = application_io else {
|
||||
@@ -283,26 +283,18 @@ pub fn resource<'a>(_: impl Ctx, hash: ResourceHash, #[scope(editor_api::IDENTIF
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""), inject_scope)]
|
||||
pub fn wgpu_executor<'a>(_: impl Ctx, #[scope(editor_api::IDENTIFIER)] editor_api: &'a PlatformEditorApi) -> &'a ::wgpu_executor::WgpuExecutor {
|
||||
editor_api
|
||||
.application_io
|
||||
.as_ref()
|
||||
.expect("ApplicationIo not not available")
|
||||
.gpu_executor()
|
||||
.expect("GPU executor not available")
|
||||
pub fn wgpu_executor(_: impl Ctx, #[scope(editor_api::IDENTIFIER)] editor_api: Arc<PlatformEditorApi>) -> ::wgpu_executor::WgpuExecutorHandle {
|
||||
::wgpu_executor::WgpuExecutorHandle(
|
||||
editor_api
|
||||
.application_io
|
||||
.as_ref()
|
||||
.expect("ApplicationIo not not available")
|
||||
.gpu_executor_arc()
|
||||
.expect("GPU executor not available"),
|
||||
)
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""), inject_scope)]
|
||||
pub fn try_wgpu_executor<'a>(_: impl Ctx, #[scope(editor_api::IDENTIFIER)] editor_api: &'a PlatformEditorApi) -> Option<&'a ::wgpu_executor::WgpuExecutor> {
|
||||
editor_api.application_io.as_ref()?.gpu_executor()
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""), inject_scope)]
|
||||
pub fn wgpu_executor_arc<'a>(_: impl Ctx, #[scope(editor_api::IDENTIFIER)] editor_api: &'a PlatformEditorApi) -> std::sync::Arc<::wgpu_executor::WgpuExecutor> {
|
||||
editor_api
|
||||
.application_io
|
||||
.as_ref()
|
||||
.expect("ApplicationIo not available")
|
||||
.gpu_executor_arc()
|
||||
.expect("GPU executor not available")
|
||||
pub fn try_wgpu_executor(_: impl Ctx, #[scope(editor_api::IDENTIFIER)] editor_api: Arc<PlatformEditorApi>) -> Option<::wgpu_executor::WgpuExecutorHandle> {
|
||||
editor_api.application_io.as_ref()?.gpu_executor_arc().map(::wgpu_executor::WgpuExecutorHandle)
|
||||
}
|
||||
|
||||
@@ -119,9 +119,9 @@ fn render_background<'a>(
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""), inject_scope)]
|
||||
fn composite_background_pipeline<'a>(
|
||||
fn composite_background_pipeline(
|
||||
_ctx: impl Ctx,
|
||||
#[scope(crate::platform_application_io::try_wgpu_executor::IDENTIFIER)] executor: Option<&'a WgpuExecutor>,
|
||||
#[scope(crate::platform_application_io::try_wgpu_executor::IDENTIFIER)] executor: Option<wgpu_executor::WgpuExecutorHandle>,
|
||||
#[data] pipeline: WgpuPipelineCache,
|
||||
) -> WgpuPipelineCache {
|
||||
if let Some(executor) = executor {
|
||||
|
||||
@@ -322,10 +322,10 @@ fn flood_fill(start: &TileCoord, tile_set: &HashSet<TileCoord>, visited: &mut Ha
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""))]
|
||||
pub fn render_output_cache<'a>(
|
||||
pub fn render_output_cache(
|
||||
ctx: impl Ctx + ExtractAll + DeriveCtx,
|
||||
#[scope(crate::platform_application_io::try_wgpu_executor::IDENTIFIER)] executor: Option<&'a WgpuExecutor>,
|
||||
#[scope(crate::platform_application_io::editor_api::IDENTIFIER)] editor_api: &'a PlatformEditorApi,
|
||||
#[scope(crate::platform_application_io::try_wgpu_executor::IDENTIFIER)] executor: Option<wgpu_executor::WgpuExecutorHandle>,
|
||||
#[scope(crate::platform_application_io::editor_api::IDENTIFIER)] editor_api: std::sync::Arc<PlatformEditorApi>,
|
||||
data: impl Node<Context<'_>, Output = RenderOutput>,
|
||||
#[data] tile_cache: TileCache,
|
||||
) -> Result<RenderOutput, Interrupt> {
|
||||
@@ -420,7 +420,7 @@ pub fn render_output_cache<'a>(
|
||||
let executor = executor.expect("GPU executor not available");
|
||||
let output_texture = executor.request_texture(physical_resolution);
|
||||
|
||||
let combined_metadata = composite_cached_regions(&all_regions, &output_texture, &device_origin_offset, &footprint.transform, executor);
|
||||
let combined_metadata = composite_cached_regions(&all_regions, &output_texture, &device_origin_offset, &footprint.transform, &executor);
|
||||
|
||||
Ok(RenderOutput {
|
||||
data: RenderOutputType::Texture(output_texture),
|
||||
|
||||
@@ -72,9 +72,9 @@ fn render_intermediate<T: 'static + Render + WasmNotSend + Send + Sync>(
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""))]
|
||||
fn render<'a>(
|
||||
fn render(
|
||||
ctx: impl Ctx + ExtractFootprint + ExtractVarArgs,
|
||||
#[scope(crate::platform_application_io::try_wgpu_executor::IDENTIFIER)] executor: Option<&'a WgpuExecutor>,
|
||||
#[scope(crate::platform_application_io::try_wgpu_executor::IDENTIFIER)] executor: Option<wgpu_executor::WgpuExecutorHandle>,
|
||||
data: RenderIntermediate,
|
||||
) -> RenderOutput {
|
||||
let footprint = ctx.footprint();
|
||||
|
||||
@@ -72,9 +72,9 @@ pub fn render_pixel_preview(
|
||||
}
|
||||
|
||||
#[node_macro::node(category(""), inject_scope)]
|
||||
fn pixel_preview_pipeline<'a>(
|
||||
fn pixel_preview_pipeline(
|
||||
_ctx: impl Ctx,
|
||||
#[scope(crate::platform_application_io::try_wgpu_executor::IDENTIFIER)] executor: Option<&'a WgpuExecutor>,
|
||||
#[scope(crate::platform_application_io::try_wgpu_executor::IDENTIFIER)] executor: Option<wgpu_executor::WgpuExecutorHandle>,
|
||||
#[data] pipeline: WgpuPipelineCache,
|
||||
) -> WgpuPipelineCache {
|
||||
if let Some(executor) = executor {
|
||||
|
||||
Reference in New Issue
Block a user