From 9e836326470d0d0b957a984f752efa8eebd8bd00 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Mon, 27 Jul 2026 10:47:44 +0000 Subject: [PATCH] Make the GPU render and dispatch pipelines synchronous --- node-graph/libraries/wgpu-executor/src/lib.rs | 13 +- .../libraries/wgpu-executor/src/pipeline.rs | 32 +---- .../per_pixel_adjust_runtime.rs | 6 +- .../src/shader_nodes/per_pixel_adjust.rs | 5 +- .../nodes/gstd/src/platform_application_io.rs | 16 ++- .../nodes/gstd/src/render_background.rs | 22 ++-- node-graph/nodes/gstd/src/render_cache.rs | 111 +++++++----------- node-graph/nodes/gstd/src/render_node.rs | 1 - .../nodes/gstd/src/render_pixel_preview.rs | 45 ++++--- 9 files changed, 102 insertions(+), 149 deletions(-) diff --git a/node-graph/libraries/wgpu-executor/src/lib.rs b/node-graph/libraries/wgpu-executor/src/lib.rs index 4c724ec684..9af2c73972 100644 --- a/node-graph/libraries/wgpu-executor/src/lib.rs +++ b/node-graph/libraries/wgpu-executor/src/lib.rs @@ -9,7 +9,7 @@ use crate::texture_cache::TextureCache; use anyhow::Result; use core_types::Color; use core_types::color::SRGBA8; -use futures::lock::Mutex; +use std::sync::Mutex; use glam::UVec2; use graphene_application_io::{ApplicationIo, EditorApi}; use raster_types::Texture; @@ -19,7 +19,6 @@ 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; @@ -68,8 +67,8 @@ impl<'a, T: ApplicationIo> From<&'a EditorApi> for & } impl WgpuExecutor { - pub async fn render_vello_scene(&self, scene: &Scene, size: UVec2, context: &RenderContext, background: Option) -> Result { - let texture = self.request_texture(size).await; + pub fn render_vello_scene(&self, scene: &Scene, size: UVec2, context: &RenderContext, background: Option) -> Result { + let texture = self.request_texture(size); let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); @@ -82,7 +81,7 @@ impl WgpuExecutor { }; { - let mut renderer = self.inner.vello_renderer.lock().await; + let mut renderer = self.inner.vello_renderer.lock().unwrap(); for (image_brush, texture) in context.resource_overrides.iter() { let texture_view = wgpu::TexelCopyTextureInfoBase { texture: (**texture).clone(), @@ -109,8 +108,8 @@ impl WgpuExecutor { pipeline.init::

(self); } - pub async fn request_texture(&self, size: UVec2) -> Texture { - self.inner.texture_cache.lock().await.request_texture(&self.context().device, size) + pub fn request_texture(&self, size: UVec2) -> Texture { + self.inner.texture_cache.lock().unwrap().request_texture(&self.context().device, size) } } diff --git a/node-graph/libraries/wgpu-executor/src/pipeline.rs b/node-graph/libraries/wgpu-executor/src/pipeline.rs index 75d286d834..199826c535 100644 --- a/node-graph/libraries/wgpu-executor/src/pipeline.rs +++ b/node-graph/libraries/wgpu-executor/src/pipeline.rs @@ -1,42 +1,16 @@ use dyn_any::DynAny; use std::any::Any; -use std::future::Future; -use std::pin::Pin; use std::sync::{Arc, OnceLock}; use crate::WgpuExecutor; -pub type PipelineFuture<'a, T> = Pin + Send + 'a>>; - pub trait Pipeline: Any + Send + Sync + Sized { type Args<'a>; type Out: Send; fn create(executor: &WgpuExecutor) -> Self; - fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> PipelineFuture<'a, Self::Out>; -} - -pub trait AsyncPipeline: Any + Send + Sync + Sized { - type Args<'a>; - type Out: Send; - - fn create(executor: &WgpuExecutor) -> Self; - - fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> impl Future + Send + 'a; -} - -impl Pipeline for P { - type Args<'a> =

::Args<'a>; - type Out =

::Out; - - fn create(executor: &WgpuExecutor) -> Self { -

::create(executor) - } - - fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> PipelineFuture<'a, Self::Out> { - Box::pin(

::run(self, executor, args)) - } + fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> Self::Out; } #[derive(Default, Clone, DynAny)] @@ -51,13 +25,13 @@ impl PipelineCache { self.pipeline.get_or_init(|| Box::new(P::create(executor))); } - pub async fn run(&self, args: &P::Args<'_>) -> P::Out { + pub fn run(&self, args: &P::Args<'_>) -> P::Out { let executor = self.executor.get().expect("PipelineCache not initialized"); let entry = self.pipeline.get().expect("PipelineCache not initialized"); let pipeline = (&**entry) .downcast_ref::

() .unwrap_or_else(|| panic!("PipelineCache type mismatch: run::<{}>() but init used a different pipeline type", std::any::type_name::

(),)); - pipeline.run(executor, args).await + pipeline.run(executor, args) } } diff --git a/node-graph/libraries/wgpu-executor/src/shader_runtime/per_pixel_adjust_runtime.rs b/node-graph/libraries/wgpu-executor/src/shader_runtime/per_pixel_adjust_runtime.rs index 9f393d6945..e6eb444d13 100644 --- a/node-graph/libraries/wgpu-executor/src/shader_runtime/per_pixel_adjust_runtime.rs +++ b/node-graph/libraries/wgpu-executor/src/shader_runtime/per_pixel_adjust_runtime.rs @@ -2,7 +2,7 @@ use crate::WgpuContext; use crate::shader_runtime::{FULLSCREEN_VERTEX_SHADER_NAME, ShaderRuntime}; use core_types::list::{Item, List}; use core_types::shaders::buffer_struct::BufferStruct; -use futures::lock::Mutex; +use std::sync::Mutex; use raster_types::{GPU, Raster}; use std::borrow::Cow; use std::collections::HashMap; @@ -33,8 +33,8 @@ impl PerPixelAdjustShaderRuntime { } impl ShaderRuntime { - pub async fn run_per_pixel_adjust(&self, shaders: &Shaders<'_>, textures: List>, args: Option<&T>) -> List> { - let mut cache = self.per_pixel_adjust.pipeline_cache.lock().await; + pub fn run_per_pixel_adjust(&self, shaders: &Shaders<'_>, textures: List>, args: Option<&T>) -> List> { + let mut cache = self.per_pixel_adjust.pipeline_cache.lock().unwrap(); let pipeline = cache .entry(shaders.fragment_shader_name.to_owned()) .or_insert_with(|| PerPixelAdjustGraphicsPipeline::new(&self.context, shaders)); diff --git a/node-graph/node-macro/src/shader_nodes/per_pixel_adjust.rs b/node-graph/node-macro/src/shader_nodes/per_pixel_adjust.rs index 954863b2f4..6a59db5cb5 100644 --- a/node-graph/node-macro/src/shader_nodes/per_pixel_adjust.rs +++ b/node-graph/node-macro/src/shader_nodes/per_pixel_adjust.rs @@ -287,7 +287,7 @@ impl PerPixelAdjustCodegen<'_> { wgsl_shader: crate::WGSL_SHADER, fragment_shader_name: super::#entry_point_name, has_uniform: #has_uniform, - }, #gpu_image, #uniform_buffer).await + }, #gpu_image, #uniform_buffer) } }; @@ -314,13 +314,12 @@ impl PerPixelAdjustCodegen<'_> { context_features: self.parsed.input.context_features.clone(), }, output_type: raster_gpu, - is_async: true, + is_async: false, fields, body, description: self.parsed.description.clone(), }; parsed_node_fn.replace_impl_trait_in_input(); - parsed_node_fn.inject_async_source_fields(self.crate_ident.gcore()?); let gpu_node_impl = crate::codegen::generate_node_code(self.crate_ident, &parsed_node_fn)?; // wrap node in `mod #gpu_node_mod` diff --git a/node-graph/nodes/gstd/src/platform_application_io.rs b/node-graph/nodes/gstd/src/platform_application_io.rs index 7e0362766a..1b9b485adb 100644 --- a/node-graph/nodes/gstd/src/platform_application_io.rs +++ b/node-graph/nodes/gstd/src/platform_application_io.rs @@ -10,6 +10,8 @@ use core_types::math::bbox::Bbox; use core_types::transform::Footprint; #[cfg(target_family = "wasm")] use core_types::{ATTR_EDITOR_MERGED_LAYERS, ATTR_TRANSFORM, WasmNotSend}; +use core_types::gpoll::GPoll; +use core_types::runtime::SourceFuture; use core_types::{Color, Ctx}; pub use graph_craft::application_io::resource::{Resource, ResourceHash}; pub use graph_craft::application_io::*; @@ -267,10 +269,16 @@ pub fn editor_api<'a>(_: impl Ctx, #[scope("editor-api")] editor_api: &'a Platfo } #[node_macro::node(category(""))] -pub async fn resource<'a>(_: impl Ctx, hash: ResourceHash, #[scope(editor_api::IDENTIFIER)] editor_api: &'a PlatformEditorApi) -> Resource { - let application_io = editor_api.application_io.as_ref().expect("ApplicationIo must be available when using resources"); - application_io.load_resource(hash).await.unwrap_or_else(|| { - panic!("Resource {hash} not found"); +pub fn resource<'a>(_: impl Ctx, hash: ResourceHash, #[scope(editor_api::IDENTIFIER)] editor_api: &'a PlatformEditorApi) -> SourceFuture> { + let application_io = editor_api.application_io.clone(); + Box::pin(async move { + let Some(application_io) = application_io else { + return GPoll::error("ApplicationIo not available"); + }; + match application_io.load_resource(hash).await { + Some(resource) => GPoll::Final(resource), + None => GPoll::error("resource not found"), + } }) } diff --git a/node-graph/nodes/gstd/src/render_background.rs b/node-graph/nodes/gstd/src/render_background.rs index a416d83d34..52d9c87653 100644 --- a/node-graph/nodes/gstd/src/render_background.rs +++ b/node-graph/nodes/gstd/src/render_background.rs @@ -9,7 +9,7 @@ use graphic_types::raster_types::Texture; use rendering::{RenderParams, SvgRender, SvgRenderOutput}; use std::fmt::Write; use wgpu::util::DeviceExt; -use wgpu_executor::{AsyncWgpuPipeline, WgpuExecutor, WgpuPipelineCache}; +use wgpu_executor::{WgpuExecutor, WgpuPipeline, WgpuPipelineCache}; #[node_macro::node(category(""))] fn render_background<'a>( @@ -35,14 +35,12 @@ fn render_background<'a>( let data = match foreground_data { RenderOutputType::Texture(foreground_texture) => { let doc_to_screen = render_params.footprint.transform.as_affine2(); - let blended = pipeline - .run::(&CompositeBackgroundArgs { - foreground: foreground_texture.as_ref(), - backgrounds: &metadata.backgrounds, - document_to_screen: doc_to_screen, - zoom: render_params.viewport_zoom.to_f32(), - }) - .await; + let blended = pipeline.run::(&CompositeBackgroundArgs { + foreground: foreground_texture.as_ref(), + backgrounds: &metadata.backgrounds, + document_to_screen: doc_to_screen, + zoom: render_params.viewport_zoom.to_f32(), + }); RenderOutputType::Texture(blended) } @@ -148,7 +146,7 @@ pub struct CompositeBackgroundArgs<'a> { zoom: f32, } -impl AsyncWgpuPipeline for CompositeBackground { +impl WgpuPipeline for CompositeBackground { type Args<'a> = CompositeBackgroundArgs<'a>; type Out = Texture; @@ -331,7 +329,7 @@ impl AsyncWgpuPipeline for CompositeBackground { } } - async fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> Self::Out { + fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> Self::Out { let &CompositeBackgroundArgs { foreground, backgrounds, @@ -340,7 +338,7 @@ impl AsyncWgpuPipeline for CompositeBackground { } = args; let foreground_size = foreground.size(); - let output = executor.request_texture(UVec2::new(foreground_size.width, foreground_size.height)).await; + let output = executor.request_texture(UVec2::new(foreground_size.width, foreground_size.height)); if zoom <= 0. { return output; diff --git a/node-graph/nodes/gstd/src/render_cache.rs b/node-graph/nodes/gstd/src/render_cache.rs index 27f27cceb4..f37d4c3099 100644 --- a/node-graph/nodes/gstd/src/render_cache.rs +++ b/node-graph/nodes/gstd/src/render_cache.rs @@ -1,8 +1,9 @@ //! Tile-based render caching for efficient viewport panning. +use core_types::gpoll::Interrupt; use core_types::math::bbox::AxisAlignedBbox; use core_types::transform::{Footprint, RenderQuality, Transform}; -use core_types::{CloneVarArgs, Context, Ctx, ExtractAll, ExtractAnimationTime, ExtractPointerPosition, ExtractRealTime, OwnedContextImpl}; +use core_types::{Context, Ctx, DeriveCtx, ExtractAll}; use glam::{DAffine2, DVec2, IVec2, UVec2}; use graph_craft::application_io::PlatformEditorApi; use graph_craft::document::value::{RenderOutput, RenderOutputType}; @@ -321,25 +322,23 @@ fn flood_fill(start: &TileCoord, tile_set: &HashSet, visited: &mut Ha } #[node_macro::node(category(""))] -pub async fn render_output_cache<'a>( - ctx: impl Ctx + ExtractAll + CloneVarArgs + ExtractRealTime + ExtractAnimationTime + ExtractPointerPosition + Sync, +pub fn render_output_cache<'a>( + 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, - data: impl Node, Output = RenderOutput> + Send + Sync, + data: impl Node, Output = RenderOutput>, #[data] tile_cache: TileCache, -) -> RenderOutput { - let footprint = ctx.footprint(); +) -> Result { + let footprint = *ctx.footprint(); let Some(render_params) = ctx.vararg(0).ok().and_then(|v| v.downcast_ref::()) else { log::warn!("render_output_cache: missing or invalid render params, falling back to direct render"); - let context = OwnedContextImpl::from(ctx.clone()).with_footprint(*footprint); - return data.eval(context.into_context()).await; + return data.eval(&ctx.derived()); }; // Fall back to direct render for non-Vello or zero-size viewports let physical_resolution = footprint.resolution; if !matches!(render_params.render_output_type, RenderOutputTypeRequest::Vello) || physical_resolution.x == 0 || physical_resolution.y == 0 { - let context = OwnedContextImpl::from(ctx.clone()).with_footprint(*footprint).with_vararg(Box::new(render_params.clone())); - return data.eval(context.into_context()).await; + return data.eval(&ctx.derived()); } let zoom = footprint.scale_magnitudes().x; @@ -375,8 +374,38 @@ pub async fn render_output_cache<'a>( if missing_region.tiles.is_empty() { continue; } - let region = render_missing_region(missing_region, |ctx| data.eval(ctx), ctx.clone(), render_params, &footprint.transform, &device_origin_offset).await; - new_regions.push(region); + let min_tile = missing_region.tiles.iter().fold(IVec2::new(i32::MAX, i32::MAX), |acc, t| acc.min(IVec2::new(t.x, t.y))); + let max_tile = missing_region.tiles.iter().fold(IVec2::new(i32::MIN, i32::MIN), |acc, t| acc.max(IVec2::new(t.x, t.y))); + + let tile_count = (max_tile - min_tile) + IVec2::ONE; + let region_pixel_size = (tile_count * TILE_SIZE as i32).as_uvec2(); + + let tile_global_offset = min_tile.as_dvec2() * TILE_SIZE as f64 + device_origin_offset; + let region_transform = DAffine2::from_translation(-tile_global_offset) * footprint.transform; + let region_footprint = Footprint { + transform: region_transform, + resolution: region_pixel_size, + quality: RenderQuality::Full, + }; + + let mut result = data.eval(&ctx.with_footprint(®ion_footprint))?; + + let RenderOutputType::Texture(texture) = result.data else { + unreachable!("render_output_cache: expected texture output from Vello render"); + }; + + result.metadata.apply_transform(region_transform.inverse()); + + let memory_size = (region_pixel_size.x * region_pixel_size.y) as usize * BYTES_PER_PIXEL; + + new_regions.push(CachedRegion { + texture, + texture_size: region_pixel_size, + tiles: missing_region.tiles.clone(), + metadata: result.metadata, + last_access: 0, + memory_size, + }); } tile_cache.store_regions(new_regions.clone()); @@ -385,68 +414,18 @@ pub async fn render_output_cache<'a>( // If no regions, fall back to direct render if all_regions.is_empty() { - let context = OwnedContextImpl::from(ctx.clone()).with_footprint(*footprint).with_vararg(Box::new(render_params.clone())); - return data.eval(context.into_context()).await; + return data.eval(&ctx.derived()); } let executor = executor.expect("GPU executor not available"); - let output_texture = executor.request_texture(physical_resolution).await; + let output_texture = executor.request_texture(physical_resolution); let combined_metadata = composite_cached_regions(&all_regions, &output_texture, &device_origin_offset, &footprint.transform, executor); - RenderOutput { + Ok(RenderOutput { data: RenderOutputType::Texture(output_texture), metadata: combined_metadata, - } -} - -async fn render_missing_region( - region: &RenderRegion, - render_fn: F, - ctx: impl Ctx + ExtractAll + CloneVarArgs, - render_params: &RenderParams, - viewport_transform: &DAffine2, - viewport_origin_offset: &DVec2, -) -> CachedRegion -where - F: Fn(Context<'_>) -> Fut, - Fut: std::future::Future, -{ - let min_tile = region.tiles.iter().fold(IVec2::new(i32::MAX, i32::MAX), |acc, t| acc.min(IVec2::new(t.x, t.y))); - let max_tile = region.tiles.iter().fold(IVec2::new(i32::MIN, i32::MIN), |acc, t| acc.max(IVec2::new(t.x, t.y))); - - let tile_count = (max_tile - min_tile) + IVec2::ONE; - let region_pixel_size = (tile_count * TILE_SIZE as i32).as_uvec2(); - - let tile_global_offset = min_tile.as_dvec2() * TILE_SIZE as f64 + *viewport_origin_offset; - let region_transform = DAffine2::from_translation(-tile_global_offset) * *viewport_transform; - let region_footprint = Footprint { - transform: region_transform, - resolution: region_pixel_size, - quality: RenderQuality::Full, - }; - - let region_params = render_params.clone(); - let region_ctx = OwnedContextImpl::from(ctx).with_footprint(region_footprint).with_vararg(Box::new(region_params)).into_context(); - let mut result = render_fn(region_ctx).await; - - let RenderOutputType::Texture(texture) = result.data else { - unreachable!("render_missing_region: expected texture output from Vello render"); - }; - - let pixel_to_document = region_transform.inverse(); - result.metadata.apply_transform(pixel_to_document); - - let memory_size = (region_pixel_size.x * region_pixel_size.y) as usize * BYTES_PER_PIXEL; - - CachedRegion { - texture, - texture_size: region_pixel_size, - tiles: region.tiles.clone(), - metadata: result.metadata, - last_access: 0, - memory_size, - } + }) } fn composite_cached_regions( diff --git a/node-graph/nodes/gstd/src/render_node.rs b/node-graph/nodes/gstd/src/render_node.rs index a8f40074e8..4aeffd6138 100644 --- a/node-graph/nodes/gstd/src/render_node.rs +++ b/node-graph/nodes/gstd/src/render_node.rs @@ -131,7 +131,6 @@ fn render<'a>( let texture = executor .expect("GPU executor not available") .render_vello_scene(&transformed_scene, footprint.resolution, context, None) - .await .expect("Failed to render Vello scene"); RenderOutputType::Texture(texture) } diff --git a/node-graph/nodes/gstd/src/render_pixel_preview.rs b/node-graph/nodes/gstd/src/render_pixel_preview.rs index 3247c11114..bbcd2e78ca 100644 --- a/node-graph/nodes/gstd/src/render_pixel_preview.rs +++ b/node-graph/nodes/gstd/src/render_pixel_preview.rs @@ -1,22 +1,22 @@ +use core_types::gpoll::Interrupt; use core_types::transform::{Footprint, Transform}; -use core_types::{CloneVarArgs, Context, Ctx, ExtractAll, OwnedContextImpl}; +use core_types::{Context, Ctx, DeriveCtx, ExtractAll}; use glam::{DAffine2, DVec2, UVec2, Vec2}; use graph_craft::document::value::{RenderOutput, RenderOutputType}; use graphic_types::raster_types::Texture; use rendering::{RenderOutputType as RenderOutputTypeRequest, RenderParams}; use vector_types::vector::style::RenderMode; -use wgpu_executor::{AsyncWgpuPipeline, WgpuExecutor, WgpuPipelineCache}; +use wgpu_executor::{WgpuExecutor, WgpuPipeline, WgpuPipelineCache}; #[node_macro::node(category(""))] -pub async fn render_pixel_preview<'a>( - ctx: impl Ctx + ExtractAll + CloneVarArgs + Sync, +pub fn render_pixel_preview( + ctx: impl Ctx + ExtractAll + DeriveCtx, #[scope(pixel_preview_pipeline::IDENTIFIER)] pipeline: WgpuPipelineCache, - data: impl Node, Output = RenderOutput> + Send + Sync, -) -> RenderOutput { + data: impl Node, Output = RenderOutput>, +) -> Result { let Some(render_params) = ctx.vararg(0).ok().and_then(|v| v.downcast_ref::()).cloned() else { log::error!("invalid render params for pixel preview"); - let context = OwnedContextImpl::from(ctx).into_context(); - return data.eval(context).await; + return data.eval(&ctx.derived()); }; let physical_scale = render_params.scale; @@ -24,8 +24,7 @@ pub async fn render_pixel_preview<'a>( let viewport_zoom = footprint.scale_magnitudes().x; if render_params.render_mode != RenderMode::PixelPreview || !matches!(render_params.render_output_type, RenderOutputTypeRequest::Vello) || viewport_zoom <= 1. { - let context = OwnedContextImpl::from(ctx).into_context(); - return data.eval(context).await; + return data.eval(&ctx.derived()); } let physical_resolution = footprint.resolution; @@ -51,27 +50,25 @@ pub async fn render_pixel_preview<'a>( quality: footprint.quality, }; - let new_ctx = OwnedContextImpl::from(ctx).with_footprint(upstream_footprint).with_vararg(Box::new(render_params)).into_context(); - let mut result = data.eval(new_ctx).await; + let scoped = ctx.push_vararg(&render_params); + let mut result = data.eval(&scoped.ctx().with_footprint(&upstream_footprint))?; - let RenderOutputType::Texture(ref source_texture) = result.data else { return result }; + let RenderOutputType::Texture(ref source_texture) = result.data else { return Ok(result) }; let logical_transform = DAffine2::from_scale(DVec2::splat(1. / physical_scale)) * footprint.transform; let transform = DAffine2::from_translation(-upstream_min) * logical_transform.inverse() * DAffine2::from_scale(logical_resolution); - let resampled = pipeline - .run::(&PixelPreviewArgs { - source: source_texture.as_ref(), - transform: &transform, - size: physical_resolution, - }) - .await; + let resampled = pipeline.run::(&PixelPreviewArgs { + source: source_texture.as_ref(), + transform: &transform, + size: physical_resolution, + }); result.data = RenderOutputType::Texture(resampled); result.metadata.apply_transform(footprint.transform * DAffine2::from_translation(upstream_min)); - result + Ok(result) } #[node_macro::node(category(""), inject_scope)] @@ -97,7 +94,7 @@ pub struct PixelPreviewArgs<'a> { size: UVec2, } -impl AsyncWgpuPipeline for PixelPreview { +impl WgpuPipeline for PixelPreview { type Args<'a> = PixelPreviewArgs<'a>; type Out = Texture; @@ -169,11 +166,11 @@ impl AsyncWgpuPipeline for PixelPreview { PixelPreview { pipeline, bind_group_layout } } - async fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> Self::Out { + fn run<'a>(&'a self, executor: &'a WgpuExecutor, args: &'a Self::Args<'_>) -> Self::Out { let context = &executor.context(); let &PixelPreviewArgs { source, transform, size } = args; - let output = executor.request_texture(size).await; + let output = executor.request_texture(size); let source_view = source.create_view(&wgpu::TextureViewDescriptor::default()); let output_view = output.create_view(&wgpu::TextureViewDescriptor::default());