From 9c570099a664f6d4676fc7fa895bf1ed03194d28 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Fri, 14 Nov 2025 22:26:47 -0500 Subject: [PATCH 1/3] Preliminary implementation --- Cargo.lock | 3 +-- Cargo.toml | 2 +- wgpu-hal/src/gles/adapter.rs | 1 + wgpu-hal/src/gles/command.rs | 13 +++++++++++++ wgpu-hal/src/gles/mod.rs | 3 +++ wgpu-hal/src/gles/queue.rs | 23 +++++++++++++++-------- 6 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d832ff45cfc..6eaa55f1d2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1741,8 +1741,7 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "glow" version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" +source = "git+https://github.com/opstic/glow?branch=multisampled_render_to_texture#0273b1a321c47c88b1e6709fa043a53340bce113" dependencies = [ "js-sys", "slotmap", diff --git a/Cargo.toml b/Cargo.toml index 965556b6b4f..99dffca5ada 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -221,7 +221,7 @@ windows-core = { version = "0.62", default-features = false } # Gles dependencies khronos-egl = "6" -glow = "0.16" +glow = { git = "https://github.com/opstic/glow", branch = "multisampled_render_to_texture" } glutin = { version = "0.31", default-features = false } glutin-winit = { version = "0.4", default-features = false } glutin_wgl_sys = "0.6" diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 6ee5f713734..28b33b49986 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -650,6 +650,7 @@ impl super::Adapter { // that's the only way to get gl_InstanceID to work correctly. features.set(wgt::Features::INDIRECT_FIRST_INSTANCE, supported); } + private_caps.set(super::PrivateCapabilities::MULTISAMPLED_RENDER_TO_TEXTURE, extensions.contains("GL_EXT_multisampled_render_to_texture")); let max_texture_size = unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) } as u32; let max_texture_3d_size = unsafe { gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) } as u32; diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 6136b4fd034..f24076a1b1c 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -558,10 +558,22 @@ impl crate::CommandEncoder for super::CommandEncoder { for (i, cat) in desc.color_attachments.iter().enumerate() { if let Some(cat) = cat.as_ref() { let attachment = glow::COLOR_ATTACHMENT0 + i as u32; + if let Some(ref rat) = cat.resolve_target { + if self.private_caps.contains(super::PrivateCapabilities::MULTISAMPLED_RENDER_TO_TEXTURE) && cat.target.usage.contains(wgt::TextureUses::TRANSIENT) { + self.cmd_buffer.commands.push(C::BindAttachment { + attachment, + view: rat.view.clone(), + depth_slice: None, + sample_count: desc.sample_count, + }); + continue; + } + } self.cmd_buffer.commands.push(C::BindAttachment { attachment, view: cat.target.view.clone(), depth_slice: cat.depth_slice, + sample_count: 1, }); if let Some(ref rat) = cat.resolve_target { self.state @@ -584,6 +596,7 @@ impl crate::CommandEncoder for super::CommandEncoder { attachment, view: dsat.target.view.clone(), depth_slice: None, + sample_count: 1, }); if aspects.contains(crate::FormatAspects::DEPTH) && !dsat.depth_ops.contains(crate::AttachmentOps::STORE) diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index aad85106b10..0a489948002 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -232,6 +232,8 @@ bitflags::bitflags! { /// /// When this is true, instance offset emulation via vertex buffer rebinding and a shader uniform will be disabled. const FULLY_FEATURED_INSTANCING = 1 << 16; + /// Supports direct multisampled rendering to a texture without needing a resolve texture. + const MULTISAMPLED_RENDER_TO_TEXTURE = 1 << 17; } } @@ -924,6 +926,7 @@ enum Command { attachment: u32, view: TextureView, depth_slice: Option, + sample_count: u32, }, ResolveAttachment { attachment: u32, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 5ce0cac30b4..e28ba444e86 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -111,6 +111,7 @@ impl super::Queue { attachment: u32, view: &super::TextureView, depth_slice: Option, + sample_count: u32, ) { match view.inner { super::TextureInner::Renderbuffer { raw } => { @@ -156,13 +157,17 @@ impl super::Queue { } else { unsafe { assert_eq!(view.mip_levels.len(), 1); - gl.framebuffer_texture_2d( - fbo_target, - attachment, - get_2d_target(target, view.array_layers.start), - Some(raw), - view.mip_levels.start as i32, - ) + if sample_count != 1 { + gl.framebuffer_texture_2d_multisample(fbo_target, attachment, get_2d_target(target, view.array_layers.start), Some(raw), view.mip_levels.start as i32, sample_count as i32) + } else { + gl.framebuffer_texture_2d( + fbo_target, + attachment, + get_2d_target(target, view.array_layers.start), + Some(raw), + view.mip_levels.start as i32, + ) + } }; } } @@ -1119,9 +1124,10 @@ impl super::Queue { attachment, ref view, depth_slice, + sample_count, } => { unsafe { - self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, attachment, view, depth_slice) + self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, attachment, view, depth_slice, sample_count) }; } C::ResolveAttachment { @@ -1139,6 +1145,7 @@ impl super::Queue { glow::COLOR_ATTACHMENT0, dst, None, + 1, ) }; unsafe { From a30c11057b991c35897e921247b1f1ba406f8b84 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 16 Nov 2025 18:58:27 -0500 Subject: [PATCH 2/3] Improvement --- wgpu-hal/src/gles/adapter.rs | 5 ++++- wgpu-hal/src/gles/command.rs | 10 +++++++++- wgpu-hal/src/gles/queue.rs | 18 ++++++++++++++++-- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 28b33b49986..50e32996ec5 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -650,7 +650,10 @@ impl super::Adapter { // that's the only way to get gl_InstanceID to work correctly. features.set(wgt::Features::INDIRECT_FIRST_INSTANCE, supported); } - private_caps.set(super::PrivateCapabilities::MULTISAMPLED_RENDER_TO_TEXTURE, extensions.contains("GL_EXT_multisampled_render_to_texture")); + private_caps.set( + super::PrivateCapabilities::MULTISAMPLED_RENDER_TO_TEXTURE, + extensions.contains("GL_EXT_multisampled_render_to_texture"), + ); let max_texture_size = unsafe { gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) } as u32; let max_texture_3d_size = unsafe { gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) } as u32; diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index f24076a1b1c..a11024c972e 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -558,8 +558,16 @@ impl crate::CommandEncoder for super::CommandEncoder { for (i, cat) in desc.color_attachments.iter().enumerate() { if let Some(cat) = cat.as_ref() { let attachment = glow::COLOR_ATTACHMENT0 + i as u32; + // Try to use the multisampled render-to-texture extension to avoid resolving if let Some(ref rat) = cat.resolve_target { - if self.private_caps.contains(super::PrivateCapabilities::MULTISAMPLED_RENDER_TO_TEXTURE) && cat.target.usage.contains(wgt::TextureUses::TRANSIENT) { + if matches!(rat.view.inner, super::TextureInner::Texture { .. }) + && self.private_caps.contains( + super::PrivateCapabilities::MULTISAMPLED_RENDER_TO_TEXTURE, + ) + && !cat.ops.contains(crate::AttachmentOps::STORE) + // Extension specifies that only COLOR_ATTACHMENT0 is valid + && i == 0 + { self.cmd_buffer.commands.push(C::BindAttachment { attachment, view: rat.view.clone(), diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index e28ba444e86..afb9f926bf7 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -158,7 +158,14 @@ impl super::Queue { unsafe { assert_eq!(view.mip_levels.len(), 1); if sample_count != 1 { - gl.framebuffer_texture_2d_multisample(fbo_target, attachment, get_2d_target(target, view.array_layers.start), Some(raw), view.mip_levels.start as i32, sample_count as i32) + gl.framebuffer_texture_2d_multisample( + fbo_target, + attachment, + get_2d_target(target, view.array_layers.start), + Some(raw), + view.mip_levels.start as i32, + sample_count as i32, + ) } else { gl.framebuffer_texture_2d( fbo_target, @@ -1127,7 +1134,14 @@ impl super::Queue { sample_count, } => { unsafe { - self.set_attachment(gl, glow::DRAW_FRAMEBUFFER, attachment, view, depth_slice, sample_count) + self.set_attachment( + gl, + glow::DRAW_FRAMEBUFFER, + attachment, + view, + depth_slice, + sample_count, + ) }; } C::ResolveAttachment { From 20850a8cb1da0ad6d1f8336128eecd8014fba5e4 Mon Sep 17 00:00:00 2001 From: Opstic <46141527+opstic@users.noreply.github.com> Date: Sun, 16 Nov 2025 19:08:03 -0500 Subject: [PATCH 3/3] Oops --- Cargo.lock | 3 ++- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6eaa55f1d2c..d832ff45cfc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1741,7 +1741,8 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "glow" version = "0.16.0" -source = "git+https://github.com/opstic/glow?branch=multisampled_render_to_texture#0273b1a321c47c88b1e6709fa043a53340bce113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" dependencies = [ "js-sys", "slotmap", diff --git a/Cargo.toml b/Cargo.toml index 99dffca5ada..965556b6b4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -221,7 +221,7 @@ windows-core = { version = "0.62", default-features = false } # Gles dependencies khronos-egl = "6" -glow = { git = "https://github.com/opstic/glow", branch = "multisampled_render_to_texture" } +glow = "0.16" glutin = { version = "0.31", default-features = false } glutin-winit = { version = "0.4", default-features = false } glutin_wgl_sys = "0.6"