mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Render artwork at correct resolution when using vello on wasm (#3416)
* Work on fixing rendering for wasm+vello * Render vello canvas in wasm at the correct resolution * Cleanup unused surface rendering code * Remove vector to raster conversion * Remove desktop changes * Revert window.rs changes * Don't round logical coordinates * Fix desktop compilation + don't round logical coordinates for svg rendering * Further cleanup * Compute logical size from acutal physical sizes
This commit is contained in:
@@ -55,6 +55,10 @@ pub struct NodeRuntime {
|
||||
/// The current renders of the thumbnails for layer nodes.
|
||||
thumbnail_renders: HashMap<NodeId, Vec<SvgSegment>>,
|
||||
vector_modify: HashMap<NodeId, Vector>,
|
||||
|
||||
/// Cached surface for WASM viewport rendering (reused across frames)
|
||||
#[cfg(all(target_family = "wasm", feature = "gpu"))]
|
||||
wasm_viewport_surface: Option<wgpu_executor::WgpuSurface>,
|
||||
}
|
||||
|
||||
/// Messages passed from the editor thread to the node runtime thread.
|
||||
@@ -131,6 +135,8 @@ impl NodeRuntime {
|
||||
thumbnail_renders: Default::default(),
|
||||
vector_modify: Default::default(),
|
||||
inspect_state: None,
|
||||
#[cfg(all(target_family = "wasm", feature = "gpu"))]
|
||||
wasm_viewport_surface: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,6 +265,82 @@ impl NodeRuntime {
|
||||
None,
|
||||
)
|
||||
}
|
||||
#[cfg(all(target_family = "wasm", feature = "gpu"))]
|
||||
Ok(TaggedValue::RenderOutput(RenderOutput {
|
||||
data: RenderOutputType::Texture(image_texture),
|
||||
metadata,
|
||||
})) if !render_config.for_export => {
|
||||
// On WASM, for viewport rendering, blit the texture to a surface and return a CanvasFrame
|
||||
let app_io = self.editor_api.application_io.as_ref().unwrap();
|
||||
let executor = app_io.gpu_executor().expect("GPU executor should be available when we receive a texture");
|
||||
|
||||
// Get or create the cached surface
|
||||
if self.wasm_viewport_surface.is_none() {
|
||||
let surface_handle = app_io.create_window();
|
||||
let wasm_surface = executor
|
||||
.create_surface(graphene_std::wasm_application_io::WasmSurfaceHandle {
|
||||
surface: surface_handle.surface.clone(),
|
||||
window_id: surface_handle.window_id,
|
||||
})
|
||||
.expect("Failed to create surface");
|
||||
self.wasm_viewport_surface = Some(Arc::new(wasm_surface));
|
||||
}
|
||||
|
||||
let surface = self.wasm_viewport_surface.as_ref().unwrap();
|
||||
|
||||
// Use logical resolution for CSS sizing, physical resolution for the actual surface/texture
|
||||
let physical_resolution = render_config.viewport.resolution;
|
||||
let logical_resolution = physical_resolution.as_dvec2() / render_config.scale;
|
||||
|
||||
// Blit the texture to the surface
|
||||
let mut encoder = executor.context.device.create_command_encoder(&vello::wgpu::CommandEncoderDescriptor {
|
||||
label: Some("Texture to Surface Blit"),
|
||||
});
|
||||
|
||||
// Configure the surface at physical resolution (for HiDPI displays)
|
||||
let surface_inner = &surface.surface.inner;
|
||||
let surface_caps = surface_inner.get_capabilities(&executor.context.adapter);
|
||||
surface_inner.configure(
|
||||
&executor.context.device,
|
||||
&vello::wgpu::SurfaceConfiguration {
|
||||
usage: vello::wgpu::TextureUsages::RENDER_ATTACHMENT | vello::wgpu::TextureUsages::COPY_DST,
|
||||
format: vello::wgpu::TextureFormat::Rgba8Unorm,
|
||||
width: physical_resolution.x,
|
||||
height: physical_resolution.y,
|
||||
present_mode: surface_caps.present_modes[0],
|
||||
alpha_mode: vello::wgpu::CompositeAlphaMode::Opaque,
|
||||
view_formats: vec![],
|
||||
desired_maximum_frame_latency: 2,
|
||||
},
|
||||
);
|
||||
|
||||
let surface_texture = surface_inner.get_current_texture().expect("Failed to get surface texture");
|
||||
|
||||
// Blit the rendered texture to the surface
|
||||
surface.surface.blitter.copy(
|
||||
&executor.context.device,
|
||||
&mut encoder,
|
||||
&image_texture.texture.create_view(&vello::wgpu::TextureViewDescriptor::default()),
|
||||
&surface_texture.texture.create_view(&vello::wgpu::TextureViewDescriptor::default()),
|
||||
);
|
||||
|
||||
executor.context.queue.submit([encoder.finish()]);
|
||||
surface_texture.present();
|
||||
|
||||
let frame = graphene_std::application_io::SurfaceFrame {
|
||||
surface_id: surface.window_id,
|
||||
resolution: logical_resolution,
|
||||
transform: glam::DAffine2::IDENTITY,
|
||||
};
|
||||
|
||||
(
|
||||
Ok(TaggedValue::RenderOutput(RenderOutput {
|
||||
data: RenderOutputType::CanvasFrame(frame),
|
||||
metadata,
|
||||
})),
|
||||
None,
|
||||
)
|
||||
}
|
||||
Ok(TaggedValue::RenderOutput(RenderOutput {
|
||||
data: RenderOutputType::Texture(texture),
|
||||
metadata,
|
||||
|
||||
Reference in New Issue
Block a user