# Patch: egui-wgpu 0.34.2 - runtime MSAA (used by TCAD Viewer)
# Against crates.io egui-wgpu 0.34.2, src/ only.
#
# Apply inside an extracted egui-wgpu-0.34.2 tree:
#   patch -p1 < egui-wgpu-0.34.2-runtime-msaa.patch
# Then point Cargo [patch.crates-io] at that tree, or vendor it.
#
diff --git a/egui-wgpu-0.34.2/src/lib.rs b/egui-wgpu-0.34.2/src/lib.rs
index 64e3551..009e2f7 100644
--- a/egui-wgpu-0.34.2/src/lib.rs
+++ b/egui-wgpu-0.34.2/src/lib.rs
@@ -21,9 +21,12 @@ pub use wgpu;
 /// Low-level painting of [`egui`](https://github.com/emilk/egui) on [`wgpu`].
 mod renderer;
 
+mod runtime_msaa;
+
 mod setup;
 
 pub use renderer::*;
+pub use runtime_msaa::request_msaa;
 pub use setup::{
     EguiDisplayHandle, NativeAdapterSelectorMethod, WgpuSetup, WgpuSetupCreateNew,
     WgpuSetupExisting,
diff --git a/egui-wgpu-0.34.2/src/renderer.rs b/egui-wgpu-0.34.2/src/renderer.rs
index e55f758..94876c3 100644
--- a/egui-wgpu-0.34.2/src/renderer.rs
+++ b/egui-wgpu-0.34.2/src/renderer.rs
@@ -235,6 +235,9 @@ impl Default for RendererOptions {
 /// Renderer for a egui based GUI.
 pub struct Renderer {
     pipeline: wgpu::RenderPipeline,
+    shader_module: wgpu::ShaderModule,
+    pipeline_layout: wgpu::PipelineLayout,
+    output_color_format: wgpu::TextureFormat,
 
     index_buffer: SlicedBuffer,
     vertex_buffer: SlicedBuffer,
@@ -259,6 +262,83 @@ pub struct Renderer {
     pub callback_resources: CallbackResources,
 }
 
+fn create_egui_render_pipeline(
+    device: &wgpu::Device,
+    pipeline_layout: &wgpu::PipelineLayout,
+    module: &wgpu::ShaderModule,
+    output_color_format: wgpu::TextureFormat,
+    options: &RendererOptions,
+) -> wgpu::RenderPipeline {
+    let depth_stencil = options.depth_stencil_format.map(|format| wgpu::DepthStencilState {
+        format,
+        depth_write_enabled: Some(false),
+        depth_compare: Some(wgpu::CompareFunction::Always),
+        stencil: wgpu::StencilState::default(),
+        bias: wgpu::DepthBiasState::default(),
+    });
+
+    profiling::scope!("create_render_pipeline");
+    device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
+        label: Some("egui_pipeline"),
+        layout: Some(pipeline_layout),
+        vertex: wgpu::VertexState {
+            entry_point: Some("vs_main"),
+            module,
+            buffers: &[wgpu::VertexBufferLayout {
+                array_stride: 5 * 4,
+                step_mode: wgpu::VertexStepMode::Vertex,
+                attributes: &wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2, 2 => Uint32],
+            }],
+            compilation_options: wgpu::PipelineCompilationOptions::default(),
+        },
+        primitive: wgpu::PrimitiveState {
+            topology: wgpu::PrimitiveTopology::TriangleList,
+            unclipped_depth: false,
+            conservative: false,
+            cull_mode: None,
+            front_face: wgpu::FrontFace::default(),
+            polygon_mode: wgpu::PolygonMode::default(),
+            strip_index_format: None,
+        },
+        depth_stencil,
+        multisample: wgpu::MultisampleState {
+            alpha_to_coverage_enabled: false,
+            count: options.msaa_samples.max(1),
+            mask: !0,
+        },
+        fragment: Some(wgpu::FragmentState {
+            module,
+            entry_point: Some(if output_color_format.is_srgb() {
+                log::warn!(
+                    "Detected a linear (sRGBA aware) framebuffer {output_color_format:?}. egui prefers Rgba8Unorm or Bgra8Unorm"
+                );
+                "fs_main_linear_framebuffer"
+            } else {
+                "fs_main_gamma_framebuffer"
+            }),
+            targets: &[Some(wgpu::ColorTargetState {
+                format: output_color_format,
+                blend: Some(wgpu::BlendState {
+                    color: wgpu::BlendComponent {
+                        src_factor: wgpu::BlendFactor::One,
+                        dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
+                        operation: wgpu::BlendOperation::Add,
+                    },
+                    alpha: wgpu::BlendComponent {
+                        src_factor: wgpu::BlendFactor::OneMinusDstAlpha,
+                        dst_factor: wgpu::BlendFactor::One,
+                        operation: wgpu::BlendOperation::Add,
+                    },
+                }),
+                write_mask: wgpu::ColorWrites::ALL,
+            })],
+            compilation_options: wgpu::PipelineCompilationOptions::default(),
+        }),
+        multiview_mask: None,
+        cache: None,
+    })
+}
+
 impl Renderer {
     /// Creates a renderer for a egui UI.
     ///
@@ -357,81 +437,13 @@ impl Renderer {
             immediate_size: 0,
         });
 
-        let depth_stencil = options
-            .depth_stencil_format
-            .map(|format| wgpu::DepthStencilState {
-                format,
-                depth_write_enabled: Some(false),
-                depth_compare: Some(wgpu::CompareFunction::Always),
-                stencil: wgpu::StencilState::default(),
-                bias: wgpu::DepthBiasState::default(),
-            });
-
-        let pipeline = {
-            profiling::scope!("create_render_pipeline");
-            device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
-                label: Some("egui_pipeline"),
-                layout: Some(&pipeline_layout),
-                vertex: wgpu::VertexState {
-                    entry_point: Some("vs_main"),
-                    module: &module,
-                    buffers: &[wgpu::VertexBufferLayout {
-                        array_stride: 5 * 4,
-                        step_mode: wgpu::VertexStepMode::Vertex,
-                        // 0: vec2 position
-                        // 1: vec2 texture coordinates
-                        // 2: uint color
-                        attributes: &wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2, 2 => Uint32],
-                    }],
-                    compilation_options: wgpu::PipelineCompilationOptions::default()
-                },
-                primitive: wgpu::PrimitiveState {
-                    topology: wgpu::PrimitiveTopology::TriangleList,
-                    unclipped_depth: false,
-                    conservative: false,
-                    cull_mode: None,
-                    front_face: wgpu::FrontFace::default(),
-                    polygon_mode: wgpu::PolygonMode::default(),
-                    strip_index_format: None,
-                },
-                depth_stencil,
-                multisample: wgpu::MultisampleState {
-                    alpha_to_coverage_enabled: false,
-                    count: options.msaa_samples.max(1),
-                    mask: !0,
-                },
-
-                fragment: Some(wgpu::FragmentState {
-                    module: &module,
-                    entry_point: Some(if output_color_format.is_srgb() {
-                        log::warn!("Detected a linear (sRGBA aware) framebuffer {output_color_format:?}. egui prefers Rgba8Unorm or Bgra8Unorm");
-                        "fs_main_linear_framebuffer"
-                    } else {
-                        "fs_main_gamma_framebuffer" // this is what we prefer
-                    }),
-                    targets: &[Some(wgpu::ColorTargetState {
-                        format: output_color_format,
-                        blend: Some(wgpu::BlendState {
-                            color: wgpu::BlendComponent {
-                                src_factor: wgpu::BlendFactor::One,
-                                dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
-                                operation: wgpu::BlendOperation::Add,
-                            },
-                            alpha: wgpu::BlendComponent {
-                                src_factor: wgpu::BlendFactor::OneMinusDstAlpha,
-                                dst_factor: wgpu::BlendFactor::One,
-                                operation: wgpu::BlendOperation::Add,
-                            },
-                        }),
-                        write_mask: wgpu::ColorWrites::ALL,
-                    })],
-                    compilation_options: wgpu::PipelineCompilationOptions::default()
-                }),
-                multiview_mask: None,
-                cache: None,
-            }
-        )
-        };
+        let pipeline = create_egui_render_pipeline(
+            device,
+            &pipeline_layout,
+            &module,
+            output_color_format,
+            &options,
+        );
 
         const VERTEX_BUFFER_START_CAPACITY: wgpu::BufferAddress =
             (std::mem::size_of::<Vertex>() * 1024) as _;
@@ -440,6 +452,9 @@ impl Renderer {
 
         Self {
             pipeline,
+            shader_module: module,
+            pipeline_layout,
+            output_color_format,
             vertex_buffer: SlicedBuffer {
                 buffer: create_vertex_buffer(device, VERTEX_BUFFER_START_CAPACITY),
                 slices: Vec::with_capacity(64),
@@ -463,6 +478,22 @@ impl Renderer {
         }
     }
 
+    /// Recreate only the render pipeline when MSAA changes (keeps font/UI textures).
+    pub fn set_msaa_samples(&mut self, device: &wgpu::Device, msaa_samples: u32) {
+        let msaa_samples = msaa_samples.max(1);
+        if self.options.msaa_samples == msaa_samples {
+            return;
+        }
+        self.options.msaa_samples = msaa_samples;
+        self.pipeline = create_egui_render_pipeline(
+            device,
+            &self.pipeline_layout,
+            &self.shader_module,
+            self.output_color_format,
+            &self.options,
+        );
+    }
+
     /// Executes the egui renderer onto an existing wgpu renderpass.
     ///
     /// Note that the lifetime of `render_pass` is `'static` which requires a call to [`wgpu::RenderPass::forget_lifetime`].
diff --git a/egui-wgpu-0.34.2/src/runtime_msaa.rs b/egui-wgpu-0.34.2/src/runtime_msaa.rs
new file mode 100644
index 0000000..1439921
--- /dev/null
+++ b/egui-wgpu-0.34.2/src/runtime_msaa.rs
@@ -0,0 +1,22 @@
+//! Pending MSAA changes applied at the start of the next Painter frame.
+
+use std::sync::atomic::{AtomicU32, Ordering};
+
+/// Bit 31 = pending flag; low bits = sample count (1 or 4).
+static PENDING_MSAA: AtomicU32 = AtomicU32::new(0);
+const PENDING_FLAG: u32 = 1 << 31;
+
+/// Request MSAA sample count for all Painter instances on the next paint.
+pub fn request_msaa(samples: u32) {
+    let samples = samples.max(1);
+    PENDING_MSAA.store(samples | PENDING_FLAG, Ordering::Release);
+}
+
+pub(crate) fn take_pending_msaa() -> Option<u32> {
+    let v = PENDING_MSAA.swap(0, Ordering::AcqRel);
+    if v & PENDING_FLAG != 0 {
+        Some(v & !PENDING_FLAG)
+    } else {
+        None
+    }
+}
diff --git a/egui-wgpu-0.34.2/src/winit.rs b/egui-wgpu-0.34.2/src/winit.rs
index 3f6adfc..e2c12ca 100644
--- a/egui-wgpu-0.34.2/src/winit.rs
+++ b/egui-wgpu-0.34.2/src/winit.rs
@@ -384,6 +384,30 @@ impl Painter {
         state.resizing = resizing;
     }
 
+    /// Change MSAA sample count and recreate depth/MSAA attachments for this viewport.
+    pub fn apply_msaa_samples(&mut self, viewport_id: ViewportId, samples: u32) {
+        let samples = samples.max(1);
+        if self.options.msaa_samples == samples {
+            return;
+        }
+        self.options.msaa_samples = samples;
+        if samples <= 1 {
+            self.msaa_texture_view.remove(&viewport_id);
+        }
+        if let Some(state) = self.surfaces.get(&viewport_id) {
+            if let (Some(w), Some(h)) = (
+                NonZeroU32::new(state.width.max(1)),
+                NonZeroU32::new(state.height.max(1)),
+            ) {
+                self.resize_and_generate_depth_texture_view_and_msaa_view(
+                    viewport_id,
+                    w,
+                    h,
+                );
+            }
+        }
+    }
+
     pub fn on_window_resized(
         &mut self,
         viewport_id: ViewportId,
@@ -422,6 +446,10 @@ impl Painter {
     ) -> f32 {
         profiling::function_scope!();
 
+        if let Some(samples) = crate::runtime_msaa::take_pending_msaa() {
+            self.apply_msaa_samples(viewport_id, samples);
+        }
+
         /// Guard to ensure that commands are always submitted to the renderer queue
         /// so that calls to [`write_buffer()`](https://docs.rs/wgpu/latest/wgpu/struct.Queue.html#method.write_buffer)
         /// are completed even if we take a codepath which doesn't submit commands and avoids
