Skip to content

Commit af7974f

Browse files
Implement wgpu-sync
1 parent 6a54dcb commit af7974f

12 files changed

Lines changed: 284 additions & 47 deletions

File tree

Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ members = [
1414
"frontend/wrapper",
1515
"libraries/dyn-any",
1616
"libraries/math-parser",
17+
"libraries/wgpu-sync",
1718
"node-graph/libraries/graphene-hash",
1819
"node-graph/libraries/*",
1920
"node-graph/nodes/*",
@@ -98,6 +99,7 @@ graphene-std = { path = "node-graph/nodes/gstd" }
9899
interpreted-executor = { path = "node-graph/interpreted-executor" }
99100
node-macro = { path = "node-graph/node-macro" }
100101
wgpu-executor = { path = "node-graph/libraries/wgpu-executor" }
102+
wgpu-sync = { path = "libraries/wgpu-sync" }
101103
graphite-proc-macros = { path = "proc-macros" }
102104
graphite-editor = { path = "editor" }
103105
graphene-canvas-utils = { path = "node-graph/libraries/canvas-utils" }

desktop/src/render/state.rs

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
use wgpu::PresentMode;
22

33
use crate::window::Window;
4-
use crate::wrapper::{WgpuContext, WgpuExecutor};
4+
use crate::wrapper::{WgpuContext, WgpuCurrentSurfaceTexture, WgpuExecutor, WgpuSurface};
55

66
#[derive(derivative::Derivative)]
77
#[derivative(Debug)]
88
pub(crate) struct RenderState {
9-
surface: wgpu::Surface<'static>,
10-
context: WgpuContext,
9+
surface: WgpuSurface,
1110
executor: WgpuExecutor,
1211
config: wgpu::SurfaceConfiguration,
1312
render_pipeline: wgpu::RenderPipeline,
@@ -162,12 +161,11 @@ impl RenderState {
162161
cache: None,
163162
});
164163

165-
let wgpu_executor = WgpuExecutor::with_context(context.clone()).expect("Failed to create WgpuExecutor");
164+
let executor = WgpuExecutor::with_context(context).expect("Failed to create WgpuExecutor");
166165

167166
Self {
168167
surface,
169-
context,
170-
executor: wgpu_executor,
168+
executor,
171169
config,
172170
render_pipeline,
173171
transparent_texture,
@@ -193,12 +191,6 @@ impl RenderState {
193191
self.desired_width = width;
194192
self.desired_height = height;
195193
self.surface_outdated = true;
196-
197-
if width > 0 && height > 0 && (self.config.width != width || self.config.height != height) {
198-
self.config.width = width;
199-
self.config.height = height;
200-
self.surface.configure(&self.context.device, &self.config);
201-
}
202194
}
203195

204196
pub(crate) fn bind_viewport_texture(&mut self, viewport_texture: std::sync::Arc<wgpu::Texture>) {
@@ -254,6 +246,14 @@ impl RenderState {
254246
if !self.surface_outdated {
255247
return Ok(());
256248
}
249+
250+
// Apply resize once per presented frame.
251+
if self.desired_width > 0 && self.desired_height > 0 && (self.config.width != self.desired_width || self.config.height != self.desired_height) {
252+
self.config.width = self.desired_width;
253+
self.config.height = self.desired_height;
254+
self.surface.configure(&self.executor.context().device, &self.config);
255+
}
256+
257257
let ui_scale = if let Some(ui_texture) = &self.ui_texture
258258
&& (self.desired_width != ui_texture.width() || self.desired_height != ui_texture.height())
259259
{
@@ -266,21 +266,19 @@ impl RenderState {
266266
self.render_overlays(scene);
267267
}
268268

269-
let (output, suboptimal) = match self.surface.get_current_texture() {
270-
wgpu::CurrentSurfaceTexture::Success(t) => (t, false),
271-
// wgpu reports the swapchain no longer matches the underlying surface; present this frame and reconfigure after present, since `Surface::configure` panics while an acquired `SurfaceTexture` is still alive
272-
wgpu::CurrentSurfaceTexture::Suboptimal(t) => (t, true),
273-
// Window is minimized or behind another window: skip the frame silently and try again once it becomes visible
274-
wgpu::CurrentSurfaceTexture::Occluded => return Ok(()),
275-
wgpu::CurrentSurfaceTexture::Lost => return Err(RenderError::SurfaceLost),
276-
wgpu::CurrentSurfaceTexture::Outdated => return Err(RenderError::SurfaceOutdated),
277-
wgpu::CurrentSurfaceTexture::Timeout => return Err(RenderError::SurfaceTimeout),
278-
wgpu::CurrentSurfaceTexture::Validation => return Err(RenderError::SurfaceValidation),
269+
let (surface_texture, suboptimal) = match self.surface.get_current_texture(&self.executor.context().queue) {
270+
WgpuCurrentSurfaceTexture::Success(t) => (t, false),
271+
WgpuCurrentSurfaceTexture::Suboptimal(t) => (t, true),
272+
WgpuCurrentSurfaceTexture::Occluded => return Ok(()),
273+
WgpuCurrentSurfaceTexture::Lost => return Err(RenderError::SurfaceLost),
274+
WgpuCurrentSurfaceTexture::Outdated => return Err(RenderError::SurfaceOutdated),
275+
WgpuCurrentSurfaceTexture::Timeout => return Err(RenderError::SurfaceTimeout),
276+
WgpuCurrentSurfaceTexture::Validation => return Err(RenderError::SurfaceValidation),
279277
};
280278

281-
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
279+
let view = surface_texture.texture.create_view(&wgpu::TextureViewDescriptor::default());
282280

283-
let mut encoder = self.context.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder") });
281+
let mut encoder = self.executor.context().device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: Some("Render Encoder") });
284282

285283
{
286284
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
@@ -318,12 +316,12 @@ impl RenderState {
318316
tracing::warn!("No bind group available - showing clear color only");
319317
}
320318
}
321-
self.context.queue.submit(std::iter::once(encoder.finish()));
319+
surface_texture.queue.submit(std::iter::once(encoder.finish()));
322320
window.pre_present_notify();
323-
output.present();
321+
surface_texture.present();
324322

325323
if suboptimal {
326-
self.surface.configure(&self.context.device, &self.config);
324+
self.surface.configure(&self.executor.context().device, &self.config);
327325
}
328326

329327
if ui_scale.is_some() {
@@ -340,7 +338,7 @@ impl RenderState {
340338
let overlays_texture_view = self.overlays_texture.as_ref().unwrap_or(&self.transparent_texture).create_view(&wgpu::TextureViewDescriptor::default());
341339
let ui_texture_view = self.ui_texture.as_ref().unwrap_or(&self.transparent_texture).create_view(&wgpu::TextureViewDescriptor::default());
342340

343-
let bind_group = self.context.device.create_bind_group(&wgpu::BindGroupDescriptor {
341+
let bind_group = self.executor.context().device.create_bind_group(&wgpu::BindGroupDescriptor {
344342
layout: &self.render_pipeline.get_bind_group_layout(0),
345343
entries: &[
346344
wgpu::BindGroupEntry {

desktop/src/window.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::consts::APP_NAME;
22
use crate::event::AppEventScheduler;
33
use crate::wrapper::messages::MenuItem;
4+
use crate::wrapper::{WgpuInstance, WgpuSurface};
45
use std::collections::HashMap;
56
use std::sync::Arc;
67
use winit::cursor::{CursorIcon, CustomCursor, CustomCursorSource};
@@ -86,8 +87,8 @@ impl Window {
8687
self.winit_window.request_redraw();
8788
}
8889

89-
pub(crate) fn create_surface(&self, instance: &wgpu::Instance) -> wgpu::Surface<'static> {
90-
instance.create_surface(self.winit_window.clone()).unwrap()
90+
pub(crate) fn create_surface(&self, instance: &WgpuInstance) -> WgpuSurface {
91+
instance.create_surface(self.winit_window.clone()).expect("Failed to create surface")
9192
}
9293

9394
pub(crate) fn pre_present_notify(&self) {

desktop/wrapper/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ pub use graphite_editor::consts::{DOUBLE_CLICK_MILLISECONDS, FILE_EXTENSION};
1111
pub use wgpu_executor::WgpuBackends;
1212
pub use wgpu_executor::WgpuContext;
1313
pub use wgpu_executor::WgpuContextBuilder;
14+
pub use wgpu_executor::WgpuCurrentSurfaceTexture;
1415
pub use wgpu_executor::WgpuExecutor;
1516
pub use wgpu_executor::WgpuFeatures;
17+
pub use wgpu_executor::WgpuInstance;
18+
pub use wgpu_executor::WgpuSurface;
1619

1720
mod handle_desktop_wrapper_message;
1821
mod intercept_editor_message;

libraries/wgpu-sync/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "wgpu-sync"
3+
description = "Helper for working with wgpu in a multi-threaded context"
4+
version.workspace = true
5+
edition.workspace = true
6+
authors.workspace = true
7+
license.workspace = true
8+
9+
[dependencies]
10+
wgpu = { workspace = true }

0 commit comments

Comments
 (0)