From 02ac81b981476ce5e145c9145326a7922073801a Mon Sep 17 00:00:00 2001 From: Ayush Amawate Date: Wed, 18 Mar 2026 05:44:52 +0530 Subject: [PATCH 1/4] fix Firefox color rendering by respecting surface texture format preference --- editor/src/node_graph_executor/runtime.rs | 24 +++++++------------ node-graph/libraries/wgpu-executor/src/lib.rs | 5 +++- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/editor/src/node_graph_executor/runtime.rs b/editor/src/node_graph_executor/runtime.rs index 26102cda07..80321990bd 100644 --- a/editor/src/node_graph_executor/runtime.rs +++ b/editor/src/node_graph_executor/runtime.rs @@ -348,11 +348,13 @@ impl NodeRuntime { // 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); + // Use the surface's preferred format (Firefox WebGL prefers Bgra8Unorm, Chrome prefers Rgba8Unorm) + let surface_format = surface_caps.formats.iter().copied().find(|f| f.is_srgb()).unwrap_or(surface_caps.formats[0]); 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, + format: surface_format, width: physical_resolution.x, height: physical_resolution.y, present_mode: surface_caps.present_modes[0], @@ -365,21 +367,11 @@ impl NodeRuntime { let surface_texture = surface_inner.get_current_texture().expect("Failed to get surface texture"); self.current_viewport_texture = Some(image_texture.clone()); - encoder.copy_texture_to_texture( - vello::wgpu::TexelCopyTextureInfoBase { - texture: image_texture.texture.as_ref(), - mip_level: 0, - origin: Default::default(), - aspect: Default::default(), - }, - vello::wgpu::TexelCopyTextureInfoBase { - texture: &surface_texture.texture, - mip_level: 0, - origin: Default::default(), - aspect: Default::default(), - }, - image_texture.texture.size(), - ); + // Use the blitter to copy the texture to the surface, handling format conversion + // (e.g., Rgba8Unorm source to Bgra8Unorm surface on Firefox) + let source_view = image_texture.texture.create_view(&vello::wgpu::TextureViewDescriptor::default()); + let target_view = surface_texture.texture.create_view(&vello::wgpu::TextureViewDescriptor::default()); + surface.surface.blitter.copy(&executor.context.device, &mut encoder, &source_view, &target_view); executor.context.queue.submit([encoder.finish()]); surface_texture.present(); diff --git a/node-graph/libraries/wgpu-executor/src/lib.rs b/node-graph/libraries/wgpu-executor/src/lib.rs index e98869238d..ec3d858b82 100644 --- a/node-graph/libraries/wgpu-executor/src/lib.rs +++ b/node-graph/libraries/wgpu-executor/src/lib.rs @@ -173,7 +173,10 @@ impl WgpuExecutor { } pub fn create_surface_inner(&self, surface: wgpu::Surface<'static>, window_id: SurfaceId) -> Result> { - let blitter = TextureBlitter::new(&self.context.device, VELLO_SURFACE_FORMAT); + // Get the surface's preferred format (Firefox WebGL may prefer Bgra8Unorm, Chrome prefers Rgba8Unorm) + let surface_caps = surface.get_capabilities(&self.context.adapter); + let surface_format = surface_caps.formats.iter().copied().find(|f| f.is_srgb()).unwrap_or(surface_caps.formats[0]); + let blitter = TextureBlitter::new(&self.context.device, surface_format); Ok(SurfaceHandle { window_id, surface: Surface { From fbbeadd703bfa3ea910955645b57ebc396e54181 Mon Sep 17 00:00:00 2001 From: Ayush Amawate Date: Wed, 18 Mar 2026 07:25:47 +0530 Subject: [PATCH 2/4] apply gemini suggestions --- editor/src/node_graph_executor/runtime.rs | 4 +--- node-graph/libraries/wgpu-executor/src/lib.rs | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/editor/src/node_graph_executor/runtime.rs b/editor/src/node_graph_executor/runtime.rs index 80321990bd..59c970d866 100644 --- a/editor/src/node_graph_executor/runtime.rs +++ b/editor/src/node_graph_executor/runtime.rs @@ -348,13 +348,11 @@ impl NodeRuntime { // 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); - // Use the surface's preferred format (Firefox WebGL prefers Bgra8Unorm, Chrome prefers Rgba8Unorm) - let surface_format = surface_caps.formats.iter().copied().find(|f| f.is_srgb()).unwrap_or(surface_caps.formats[0]); surface_inner.configure( &executor.context.device, &vello::wgpu::SurfaceConfiguration { usage: vello::wgpu::TextureUsages::RENDER_ATTACHMENT | vello::wgpu::TextureUsages::COPY_DST, - format: surface_format, + format: surface.surface.format, width: physical_resolution.x, height: physical_resolution.y, present_mode: surface_caps.present_modes[0], diff --git a/node-graph/libraries/wgpu-executor/src/lib.rs b/node-graph/libraries/wgpu-executor/src/lib.rs index ec3d858b82..8319daea8e 100644 --- a/node-graph/libraries/wgpu-executor/src/lib.rs +++ b/node-graph/libraries/wgpu-executor/src/lib.rs @@ -49,6 +49,7 @@ pub struct Surface { pub inner: wgpu::Surface<'static>, pub target_texture: Mutex>, pub blitter: TextureBlitter, + pub format: wgpu::TextureFormat, } #[derive(Clone, Debug)] @@ -183,6 +184,7 @@ impl WgpuExecutor { inner: surface, target_texture: Mutex::new(None), blitter, + format: surface_format, }, }) } From 1ad5ed2fa9d95b8358e063237dd0572acb23d777 Mon Sep 17 00:00:00 2001 From: Ayush Amawate Date: Tue, 24 Mar 2026 08:22:32 +0530 Subject: [PATCH 3/4] use direct copy for chrome and convert for firefox --- editor/src/node_graph_executor/runtime.rs | 29 +++++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/editor/src/node_graph_executor/runtime.rs b/editor/src/node_graph_executor/runtime.rs index 59c970d866..eadc9aba96 100644 --- a/editor/src/node_graph_executor/runtime.rs +++ b/editor/src/node_graph_executor/runtime.rs @@ -365,11 +365,30 @@ impl NodeRuntime { let surface_texture = surface_inner.get_current_texture().expect("Failed to get surface texture"); self.current_viewport_texture = Some(image_texture.clone()); - // Use the blitter to copy the texture to the surface, handling format conversion - // (e.g., Rgba8Unorm source to Bgra8Unorm surface on Firefox) - let source_view = image_texture.texture.create_view(&vello::wgpu::TextureViewDescriptor::default()); - let target_view = surface_texture.texture.create_view(&vello::wgpu::TextureViewDescriptor::default()); - surface.surface.blitter.copy(&executor.context.device, &mut encoder, &source_view, &target_view); + // Only use the blitter if formats differ, otherwise use efficient direct copy + if surface.surface.format == vello::wgpu::TextureFormat::Rgba8Unorm { + // Same format as Vello's output - use direct texture copy + encoder.copy_texture_to_texture( + vello::wgpu::TexelCopyTextureInfoBase { + texture: image_texture.texture.as_ref(), + mip_level: 0, + origin: Default::default(), + aspect: Default::default(), + }, + vello::wgpu::TexelCopyTextureInfoBase { + texture: &surface_texture.texture, + mip_level: 0, + origin: Default::default(), + aspect: Default::default(), + }, + image_texture.texture.size(), + ); + } else { + // Different format (e.g., Firefox's Bgra8Unorm on Mac) - use blitter for conversion + let source_view = image_texture.texture.create_view(&vello::wgpu::TextureViewDescriptor::default()); + let target_view = surface_texture.texture.create_view(&vello::wgpu::TextureViewDescriptor::default()); + surface.surface.blitter.copy(&executor.context.device, &mut encoder, &source_view, &target_view); + } executor.context.queue.submit([encoder.finish()]); surface_texture.present(); From c19c6a0fa5f4d4cdfc170d5cbe3ba4fe94288a1b Mon Sep 17 00:00:00 2001 From: Ayush Amawate Date: Tue, 24 Mar 2026 10:14:04 +0530 Subject: [PATCH 4/4] bug fix : simplify surface format selection by using preferred format directly --- node-graph/libraries/wgpu-executor/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node-graph/libraries/wgpu-executor/src/lib.rs b/node-graph/libraries/wgpu-executor/src/lib.rs index 8319daea8e..f2e27ef448 100644 --- a/node-graph/libraries/wgpu-executor/src/lib.rs +++ b/node-graph/libraries/wgpu-executor/src/lib.rs @@ -174,9 +174,9 @@ impl WgpuExecutor { } pub fn create_surface_inner(&self, surface: wgpu::Surface<'static>, window_id: SurfaceId) -> Result> { - // Get the surface's preferred format (Firefox WebGL may prefer Bgra8Unorm, Chrome prefers Rgba8Unorm) + // Use the surface's preferred format (Firefox prefers Bgra8Unorm, Chrome prefers Rgba8Unorm) let surface_caps = surface.get_capabilities(&self.context.adapter); - let surface_format = surface_caps.formats.iter().copied().find(|f| f.is_srgb()).unwrap_or(surface_caps.formats[0]); + let surface_format = surface_caps.formats[0]; let blitter = TextureBlitter::new(&self.context.device, surface_format); Ok(SurfaceHandle { window_id,