Skip to main content

rgpui_wgpu/
wgpu_renderer.rs

1use crate::{CompositorGpuHint, WgpuAtlas, WgpuContext};
2use bytemuck::{Pod, Zeroable};
3use log::warn;
4#[cfg(not(target_family = "wasm"))]
5use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
6use rgpui::{
7    AtlasTextureId, Background, Bounds, DevicePixels, GpuSpecs, MonochromeSprite, Path, Point,
8    PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size, SubpixelSprite,
9    Underline, get_gamma_correction_ratios,
10};
11use std::cell::RefCell;
12use std::num::NonZeroU64;
13use std::rc::Rc;
14use std::sync::{Arc, Mutex};
15
16#[repr(C)]
17#[derive(Clone, Copy, Pod, Zeroable)]
18/// 全局渲染参数,传递给着色器
19struct GlobalParams {
20    viewport_size: [f32; 2],
21    premultiplied_alpha: u32,
22    pad: u32,
23}
24
25#[repr(C)]
26#[derive(Clone, Copy, Pod, Zeroable)]
27/// POD 格式的边界框,用于 GPU 传输
28struct PodBounds {
29    origin: [f32; 2],
30    size: [f32; 2],
31}
32
33impl From<Bounds<ScaledPixels>> for PodBounds {
34    fn from(bounds: Bounds<ScaledPixels>) -> Self {
35        Self {
36            origin: [bounds.origin.x.0, bounds.origin.y.0],
37            size: [bounds.size.width.0, bounds.size.height.0],
38        }
39    }
40}
41
42#[repr(C)]
43#[derive(Clone, Copy, Pod, Zeroable)]
44/// 表面参数,包含边界和内容遮罩
45struct SurfaceParams {
46    bounds: PodBounds,
47    content_mask: PodBounds,
48}
49
50#[repr(C)]
51#[derive(Clone, Copy, Pod, Zeroable)]
52/// Gamma 校正参数
53struct GammaParams {
54    gamma_ratios: [f32; 4],
55    grayscale_enhanced_contrast: f32,
56    subpixel_enhanced_contrast: f32,
57    is_bgr: u32,
58    _pad: u32,
59}
60
61#[derive(Clone, Debug)]
62#[repr(C)]
63/// 路径精灵,用于路径渲染
64struct PathSprite {
65    bounds: Bounds<ScaledPixels>,
66}
67
68#[derive(Clone, Debug)]
69#[repr(C)]
70/// 路径光栅化顶点
71struct PathRasterizationVertex {
72    xy_position: Point<ScaledPixels>,
73    st_position: Point<f32>,
74    color: Background,
75    bounds: Bounds<ScaledPixels>,
76}
77
78pub struct WgpuSurfaceConfig {
79    pub size: Size<DevicePixels>,
80    pub transparent: bool,
81    /// 首选呈现模式。当为 `Some` 时,渲染器将使用此模式(如果表面支持),
82    /// 否则回退到 `Fifo`。当为 `None` 时,默认为 `Fifo`(垂直同步)。
83    /// 移动平台可能更喜欢 `Mailbox`(三重缓冲)以避免在生命周期转换期间
84    /// 在 `get_current_texture()` 中阻塞。
85    pub preferred_present_mode: Option<wgpu::PresentMode>,
86}
87
88/// wgpu 渲染管线集合
89struct WgpuPipelines {
90    quads: wgpu::RenderPipeline,
91    shadows: wgpu::RenderPipeline,
92    path_rasterization: wgpu::RenderPipeline,
93    paths: wgpu::RenderPipeline,
94    underlines: wgpu::RenderPipeline,
95    mono_sprites: wgpu::RenderPipeline,
96    subpixel_sprites: Option<wgpu::RenderPipeline>,
97    poly_sprites: wgpu::RenderPipeline,
98    #[allow(dead_code)]
99    surfaces: wgpu::RenderPipeline,
100}
101
102/// wgpu 绑定组布局集合
103struct WgpuBindGroupLayouts {
104    globals: wgpu::BindGroupLayout,
105    instances: wgpu::BindGroupLayout,
106    instances_with_texture: wgpu::BindGroupLayout,
107    surfaces: wgpu::BindGroupLayout,
108}
109
110/// 共享的 GPU 上下文引用,用于在多个窗口之间协调设备恢复。
111pub type GpuContext = Rc<RefCell<Option<WgpuContext>>>;
112
113/// GPU 资源集合,在设备恢复期间需要一起丢弃
114struct WgpuResources {
115    device: Arc<wgpu::Device>,
116    queue: Arc<wgpu::Queue>,
117    surface: wgpu::Surface<'static>,
118    pipelines: WgpuPipelines,
119    bind_group_layouts: WgpuBindGroupLayouts,
120    atlas_sampler: wgpu::Sampler,
121    globals_buffer: wgpu::Buffer,
122    globals_bind_group: wgpu::BindGroup,
123    path_globals_bind_group: wgpu::BindGroup,
124    instance_buffer: wgpu::Buffer,
125    path_intermediate_texture: Option<wgpu::Texture>,
126    path_intermediate_view: Option<wgpu::TextureView>,
127    path_msaa_texture: Option<wgpu::Texture>,
128    path_msaa_view: Option<wgpu::TextureView>,
129}
130
131impl WgpuResources {
132    /// 使中间纹理失效
133    fn invalidate_intermediate_textures(&mut self) {
134        self.path_intermediate_texture = None;
135        self.path_intermediate_view = None;
136        self.path_msaa_texture = None;
137        self.path_msaa_view = None;
138    }
139}
140
141pub struct WgpuRenderer {
142    /// 共享 GPU 上下文,用于设备恢复协调(WASM 上未使用)
143    #[allow(dead_code)]
144    context: Option<GpuContext>,
145    /// 合成器 GPU 提示,用于适配器选择(WASM 上未使用)
146    #[allow(dead_code)]
147    compositor_gpu: Option<CompositorGpuHint>,
148    resources: Option<WgpuResources>,
149    surface_config: wgpu::SurfaceConfiguration,
150    atlas: Arc<WgpuAtlas>,
151    path_globals_offset: u64,
152    gamma_offset: u64,
153    instance_buffer_capacity: u64,
154    max_buffer_size: u64,
155    storage_buffer_alignment: u64,
156    rendering_params: RenderingParameters,
157    is_bgr: bool,
158    dual_source_blending: bool,
159    adapter_info: wgpu::AdapterInfo,
160    transparent_alpha_mode: wgpu::CompositeAlphaMode,
161    opaque_alpha_mode: wgpu::CompositeAlphaMode,
162    max_texture_size: u32,
163    last_error: Arc<Mutex<Option<String>>>,
164    failed_frame_count: u32,
165    device_lost: std::sync::Arc<std::sync::atomic::AtomicBool>,
166    surface_configured: bool,
167    needs_redraw: bool,
168}
169
170impl WgpuRenderer {
171    /// 获取 GPU 资源引用
172    fn resources(&self) -> &WgpuResources {
173        self.resources
174            .as_ref()
175            .expect("GPU resources not available")
176    }
177
178    /// 获取 GPU 资源可变引用
179    fn resources_mut(&mut self) -> &mut WgpuResources {
180        self.resources
181            .as_mut()
182            .expect("GPU resources not available")
183    }
184
185    /// 从原始窗口句柄创建新的 WgpuRenderer。
186    ///
187    /// `gpu_context` 是一个共享引用,用于在多个窗口之间协调 GPU 上下文。
188    /// 第一个创建渲染器的窗口将初始化上下文;后续窗口将共享它。
189    ///
190    /// # 安全性
191    /// 调用者必须确保窗口句柄在返回的渲染器的生命周期内保持有效。
192    #[cfg(not(target_family = "wasm"))]
193    pub fn new<W>(
194        gpu_context: GpuContext,
195        window: &W,
196        config: WgpuSurfaceConfig,
197        compositor_gpu: Option<CompositorGpuHint>,
198    ) -> anyhow::Result<Self>
199    where
200        W: HasWindowHandle + HasDisplayHandle + std::fmt::Debug + Send + Sync + Clone + 'static,
201    {
202        let window_handle = window
203            .window_handle()
204            .map_err(|e| anyhow::anyhow!("Failed to get window handle: {e}"))?;
205
206        let target = wgpu::SurfaceTargetUnsafe::RawHandle {
207            // 回退到通过 InstanceDescriptor::display 已提供的显示句柄。
208            raw_display_handle: None,
209            raw_window_handle: window_handle.as_raw(),
210        };
211
212        // 如果已有上下文则使用其 instance,否则创建新的。
213        // 表面必须与用于适配器选择的相同 instance 创建,否则 wgpu 会 panic。
214        let instance = gpu_context
215            .borrow()
216            .as_ref()
217            .map(|ctx| ctx.instance.clone())
218            .unwrap_or_else(|| WgpuContext::instance(Box::new(window.clone())));
219
220        // 安全性:调用者保证窗口句柄在此渲染器的生命周期内有效。
221        // 实际上,RawWindow 结构体是从原生窗口句柄创建的,
222        // 并且表面在窗口之前被丢弃。
223        let surface = unsafe {
224            instance
225                .create_surface_unsafe(target)
226                .map_err(|e| anyhow::anyhow!("Failed to create surface: {e}"))?
227        };
228
229        let mut ctx_ref = gpu_context.borrow_mut();
230        let context = match ctx_ref.as_mut() {
231            Some(context) => {
232                context.check_compatible_with_surface(&surface)?;
233                context
234            }
235            None => ctx_ref.insert(WgpuContext::new(instance, &surface, compositor_gpu)?),
236        };
237
238        let atlas = Arc::new(WgpuAtlas::from_context(context));
239
240        Self::new_internal(
241            Some(Rc::clone(&gpu_context)),
242            context,
243            surface,
244            config,
245            compositor_gpu,
246            atlas,
247        )
248    }
249
250    #[cfg(target_family = "wasm")]
251    pub fn new_from_canvas(
252        context: &WgpuContext,
253        canvas: &web_sys::HtmlCanvasElement,
254        config: WgpuSurfaceConfig,
255    ) -> anyhow::Result<Self> {
256        let surface = context
257            .instance
258            .create_surface(wgpu::SurfaceTarget::Canvas(canvas.clone()))
259            .map_err(|e| anyhow::anyhow!("Failed to create surface: {e}"))?;
260
261        let atlas = Arc::new(WgpuAtlas::from_context(context));
262
263        Self::new_internal(None, context, surface, config, None, atlas)
264    }
265
266    fn new_internal(
267        gpu_context: Option<GpuContext>,
268        context: &WgpuContext,
269        surface: wgpu::Surface<'static>,
270        config: WgpuSurfaceConfig,
271        compositor_gpu: Option<CompositorGpuHint>,
272        atlas: Arc<WgpuAtlas>,
273    ) -> anyhow::Result<Self> {
274        let surface_caps = surface.get_capabilities(&context.adapter);
275        let preferred_formats = [
276            wgpu::TextureFormat::Bgra8Unorm,
277            wgpu::TextureFormat::Rgba8Unorm,
278        ];
279        let surface_format = preferred_formats
280            .iter()
281            .find(|f| surface_caps.formats.contains(f))
282            .copied()
283            .or_else(|| surface_caps.formats.iter().find(|f| !f.is_srgb()).copied())
284            .or_else(|| surface_caps.formats.first().copied())
285            .ok_or_else(|| {
286                anyhow::anyhow!(
287                    "Surface reports no supported texture formats for adapter {:?}",
288                    context.adapter.get_info().name
289                )
290            })?;
291
292        let pick_alpha_mode =
293            |preferences: &[wgpu::CompositeAlphaMode]| -> anyhow::Result<wgpu::CompositeAlphaMode> {
294                preferences
295                    .iter()
296                    .find(|p| surface_caps.alpha_modes.contains(p))
297                    .copied()
298                    .or_else(|| surface_caps.alpha_modes.first().copied())
299                    .ok_or_else(|| {
300                        anyhow::anyhow!(
301                            "Surface reports no supported alpha modes for adapter {:?}",
302                            context.adapter.get_info().name
303                        )
304                    })
305            };
306
307        let transparent_alpha_mode = pick_alpha_mode(&[
308            wgpu::CompositeAlphaMode::PreMultiplied,
309            wgpu::CompositeAlphaMode::Inherit,
310        ])?;
311
312        let opaque_alpha_mode = pick_alpha_mode(&[
313            wgpu::CompositeAlphaMode::Opaque,
314            wgpu::CompositeAlphaMode::Inherit,
315        ])?;
316
317        let alpha_mode = if config.transparent {
318            transparent_alpha_mode
319        } else {
320            opaque_alpha_mode
321        };
322
323        let device = Arc::clone(&context.device);
324        let max_texture_size = device.limits().max_texture_dimension_2d;
325
326        let requested_width = config.size.width.0 as u32;
327        let requested_height = config.size.height.0 as u32;
328        let clamped_width = requested_width.min(max_texture_size);
329        let clamped_height = requested_height.min(max_texture_size);
330
331        if clamped_width != requested_width || clamped_height != requested_height {
332            warn!(
333                "Requested surface size ({}, {}) exceeds maximum texture dimension {}. \
334                 Clamping to ({}, {}). Window content may not fill the entire window.",
335                requested_width, requested_height, max_texture_size, clamped_width, clamped_height
336            );
337        }
338
339        let surface_config = wgpu::SurfaceConfiguration {
340            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
341            format: surface_format,
342            width: clamped_width.max(1),
343            height: clamped_height.max(1),
344            present_mode: config
345                .preferred_present_mode
346                .filter(|mode| surface_caps.present_modes.contains(mode))
347                .unwrap_or(wgpu::PresentMode::Fifo),
348            desired_maximum_frame_latency: 2,
349            alpha_mode,
350            view_formats: vec![],
351        };
352        // Configure the surface immediately. The adapter selection process already validated
353        // that this adapter can successfully configure this surface.
354        surface.configure(&context.device, &surface_config);
355
356        let queue = Arc::clone(&context.queue);
357        let dual_source_blending = context.supports_dual_source_blending();
358
359        let rendering_params = RenderingParameters::new(&context.adapter, surface_format);
360        let bind_group_layouts = Self::create_bind_group_layouts(&device);
361        let pipelines = Self::create_pipelines(
362            &device,
363            &bind_group_layouts,
364            surface_format,
365            alpha_mode,
366            rendering_params.path_sample_count,
367            dual_source_blending,
368        );
369
370        let atlas_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
371            label: Some("atlas_sampler"),
372            mag_filter: wgpu::FilterMode::Linear,
373            min_filter: wgpu::FilterMode::Linear,
374            ..Default::default()
375        });
376
377        let uniform_alignment = device.limits().min_uniform_buffer_offset_alignment as u64;
378        let globals_size = std::mem::size_of::<GlobalParams>() as u64;
379        let gamma_size = std::mem::size_of::<GammaParams>() as u64;
380        let path_globals_offset = globals_size.next_multiple_of(uniform_alignment);
381        let gamma_offset = (path_globals_offset + globals_size).next_multiple_of(uniform_alignment);
382
383        let globals_buffer = device.create_buffer(&wgpu::BufferDescriptor {
384            label: Some("globals_buffer"),
385            size: gamma_offset + gamma_size,
386            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
387            mapped_at_creation: false,
388        });
389
390        let max_buffer_size = device.limits().max_buffer_size;
391        let storage_buffer_alignment = device.limits().min_storage_buffer_offset_alignment as u64;
392        let initial_instance_buffer_capacity = 2 * 1024 * 1024;
393        let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor {
394            label: Some("instance_buffer"),
395            size: initial_instance_buffer_capacity,
396            usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
397            mapped_at_creation: false,
398        });
399
400        let globals_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
401            label: Some("globals_bind_group"),
402            layout: &bind_group_layouts.globals,
403            entries: &[
404                wgpu::BindGroupEntry {
405                    binding: 0,
406                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
407                        buffer: &globals_buffer,
408                        offset: 0,
409                        size: Some(NonZeroU64::new(globals_size).unwrap()),
410                    }),
411                },
412                wgpu::BindGroupEntry {
413                    binding: 1,
414                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
415                        buffer: &globals_buffer,
416                        offset: gamma_offset,
417                        size: Some(NonZeroU64::new(gamma_size).unwrap()),
418                    }),
419                },
420            ],
421        });
422
423        let path_globals_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
424            label: Some("path_globals_bind_group"),
425            layout: &bind_group_layouts.globals,
426            entries: &[
427                wgpu::BindGroupEntry {
428                    binding: 0,
429                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
430                        buffer: &globals_buffer,
431                        offset: path_globals_offset,
432                        size: Some(NonZeroU64::new(globals_size).unwrap()),
433                    }),
434                },
435                wgpu::BindGroupEntry {
436                    binding: 1,
437                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
438                        buffer: &globals_buffer,
439                        offset: gamma_offset,
440                        size: Some(NonZeroU64::new(gamma_size).unwrap()),
441                    }),
442                },
443            ],
444        });
445
446        let adapter_info = context.adapter.get_info();
447
448        let last_error: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None));
449        let last_error_clone = Arc::clone(&last_error);
450        device.on_uncaptured_error(Arc::new(move |error| {
451            let mut guard = last_error_clone.lock().unwrap();
452            *guard = Some(error.to_string());
453        }));
454
455        let resources = WgpuResources {
456            device,
457            queue,
458            surface,
459            pipelines,
460            bind_group_layouts,
461            atlas_sampler,
462            globals_buffer,
463            globals_bind_group,
464            path_globals_bind_group,
465            instance_buffer,
466            // 延迟中间纹理创建到首次绘制调用,通过 ensure_intermediate_textures()。
467            // 这避免了在初始化期间设备/表面处于无效状态时的 panic。
468            path_intermediate_texture: None,
469            path_intermediate_view: None,
470            path_msaa_texture: None,
471            path_msaa_view: None,
472        };
473
474        Ok(Self {
475            context: gpu_context,
476            compositor_gpu,
477            resources: Some(resources),
478            surface_config,
479            atlas,
480            path_globals_offset,
481            gamma_offset,
482            instance_buffer_capacity: initial_instance_buffer_capacity,
483            max_buffer_size,
484            storage_buffer_alignment,
485            rendering_params,
486            is_bgr: false,
487            dual_source_blending,
488            adapter_info,
489            transparent_alpha_mode,
490            opaque_alpha_mode,
491            max_texture_size,
492            last_error,
493            failed_frame_count: 0,
494            device_lost: context.device_lost_flag(),
495            surface_configured: true,
496            needs_redraw: false,
497        })
498    }
499
500    /// 创建绑定组布局
501    fn create_bind_group_layouts(device: &wgpu::Device) -> WgpuBindGroupLayouts {
502        let globals =
503            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
504                label: Some("globals_layout"),
505                entries: &[
506                    wgpu::BindGroupLayoutEntry {
507                        binding: 0,
508                        visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
509                        ty: wgpu::BindingType::Buffer {
510                            ty: wgpu::BufferBindingType::Uniform,
511                            has_dynamic_offset: false,
512                            min_binding_size: NonZeroU64::new(
513                                std::mem::size_of::<GlobalParams>() as u64
514                            ),
515                        },
516                        count: None,
517                    },
518                    wgpu::BindGroupLayoutEntry {
519                        binding: 1,
520                        visibility: wgpu::ShaderStages::FRAGMENT,
521                        ty: wgpu::BindingType::Buffer {
522                            ty: wgpu::BufferBindingType::Uniform,
523                            has_dynamic_offset: false,
524                            min_binding_size: NonZeroU64::new(
525                                std::mem::size_of::<GammaParams>() as u64
526                            ),
527                        },
528                        count: None,
529                    },
530                ],
531            });
532
533        let storage_buffer_entry = |binding: u32| wgpu::BindGroupLayoutEntry {
534            binding,
535            visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
536            ty: wgpu::BindingType::Buffer {
537                ty: wgpu::BufferBindingType::Storage { read_only: true },
538                has_dynamic_offset: false,
539                min_binding_size: None,
540            },
541            count: None,
542        };
543
544        let instances = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
545            label: Some("instances_layout"),
546            entries: &[storage_buffer_entry(0)],
547        });
548
549        let instances_with_texture =
550            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
551                label: Some("instances_with_texture_layout"),
552                entries: &[
553                    storage_buffer_entry(0),
554                    wgpu::BindGroupLayoutEntry {
555                        binding: 1,
556                        visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
557                        ty: wgpu::BindingType::Texture {
558                            sample_type: wgpu::TextureSampleType::Float { filterable: true },
559                            view_dimension: wgpu::TextureViewDimension::D2,
560                            multisampled: false,
561                        },
562                        count: None,
563                    },
564                    wgpu::BindGroupLayoutEntry {
565                        binding: 2,
566                        visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
567                        ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
568                        count: None,
569                    },
570                ],
571            });
572
573        let surfaces = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
574            label: Some("surfaces_layout"),
575            entries: &[
576                wgpu::BindGroupLayoutEntry {
577                    binding: 0,
578                    visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
579                    ty: wgpu::BindingType::Buffer {
580                        ty: wgpu::BufferBindingType::Uniform,
581                        has_dynamic_offset: false,
582                        min_binding_size: NonZeroU64::new(
583                            std::mem::size_of::<SurfaceParams>() as u64
584                        ),
585                    },
586                    count: None,
587                },
588                wgpu::BindGroupLayoutEntry {
589                    binding: 1,
590                    visibility: wgpu::ShaderStages::FRAGMENT,
591                    ty: wgpu::BindingType::Texture {
592                        sample_type: wgpu::TextureSampleType::Float { filterable: true },
593                        view_dimension: wgpu::TextureViewDimension::D2,
594                        multisampled: false,
595                    },
596                    count: None,
597                },
598                wgpu::BindGroupLayoutEntry {
599                    binding: 2,
600                    visibility: wgpu::ShaderStages::FRAGMENT,
601                    ty: wgpu::BindingType::Texture {
602                        sample_type: wgpu::TextureSampleType::Float { filterable: true },
603                        view_dimension: wgpu::TextureViewDimension::D2,
604                        multisampled: false,
605                    },
606                    count: None,
607                },
608                wgpu::BindGroupLayoutEntry {
609                    binding: 3,
610                    visibility: wgpu::ShaderStages::FRAGMENT,
611                    ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
612                    count: None,
613                },
614            ],
615        });
616
617        WgpuBindGroupLayouts {
618            globals,
619            instances,
620            instances_with_texture,
621            surfaces,
622        }
623    }
624
625    /// 创建渲染管线
626    fn create_pipelines(
627        device: &wgpu::Device,
628        layouts: &WgpuBindGroupLayouts,
629        surface_format: wgpu::TextureFormat,
630        alpha_mode: wgpu::CompositeAlphaMode,
631        path_sample_count: u32,
632        dual_source_blending: bool,
633    ) -> WgpuPipelines {
634        // 诊断保护:验证设备确实启用了
635        // DUAL_SOURCE_BLENDING。我们有一个崩溃报告 (ZED-5G1) 显示
636        // 特性不匹配导致 wgpu-hal 中止,但我们尚未
637        // 确定产生不匹配的代码路径。此
638        // 保护防止崩溃并记录更多证据。
639        // 在以下情况移除此检查:
640        // a) 我们找到并修复根本原因,或
641        // b) 一段时间内没有此警告出现的报告。
642        let device_has_feature = device
643            .features()
644            .contains(wgpu::Features::DUAL_SOURCE_BLENDING);
645        if dual_source_blending && !device_has_feature {
646            log::error!(
647                "BUG: dual_source_blending flag is true but device does not \
648                 have DUAL_SOURCE_BLENDING enabled (device features: {:?}). \
649                 Falling back to mono text rendering. Please report this at \
650                 https://github.com/zed-industries/zed/issues",
651                device.features(),
652            );
653        }
654        let dual_source_blending = dual_source_blending && device_has_feature;
655
656        let base_shader_source = include_str!("shaders.wgsl");
657        let shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
658            label: Some("gpui_shaders"),
659            source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(base_shader_source)),
660        });
661
662        let subpixel_shader_source = include_str!("shaders_subpixel.wgsl");
663        let subpixel_shader_module = if dual_source_blending {
664            let combined = format!(
665                "enable dual_source_blending;\n{base_shader_source}\n{subpixel_shader_source}"
666            );
667            Some(device.create_shader_module(wgpu::ShaderModuleDescriptor {
668                label: Some("gpui_subpixel_shaders"),
669                source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Owned(combined)),
670            }))
671        } else {
672            None
673        };
674
675        let blend_mode = match alpha_mode {
676            wgpu::CompositeAlphaMode::PreMultiplied => {
677                wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING
678            }
679            _ => wgpu::BlendState::ALPHA_BLENDING,
680        };
681
682        let color_target = wgpu::ColorTargetState {
683            format: surface_format,
684            blend: Some(blend_mode),
685            write_mask: wgpu::ColorWrites::ALL,
686        };
687
688        let create_pipeline = |name: &str,
689                               vs_entry: &str,
690                               fs_entry: &str,
691                               globals_layout: &wgpu::BindGroupLayout,
692                               data_layout: &wgpu::BindGroupLayout,
693                               topology: wgpu::PrimitiveTopology,
694                               color_targets: &[Option<wgpu::ColorTargetState>],
695                               sample_count: u32,
696                               module: &wgpu::ShaderModule| {
697            let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
698                label: Some(&format!("{name}_layout")),
699                bind_group_layouts: &[Some(globals_layout), Some(data_layout)],
700                immediate_size: 0,
701            });
702
703            device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
704                label: Some(name),
705                layout: Some(&pipeline_layout),
706                vertex: wgpu::VertexState {
707                    module,
708                    entry_point: Some(vs_entry),
709                    buffers: &[],
710                    compilation_options: wgpu::PipelineCompilationOptions::default(),
711                },
712                fragment: Some(wgpu::FragmentState {
713                    module,
714                    entry_point: Some(fs_entry),
715                    targets: color_targets,
716                    compilation_options: wgpu::PipelineCompilationOptions::default(),
717                }),
718                primitive: wgpu::PrimitiveState {
719                    topology,
720                    strip_index_format: None,
721                    front_face: wgpu::FrontFace::Ccw,
722                    cull_mode: None,
723                    polygon_mode: wgpu::PolygonMode::Fill,
724                    unclipped_depth: false,
725                    conservative: false,
726                },
727                depth_stencil: None,
728                multisample: wgpu::MultisampleState {
729                    count: sample_count,
730                    mask: !0,
731                    alpha_to_coverage_enabled: false,
732                },
733                multiview_mask: None,
734                cache: None,
735            })
736        };
737
738        let quads = create_pipeline(
739            "quads",
740            "vs_quad",
741            "fs_quad",
742            &layouts.globals,
743            &layouts.instances,
744            wgpu::PrimitiveTopology::TriangleStrip,
745            &[Some(color_target.clone())],
746            1,
747            &shader_module,
748        );
749
750        let shadows = create_pipeline(
751            "shadows",
752            "vs_shadow",
753            "fs_shadow",
754            &layouts.globals,
755            &layouts.instances,
756            wgpu::PrimitiveTopology::TriangleStrip,
757            &[Some(color_target.clone())],
758            1,
759            &shader_module,
760        );
761
762        let path_rasterization = create_pipeline(
763            "path_rasterization",
764            "vs_path_rasterization",
765            "fs_path_rasterization",
766            &layouts.globals,
767            &layouts.instances,
768            wgpu::PrimitiveTopology::TriangleList,
769            &[Some(wgpu::ColorTargetState {
770                format: surface_format,
771                blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING),
772                write_mask: wgpu::ColorWrites::ALL,
773            })],
774            path_sample_count,
775            &shader_module,
776        );
777
778        let paths_blend = wgpu::BlendState {
779            color: wgpu::BlendComponent {
780                src_factor: wgpu::BlendFactor::One,
781                dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
782                operation: wgpu::BlendOperation::Add,
783            },
784            alpha: wgpu::BlendComponent {
785                src_factor: wgpu::BlendFactor::One,
786                dst_factor: wgpu::BlendFactor::One,
787                operation: wgpu::BlendOperation::Add,
788            },
789        };
790
791        let paths = create_pipeline(
792            "paths",
793            "vs_path",
794            "fs_path",
795            &layouts.globals,
796            &layouts.instances_with_texture,
797            wgpu::PrimitiveTopology::TriangleStrip,
798            &[Some(wgpu::ColorTargetState {
799                format: surface_format,
800                blend: Some(paths_blend),
801                write_mask: wgpu::ColorWrites::ALL,
802            })],
803            1,
804            &shader_module,
805        );
806
807        let underlines = create_pipeline(
808            "underlines",
809            "vs_underline",
810            "fs_underline",
811            &layouts.globals,
812            &layouts.instances,
813            wgpu::PrimitiveTopology::TriangleStrip,
814            &[Some(color_target.clone())],
815            1,
816            &shader_module,
817        );
818
819        let mono_sprites = create_pipeline(
820            "mono_sprites",
821            "vs_mono_sprite",
822            "fs_mono_sprite",
823            &layouts.globals,
824            &layouts.instances_with_texture,
825            wgpu::PrimitiveTopology::TriangleStrip,
826            &[Some(color_target.clone())],
827            1,
828            &shader_module,
829        );
830
831        let subpixel_sprites = if let Some(subpixel_module) = &subpixel_shader_module {
832            let subpixel_blend = wgpu::BlendState {
833                color: wgpu::BlendComponent {
834                    src_factor: wgpu::BlendFactor::Src1,
835                    dst_factor: wgpu::BlendFactor::OneMinusSrc1,
836                    operation: wgpu::BlendOperation::Add,
837                },
838                alpha: wgpu::BlendComponent {
839                    src_factor: wgpu::BlendFactor::One,
840                    dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
841                    operation: wgpu::BlendOperation::Add,
842                },
843            };
844
845            Some(create_pipeline(
846                "subpixel_sprites",
847                "vs_subpixel_sprite",
848                "fs_subpixel_sprite",
849                &layouts.globals,
850                &layouts.instances_with_texture,
851                wgpu::PrimitiveTopology::TriangleStrip,
852                &[Some(wgpu::ColorTargetState {
853                    format: surface_format,
854                    blend: Some(subpixel_blend),
855                    write_mask: wgpu::ColorWrites::COLOR,
856                })],
857                1,
858                subpixel_module,
859            ))
860        } else {
861            None
862        };
863
864        let poly_sprites = create_pipeline(
865            "poly_sprites",
866            "vs_poly_sprite",
867            "fs_poly_sprite",
868            &layouts.globals,
869            &layouts.instances_with_texture,
870            wgpu::PrimitiveTopology::TriangleStrip,
871            &[Some(color_target.clone())],
872            1,
873            &shader_module,
874        );
875
876        let surfaces = create_pipeline(
877            "surfaces",
878            "vs_surface",
879            "fs_surface",
880            &layouts.globals,
881            &layouts.surfaces,
882            wgpu::PrimitiveTopology::TriangleStrip,
883            &[Some(color_target)],
884            1,
885            &shader_module,
886        );
887
888        WgpuPipelines {
889            quads,
890            shadows,
891            path_rasterization,
892            paths,
893            underlines,
894            mono_sprites,
895            subpixel_sprites,
896            poly_sprites,
897            surfaces,
898        }
899    }
900
901    /// 创建路径中间纹理
902    fn create_path_intermediate(
903        device: &wgpu::Device,
904        format: wgpu::TextureFormat,
905        width: u32,
906        height: u32,
907    ) -> (wgpu::Texture, wgpu::TextureView) {
908        let texture = device.create_texture(&wgpu::TextureDescriptor {
909            label: Some("path_intermediate"),
910            size: wgpu::Extent3d {
911                width: width.max(1),
912                height: height.max(1),
913                depth_or_array_layers: 1,
914            },
915            mip_level_count: 1,
916            sample_count: 1,
917            dimension: wgpu::TextureDimension::D2,
918            format,
919            usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
920            view_formats: &[],
921        });
922        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
923        (texture, view)
924    }
925
926    /// 根据需要创建 MSAA 纹理
927    fn create_msaa_if_needed(
928        device: &wgpu::Device,
929        format: wgpu::TextureFormat,
930        width: u32,
931        height: u32,
932        sample_count: u32,
933    ) -> Option<(wgpu::Texture, wgpu::TextureView)> {
934        if sample_count <= 1 {
935            return None;
936        }
937        let texture = device.create_texture(&wgpu::TextureDescriptor {
938            label: Some("path_msaa"),
939            size: wgpu::Extent3d {
940                width: width.max(1),
941                height: height.max(1),
942                depth_or_array_layers: 1,
943            },
944            mip_level_count: 1,
945            sample_count,
946            dimension: wgpu::TextureDimension::D2,
947            format,
948            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
949            view_formats: &[],
950        });
951        let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
952        Some((texture, view))
953    }
954
955    pub fn update_drawable_size(&mut self, size: Size<DevicePixels>) {
956        let width = size.width.0 as u32;
957        let height = size.height.0 as u32;
958
959        if width != self.surface_config.width || height != self.surface_config.height {
960            let clamped_width = width.min(self.max_texture_size);
961            let clamped_height = height.min(self.max_texture_size);
962
963            if clamped_width != width || clamped_height != height {
964                warn!(
965                    "Requested surface size ({}, {}) exceeds maximum texture dimension {}. \
966                     Clamping to ({}, {}). Window content may not fill the entire window.",
967                    width, height, self.max_texture_size, clamped_width, clamped_height
968                );
969            }
970
971            self.surface_config.width = clamped_width.max(1);
972            self.surface_config.height = clamped_height.max(1);
973            let surface_config = self.surface_config.clone();
974
975            let resources = self.resources_mut();
976
977            // Wait for any in-flight GPU work to complete before destroying textures
978            if let Err(e) = resources.device.poll(wgpu::PollType::Wait {
979                submission_index: None,
980                timeout: None,
981            }) {
982                warn!("在调整大小时轮询设备失败: {e:?}");
983            }
984
985            // 在分配新纹理之前销毁旧纹理,以避免 GPU 内存峰值
986            if let Some(ref texture) = resources.path_intermediate_texture {
987                texture.destroy();
988            }
989            if let Some(ref texture) = resources.path_msaa_texture {
990                texture.destroy();
991            }
992
993            resources
994                .surface
995                .configure(&resources.device, &surface_config);
996
997            // 使中间纹理失效 - 它们将在 draw() 中惰性重新创建
998            // 在我们确认表面健康之后。这避免了
999            // 在调整大小时设备/表面处于无效状态时的 panic。
1000            resources.invalidate_intermediate_textures();
1001        }
1002    }
1003
1004    fn ensure_intermediate_textures(&mut self) {
1005        if self.resources().path_intermediate_texture.is_some() {
1006            return;
1007        }
1008
1009        let format = self.surface_config.format;
1010        let width = self.surface_config.width;
1011        let height = self.surface_config.height;
1012        let path_sample_count = self.rendering_params.path_sample_count;
1013        let resources = self.resources_mut();
1014
1015        let (t, v) = Self::create_path_intermediate(&resources.device, format, width, height);
1016        resources.path_intermediate_texture = Some(t);
1017        resources.path_intermediate_view = Some(v);
1018
1019        let (path_msaa_texture, path_msaa_view) = Self::create_msaa_if_needed(
1020            &resources.device,
1021            format,
1022            width,
1023            height,
1024            path_sample_count,
1025        )
1026        .map(|(t, v)| (Some(t), Some(v)))
1027        .unwrap_or((None, None));
1028        resources.path_msaa_texture = path_msaa_texture;
1029        resources.path_msaa_view = path_msaa_view;
1030    }
1031
1032    pub fn set_subpixel_layout(&mut self, is_bgr: bool) {
1033        self.is_bgr = is_bgr;
1034    }
1035
1036    pub fn update_transparency(&mut self, transparent: bool) {
1037        let new_alpha_mode = if transparent {
1038            self.transparent_alpha_mode
1039        } else {
1040            self.opaque_alpha_mode
1041        };
1042
1043        if new_alpha_mode != self.surface_config.alpha_mode {
1044            self.surface_config.alpha_mode = new_alpha_mode;
1045            let surface_config = self.surface_config.clone();
1046            let path_sample_count = self.rendering_params.path_sample_count;
1047            let dual_source_blending = self.dual_source_blending;
1048            let resources = self.resources_mut();
1049            resources
1050                .surface
1051                .configure(&resources.device, &surface_config);
1052            resources.pipelines = Self::create_pipelines(
1053                &resources.device,
1054                &resources.bind_group_layouts,
1055                surface_config.format,
1056                surface_config.alpha_mode,
1057                path_sample_count,
1058                dual_source_blending,
1059            );
1060        }
1061    }
1062
1063    #[allow(dead_code)]
1064    pub fn viewport_size(&self) -> Size<DevicePixels> {
1065        Size {
1066            width: DevicePixels(self.surface_config.width as i32),
1067            height: DevicePixels(self.surface_config.height as i32),
1068        }
1069    }
1070
1071    pub fn sprite_atlas(&self) -> &Arc<WgpuAtlas> {
1072        &self.atlas
1073    }
1074
1075    pub fn supports_dual_source_blending(&self) -> bool {
1076        self.dual_source_blending
1077    }
1078
1079    pub fn gpu_specs(&self) -> GpuSpecs {
1080        GpuSpecs {
1081            is_software_emulated: self.adapter_info.device_type == wgpu::DeviceType::Cpu,
1082            device_name: self.adapter_info.name.clone(),
1083            driver_name: self.adapter_info.driver.clone(),
1084            driver_info: self.adapter_info.driver_info.clone(),
1085        }
1086    }
1087
1088    pub fn max_texture_size(&self) -> u32 {
1089        self.max_texture_size
1090    }
1091
1092    pub fn draw(&mut self, scene: &Scene) -> bool {
1093        // 如果表面已被取消配置(例如在
1094        // Android 后台/旋转转换期间),则提前退出。
1095        // 尝试从未配置的表面获取纹理可能会
1096        // 在某些驱动(Adreno)上无限期阻塞。
1097        if !self.surface_configured {
1098            return false;
1099        }
1100
1101        let last_error = self.last_error.lock().unwrap().take();
1102        if let Some(error) = last_error {
1103            self.failed_frame_count += 1;
1104            log::error!(
1105                "GPU 错误在帧期间(失败 {} / 10): {error}",
1106                self.failed_frame_count
1107            );
1108
1109            // TBD. 重试更多次真的有帮助吗?
1110            if self.failed_frame_count > 10 {
1111                panic!("连续 GPU 错误过多。最后错误: {error}");
1112            } else if self.failed_frame_count > 5 {
1113                if let Some(res) = self.resources.as_mut() {
1114                    res.invalidate_intermediate_textures();
1115                }
1116                self.atlas.clear();
1117                self.needs_redraw = true;
1118                self.failed_frame_count = 0;
1119                return false;
1120            }
1121        } else {
1122            self.failed_frame_count = 0;
1123        }
1124
1125        self.atlas.before_frame();
1126
1127        let frame = match self.resources().surface.get_current_texture() {
1128            wgpu::CurrentSurfaceTexture::Success(frame) => frame,
1129            wgpu::CurrentSurfaceTexture::Suboptimal(frame) => {
1130                // 在表面可以重新配置之前必须销毁纹理。
1131                drop(frame);
1132                let surface_config = self.surface_config.clone();
1133                let resources = self.resources_mut();
1134                resources
1135                    .surface
1136                    .configure(&resources.device, &surface_config);
1137                return false;
1138            }
1139            wgpu::CurrentSurfaceTexture::Lost | wgpu::CurrentSurfaceTexture::Outdated => {
1140                let surface_config = self.surface_config.clone();
1141                let resources = self.resources_mut();
1142                resources
1143                    .surface
1144                    .configure(&resources.device, &surface_config);
1145                return false;
1146            }
1147            wgpu::CurrentSurfaceTexture::Timeout | wgpu::CurrentSurfaceTexture::Occluded => {
1148                return false;
1149            }
1150            wgpu::CurrentSurfaceTexture::Validation => {
1151                *self.last_error.lock().unwrap() =
1152                    Some("Surface texture validation error".to_string());
1153                return false;
1154            }
1155        };
1156
1157        // 现在我们知道表面是健康的,确保中间纹理存在
1158        self.ensure_intermediate_textures();
1159
1160        let frame_view = frame
1161            .texture
1162            .create_view(&wgpu::TextureViewDescriptor::default());
1163
1164        let gamma_params = GammaParams {
1165            gamma_ratios: self.rendering_params.gamma_ratios,
1166            grayscale_enhanced_contrast: self.rendering_params.grayscale_enhanced_contrast,
1167            subpixel_enhanced_contrast: self.rendering_params.subpixel_enhanced_contrast,
1168            is_bgr: self.is_bgr as u32,
1169            _pad: 0,
1170        };
1171
1172        let globals = GlobalParams {
1173            viewport_size: [
1174                self.surface_config.width as f32,
1175                self.surface_config.height as f32,
1176            ],
1177            premultiplied_alpha: if self.surface_config.alpha_mode
1178                == wgpu::CompositeAlphaMode::PreMultiplied
1179            {
1180                1
1181            } else {
1182                0
1183            },
1184            pad: 0,
1185        };
1186
1187        let path_globals = GlobalParams {
1188            premultiplied_alpha: 0,
1189            ..globals
1190        };
1191
1192        {
1193            let resources = self.resources();
1194            resources.queue.write_buffer(
1195                &resources.globals_buffer,
1196                0,
1197                bytemuck::bytes_of(&globals),
1198            );
1199            resources.queue.write_buffer(
1200                &resources.globals_buffer,
1201                self.path_globals_offset,
1202                bytemuck::bytes_of(&path_globals),
1203            );
1204            resources.queue.write_buffer(
1205                &resources.globals_buffer,
1206                self.gamma_offset,
1207                bytemuck::bytes_of(&gamma_params),
1208            );
1209        }
1210
1211        loop {
1212            let mut instance_offset: u64 = 0;
1213            let mut overflow = false;
1214
1215            let mut encoder =
1216                self.resources()
1217                    .device
1218                    .create_command_encoder(&wgpu::CommandEncoderDescriptor {
1219                        label: Some("main_encoder"),
1220                    });
1221
1222            {
1223                let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1224                    label: Some("main_pass"),
1225                    color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1226                        view: &frame_view,
1227                        resolve_target: None,
1228                        ops: wgpu::Operations {
1229                            load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
1230                            store: wgpu::StoreOp::Store,
1231                        },
1232                        depth_slice: None,
1233                    })],
1234                    depth_stencil_attachment: None,
1235                    ..Default::default()
1236                });
1237
1238                for batch in scene.batches() {
1239                    let ok = match batch {
1240                        PrimitiveBatch::Quads(range) => {
1241                            self.draw_quads(&scene.quads[range], &mut instance_offset, &mut pass)
1242                        }
1243                        PrimitiveBatch::Shadows(range) => self.draw_shadows(
1244                            &scene.shadows[range],
1245                            &mut instance_offset,
1246                            &mut pass,
1247                        ),
1248                        PrimitiveBatch::Paths(range) => {
1249                            let paths = &scene.paths[range];
1250                            if paths.is_empty() {
1251                                continue;
1252                            }
1253
1254                            drop(pass);
1255
1256                            let did_draw = self.draw_paths_to_intermediate(
1257                                &mut encoder,
1258                                paths,
1259                                &mut instance_offset,
1260                            );
1261
1262                            pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1263                                label: Some("main_pass_continued"),
1264                                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1265                                    view: &frame_view,
1266                                    resolve_target: None,
1267                                    ops: wgpu::Operations {
1268                                        load: wgpu::LoadOp::Load,
1269                                        store: wgpu::StoreOp::Store,
1270                                    },
1271                                    depth_slice: None,
1272                                })],
1273                                depth_stencil_attachment: None,
1274                                ..Default::default()
1275                            });
1276
1277                            if did_draw {
1278                                self.draw_paths_from_intermediate(
1279                                    paths,
1280                                    &mut instance_offset,
1281                                    &mut pass,
1282                                )
1283                            } else {
1284                                false
1285                            }
1286                        }
1287                        PrimitiveBatch::Underlines(range) => self.draw_underlines(
1288                            &scene.underlines[range],
1289                            &mut instance_offset,
1290                            &mut pass,
1291                        ),
1292                        PrimitiveBatch::MonochromeSprites { texture_id, range } => self
1293                            .draw_monochrome_sprites(
1294                                &scene.monochrome_sprites[range],
1295                                texture_id,
1296                                &mut instance_offset,
1297                                &mut pass,
1298                            ),
1299                        PrimitiveBatch::SubpixelSprites { texture_id, range } => self
1300                            .draw_subpixel_sprites(
1301                                &scene.subpixel_sprites[range],
1302                                texture_id,
1303                                &mut instance_offset,
1304                                &mut pass,
1305                            ),
1306                        PrimitiveBatch::PolychromeSprites { texture_id, range } => self
1307                            .draw_polychrome_sprites(
1308                                &scene.polychrome_sprites[range],
1309                                texture_id,
1310                                &mut instance_offset,
1311                                &mut pass,
1312                            ),
1313                        PrimitiveBatch::Surfaces(_surfaces) => {
1314                            // 表面仅限 macOS 用于视频播放
1315                            // Linux/wgpu 未实现
1316                            true
1317                        }
1318                    };
1319                    if !ok {
1320                        overflow = true;
1321                        break;
1322                    }
1323                }
1324            }
1325
1326            if overflow {
1327                drop(encoder);
1328                if self.instance_buffer_capacity >= self.max_buffer_size {
1329                    log::error!(
1330                        "instance buffer size grew too large: {}",
1331                        self.instance_buffer_capacity
1332                    );
1333                    frame.present();
1334                    return true;
1335                }
1336                self.grow_instance_buffer();
1337                continue;
1338            }
1339
1340            self.resources()
1341                .queue
1342                .submit(std::iter::once(encoder.finish()));
1343            frame.present();
1344            return true;
1345        }
1346    }
1347
1348    fn draw_quads(
1349        &self,
1350        quads: &[Quad],
1351        instance_offset: &mut u64,
1352        pass: &mut wgpu::RenderPass<'_>,
1353    ) -> bool {
1354        let data = unsafe { Self::instance_bytes(quads) };
1355        self.draw_instances(
1356            data,
1357            quads.len() as u32,
1358            &self.resources().pipelines.quads,
1359            instance_offset,
1360            pass,
1361        )
1362    }
1363
1364    fn draw_shadows(
1365        &self,
1366        shadows: &[Shadow],
1367        instance_offset: &mut u64,
1368        pass: &mut wgpu::RenderPass<'_>,
1369    ) -> bool {
1370        let data = unsafe { Self::instance_bytes(shadows) };
1371        self.draw_instances(
1372            data,
1373            shadows.len() as u32,
1374            &self.resources().pipelines.shadows,
1375            instance_offset,
1376            pass,
1377        )
1378    }
1379
1380    fn draw_underlines(
1381        &self,
1382        underlines: &[Underline],
1383        instance_offset: &mut u64,
1384        pass: &mut wgpu::RenderPass<'_>,
1385    ) -> bool {
1386        let data = unsafe { Self::instance_bytes(underlines) };
1387        self.draw_instances(
1388            data,
1389            underlines.len() as u32,
1390            &self.resources().pipelines.underlines,
1391            instance_offset,
1392            pass,
1393        )
1394    }
1395
1396    fn draw_monochrome_sprites(
1397        &self,
1398        sprites: &[MonochromeSprite],
1399        texture_id: AtlasTextureId,
1400        instance_offset: &mut u64,
1401        pass: &mut wgpu::RenderPass<'_>,
1402    ) -> bool {
1403        let tex_info = self.atlas.get_texture_info(texture_id);
1404        let data = unsafe { Self::instance_bytes(sprites) };
1405        self.draw_instances_with_texture(
1406            data,
1407            sprites.len() as u32,
1408            &tex_info.view,
1409            &self.resources().pipelines.mono_sprites,
1410            instance_offset,
1411            pass,
1412        )
1413    }
1414
1415    fn draw_subpixel_sprites(
1416        &self,
1417        sprites: &[SubpixelSprite],
1418        texture_id: AtlasTextureId,
1419        instance_offset: &mut u64,
1420        pass: &mut wgpu::RenderPass<'_>,
1421    ) -> bool {
1422        let tex_info = self.atlas.get_texture_info(texture_id);
1423        let data = unsafe { Self::instance_bytes(sprites) };
1424        let resources = self.resources();
1425        let pipeline = resources
1426            .pipelines
1427            .subpixel_sprites
1428            .as_ref()
1429            .unwrap_or(&resources.pipelines.mono_sprites);
1430        self.draw_instances_with_texture(
1431            data,
1432            sprites.len() as u32,
1433            &tex_info.view,
1434            pipeline,
1435            instance_offset,
1436            pass,
1437        )
1438    }
1439
1440    fn draw_polychrome_sprites(
1441        &self,
1442        sprites: &[PolychromeSprite],
1443        texture_id: AtlasTextureId,
1444        instance_offset: &mut u64,
1445        pass: &mut wgpu::RenderPass<'_>,
1446    ) -> bool {
1447        let tex_info = self.atlas.get_texture_info(texture_id);
1448        let data = unsafe { Self::instance_bytes(sprites) };
1449        self.draw_instances_with_texture(
1450            data,
1451            sprites.len() as u32,
1452            &tex_info.view,
1453            &self.resources().pipelines.poly_sprites,
1454            instance_offset,
1455            pass,
1456        )
1457    }
1458
1459    fn draw_instances(
1460        &self,
1461        data: &[u8],
1462        instance_count: u32,
1463        pipeline: &wgpu::RenderPipeline,
1464        instance_offset: &mut u64,
1465        pass: &mut wgpu::RenderPass<'_>,
1466    ) -> bool {
1467        if instance_count == 0 {
1468            return true;
1469        }
1470        let Some((offset, size)) = self.write_to_instance_buffer(instance_offset, data) else {
1471            return false;
1472        };
1473        let resources = self.resources();
1474        let bind_group = resources
1475            .device
1476            .create_bind_group(&wgpu::BindGroupDescriptor {
1477                label: None,
1478                layout: &resources.bind_group_layouts.instances,
1479                entries: &[wgpu::BindGroupEntry {
1480                    binding: 0,
1481                    resource: self.instance_binding(offset, size),
1482                }],
1483            });
1484        pass.set_pipeline(pipeline);
1485        pass.set_bind_group(0, &resources.globals_bind_group, &[]);
1486        pass.set_bind_group(1, &bind_group, &[]);
1487        pass.draw(0..4, 0..instance_count);
1488        true
1489    }
1490
1491    fn draw_instances_with_texture(
1492        &self,
1493        data: &[u8],
1494        instance_count: u32,
1495        texture_view: &wgpu::TextureView,
1496        pipeline: &wgpu::RenderPipeline,
1497        instance_offset: &mut u64,
1498        pass: &mut wgpu::RenderPass<'_>,
1499    ) -> bool {
1500        if instance_count == 0 {
1501            return true;
1502        }
1503        let Some((offset, size)) = self.write_to_instance_buffer(instance_offset, data) else {
1504            return false;
1505        };
1506        let resources = self.resources();
1507        let bind_group = resources
1508            .device
1509            .create_bind_group(&wgpu::BindGroupDescriptor {
1510                label: None,
1511                layout: &resources.bind_group_layouts.instances_with_texture,
1512                entries: &[
1513                    wgpu::BindGroupEntry {
1514                        binding: 0,
1515                        resource: self.instance_binding(offset, size),
1516                    },
1517                    wgpu::BindGroupEntry {
1518                        binding: 1,
1519                        resource: wgpu::BindingResource::TextureView(texture_view),
1520                    },
1521                    wgpu::BindGroupEntry {
1522                        binding: 2,
1523                        resource: wgpu::BindingResource::Sampler(&resources.atlas_sampler),
1524                    },
1525                ],
1526            });
1527        pass.set_pipeline(pipeline);
1528        pass.set_bind_group(0, &resources.globals_bind_group, &[]);
1529        pass.set_bind_group(1, &bind_group, &[]);
1530        pass.draw(0..4, 0..instance_count);
1531        true
1532    }
1533
1534    unsafe fn instance_bytes<T>(instances: &[T]) -> &[u8] {
1535        unsafe {
1536            std::slice::from_raw_parts(
1537                instances.as_ptr() as *const u8,
1538                std::mem::size_of_val(instances),
1539            )
1540        }
1541    }
1542
1543    fn draw_paths_from_intermediate(
1544        &self,
1545        paths: &[Path<ScaledPixels>],
1546        instance_offset: &mut u64,
1547        pass: &mut wgpu::RenderPass<'_>,
1548    ) -> bool {
1549        let first_path = &paths[0];
1550        let sprites: Vec<PathSprite> = if paths.last().map(|p| &p.order) == Some(&first_path.order)
1551        {
1552            paths
1553                .iter()
1554                .map(|p| PathSprite {
1555                    bounds: p.clipped_bounds(),
1556                })
1557                .collect()
1558        } else {
1559            let mut bounds = first_path.clipped_bounds();
1560            for path in paths.iter().skip(1) {
1561                bounds = bounds.union(&path.clipped_bounds());
1562            }
1563            vec![PathSprite { bounds }]
1564        };
1565
1566        let resources = self.resources();
1567        let Some(path_intermediate_view) = resources.path_intermediate_view.as_ref() else {
1568            return true;
1569        };
1570
1571        let sprite_data = unsafe { Self::instance_bytes(&sprites) };
1572        self.draw_instances_with_texture(
1573            sprite_data,
1574            sprites.len() as u32,
1575            path_intermediate_view,
1576            &resources.pipelines.paths,
1577            instance_offset,
1578            pass,
1579        )
1580    }
1581
1582    fn draw_paths_to_intermediate(
1583        &self,
1584        encoder: &mut wgpu::CommandEncoder,
1585        paths: &[Path<ScaledPixels>],
1586        instance_offset: &mut u64,
1587    ) -> bool {
1588        let mut vertices = Vec::new();
1589        for path in paths {
1590            let bounds = path.clipped_bounds();
1591            vertices.extend(path.vertices.iter().map(|v| PathRasterizationVertex {
1592                xy_position: v.xy_position,
1593                st_position: v.st_position,
1594                color: path.color,
1595                bounds,
1596            }));
1597        }
1598
1599        if vertices.is_empty() {
1600            return true;
1601        }
1602
1603        let vertex_data = unsafe { Self::instance_bytes(&vertices) };
1604        let Some((vertex_offset, vertex_size)) =
1605            self.write_to_instance_buffer(instance_offset, vertex_data)
1606        else {
1607            return false;
1608        };
1609
1610        let resources = self.resources();
1611        let data_bind_group = resources
1612            .device
1613            .create_bind_group(&wgpu::BindGroupDescriptor {
1614                label: Some("path_rasterization_bind_group"),
1615                layout: &resources.bind_group_layouts.instances,
1616                entries: &[wgpu::BindGroupEntry {
1617                    binding: 0,
1618                    resource: self.instance_binding(vertex_offset, vertex_size),
1619                }],
1620            });
1621
1622        let Some(path_intermediate_view) = resources.path_intermediate_view.as_ref() else {
1623            return true;
1624        };
1625
1626        let (target_view, resolve_target) = if let Some(ref msaa_view) = resources.path_msaa_view {
1627            (msaa_view, Some(path_intermediate_view))
1628        } else {
1629            (path_intermediate_view, None)
1630        };
1631
1632        {
1633            let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
1634                label: Some("path_rasterization_pass"),
1635                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
1636                    view: target_view,
1637                    resolve_target,
1638                    ops: wgpu::Operations {
1639                        load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
1640                        store: wgpu::StoreOp::Store,
1641                    },
1642                    depth_slice: None,
1643                })],
1644                depth_stencil_attachment: None,
1645                ..Default::default()
1646            });
1647
1648            pass.set_pipeline(&resources.pipelines.path_rasterization);
1649            pass.set_bind_group(0, &resources.path_globals_bind_group, &[]);
1650            pass.set_bind_group(1, &data_bind_group, &[]);
1651            pass.draw(0..vertices.len() as u32, 0..1);
1652        }
1653
1654        true
1655    }
1656
1657    fn grow_instance_buffer(&mut self) {
1658        let new_capacity = (self.instance_buffer_capacity * 2).min(self.max_buffer_size);
1659        log::info!("increased instance buffer size to {}", new_capacity);
1660        let resources = self.resources_mut();
1661        resources.instance_buffer = resources.device.create_buffer(&wgpu::BufferDescriptor {
1662            label: Some("instance_buffer"),
1663            size: new_capacity,
1664            usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
1665            mapped_at_creation: false,
1666        });
1667        self.instance_buffer_capacity = new_capacity;
1668    }
1669
1670    fn write_to_instance_buffer(
1671        &self,
1672        instance_offset: &mut u64,
1673        data: &[u8],
1674    ) -> Option<(u64, NonZeroU64)> {
1675        let offset = (*instance_offset).next_multiple_of(self.storage_buffer_alignment);
1676        let size = (data.len() as u64).max(16);
1677        if offset + size > self.instance_buffer_capacity {
1678            return None;
1679        }
1680        let resources = self.resources();
1681        resources
1682            .queue
1683            .write_buffer(&resources.instance_buffer, offset, data);
1684        *instance_offset = offset + size;
1685        Some((offset, NonZeroU64::new(size).expect("size is at least 16")))
1686    }
1687
1688    fn instance_binding(&self, offset: u64, size: NonZeroU64) -> wgpu::BindingResource<'_> {
1689        wgpu::BindingResource::Buffer(wgpu::BufferBinding {
1690            buffer: &self.resources().instance_buffer,
1691            offset,
1692            size: Some(size),
1693        })
1694    }
1695
1696    /// 将表面标记为未配置,以便在通过 [`replace_surface`](Self::replace_surface)
1697    /// 提供新表面之前跳过渲染。
1698    ///
1699    /// 这**不会**丢弃渲染器 —— 设备、队列、图集和
1700    /// 管线保持活动状态。当原生窗口被销毁时使用此方法
1701    /// (例如 Android `TerminateWindow`),但你打算稍后重新创建
1702    /// 表面而不丢失缓存的图集纹理。
1703    pub fn unconfigure_surface(&mut self) {
1704        self.surface_configured = false;
1705        // 丢弃中间纹理,因为它们引用旧表面尺寸。
1706        if let Some(res) = self.resources.as_mut() {
1707            res.invalidate_intermediate_textures();
1708        }
1709    }
1710
1711    /// 用新表面替换 wgpu 表面(例如在 Android 销毁并
1712    /// 重新创建原生窗口之后)。保持设备、队列、图集和
1713    /// 所有管线完好无损,以便缓存的 `AtlasTextureId` 保持有效。
1714    ///
1715    /// `instance` **必须** 是用于创建适配器和设备的
1716    /// 同一个 [`wgpu::Instance`](即来自 [`WgpuContext`])。使用
1717    /// 不同的实例将导致 "Device does not exist" panic,因为
1718    /// wgpu 设备绑定到其原始实例。
1719    #[cfg(not(target_family = "wasm"))]
1720    pub fn replace_surface<W: HasWindowHandle>(
1721        &mut self,
1722        window: &W,
1723        config: WgpuSurfaceConfig,
1724        instance: &wgpu::Instance,
1725    ) -> anyhow::Result<()> {
1726        let window_handle = window
1727            .window_handle()
1728            .map_err(|e| anyhow::anyhow!("Failed to get window handle: {e}"))?;
1729
1730        let surface = create_surface(instance, window_handle.as_raw())?;
1731
1732        let width = (config.size.width.0 as u32).max(1);
1733        let height = (config.size.height.0 as u32).max(1);
1734
1735        let alpha_mode = if config.transparent {
1736            self.transparent_alpha_mode
1737        } else {
1738            self.opaque_alpha_mode
1739        };
1740
1741        self.surface_config.width = width;
1742        self.surface_config.height = height;
1743        self.surface_config.alpha_mode = alpha_mode;
1744        if let Some(mode) = config.preferred_present_mode {
1745            self.surface_config.present_mode = mode;
1746        }
1747
1748        {
1749            let res = self
1750                .resources
1751                .as_mut()
1752                .expect("GPU resources not available");
1753            surface.configure(&res.device, &self.surface_config);
1754            res.surface = surface;
1755
1756            // 使中间纹理失效 —— 它们将惰性重新创建。
1757            res.invalidate_intermediate_textures();
1758        }
1759
1760        self.surface_configured = true;
1761
1762        Ok(())
1763    }
1764
1765    pub fn destroy(&mut self) {
1766        // 主动释放绑定到表面的 GPU 资源,以便底层原生
1767        // 窗口可以在渲染器本身被丢弃之前被销毁。
1768        self.resources.take();
1769    }
1770
1771    /// 返回 GPU 设备是否丢失以及是否需要恢复。
1772    pub fn device_lost(&self) -> bool {
1773        self.device_lost.load(std::sync::atomic::Ordering::SeqCst)
1774    }
1775
1776    /// 返回是否需要重绘,因为 GPU 状态已被清除。
1777    /// 调用此方法将清除标志。
1778    pub fn needs_redraw(&mut self) -> bool {
1779        std::mem::take(&mut self.needs_redraw)
1780    }
1781
1782    /// 从丢失的 GPU 设备恢复,通过使用新上下文重新创建渲染器。
1783    ///
1784    /// 在检测到 `device_lost()` 返回 true 后调用此方法。
1785    ///
1786    /// 此方法协调多个窗口之间的恢复:
1787    /// - 第一个调用此方法的窗口将重新创建共享上下文
1788    /// - 后续窗口将采用已恢复的上下文
1789    #[cfg(not(target_family = "wasm"))]
1790    pub fn recover<W>(&mut self, window: &W) -> anyhow::Result<()>
1791    where
1792        W: HasWindowHandle + HasDisplayHandle + std::fmt::Debug + Send + Sync + Clone + 'static,
1793    {
1794        let gpu_context = self.context.as_ref().expect("recover 需要 gpu_context");
1795
1796        // 检查是否有其他窗口已经恢复了上下文
1797        let needs_new_context = gpu_context
1798            .borrow()
1799            .as_ref()
1800            .is_none_or(|ctx| ctx.device_lost());
1801
1802        let window_handle = window
1803            .window_handle()
1804            .map_err(|e| anyhow::anyhow!("Failed to get window handle: {e}"))?;
1805
1806        let surface = if needs_new_context {
1807            log::warn!("GPU 设备丢失,正在重新创建上下文...");
1808
1809            // 丢弃旧资源以释放 Arc<Device>/Arc<Queue> 和 GPU 资源
1810            self.resources = None;
1811            *gpu_context.borrow_mut() = None;
1812
1813            // 等待片刻让 GPU 驱动稳定,然后尝试
1814            // 不使用软件渲染器重新创建上下文。如果失败
1815            // 调用者应该请求另一帧并重试 —— 真正的 GPU
1816            // 可能需要更多时间才能恢复(例如挂起/恢复后)。
1817            std::thread::sleep(std::time::Duration::from_millis(350));
1818
1819            let instance = WgpuContext::instance(Box::new(window.clone()));
1820            let surface = create_surface(&instance, window_handle.as_raw())?;
1821            let new_context =
1822                WgpuContext::new_rejecting_software(instance, &surface, self.compositor_gpu)?;
1823            *gpu_context.borrow_mut() = Some(new_context);
1824            surface
1825        } else {
1826            let ctx_ref = gpu_context.borrow();
1827            let instance = &ctx_ref.as_ref().unwrap().instance;
1828            create_surface(instance, window_handle.as_raw())?
1829        };
1830
1831        let config = WgpuSurfaceConfig {
1832            size: rgpui::Size {
1833                width: rgpui::DevicePixels(self.surface_config.width as i32),
1834                height: rgpui::DevicePixels(self.surface_config.height as i32),
1835            },
1836            transparent: self.surface_config.alpha_mode != wgpu::CompositeAlphaMode::Opaque,
1837            preferred_present_mode: Some(self.surface_config.present_mode),
1838        };
1839        let gpu_context = Rc::clone(gpu_context);
1840        let ctx_ref = gpu_context.borrow();
1841        let context = ctx_ref.as_ref().expect("context should exist");
1842
1843        self.resources = None;
1844        self.atlas.handle_device_lost(context);
1845
1846        *self = Self::new_internal(
1847            Some(gpu_context.clone()),
1848            context,
1849            surface,
1850            config,
1851            self.compositor_gpu,
1852            self.atlas.clone(),
1853        )?;
1854
1855        log::info!("GPU recovery complete");
1856        Ok(())
1857    }
1858}
1859
1860#[cfg(not(target_family = "wasm"))]
1861fn create_surface(
1862    instance: &wgpu::Instance,
1863    raw_window_handle: raw_window_handle::RawWindowHandle,
1864) -> anyhow::Result<wgpu::Surface<'static>> {
1865    unsafe {
1866        instance
1867            .create_surface_unsafe(wgpu::SurfaceTargetUnsafe::RawHandle {
1868                // 回退到通过 InstanceDescriptor::display 已提供的显示句柄。
1869                raw_display_handle: None,
1870                raw_window_handle,
1871            })
1872            .map_err(|e| anyhow::anyhow!("{e}"))
1873    }
1874}
1875
1876struct RenderingParameters {
1877    path_sample_count: u32,
1878    gamma_ratios: [f32; 4],
1879    grayscale_enhanced_contrast: f32,
1880    subpixel_enhanced_contrast: f32,
1881}
1882
1883impl RenderingParameters {
1884    fn new(adapter: &wgpu::Adapter, surface_format: wgpu::TextureFormat) -> Self {
1885        use std::env;
1886
1887        let format_features = adapter.get_texture_format_features(surface_format);
1888        let path_sample_count = [4, 2, 1]
1889            .into_iter()
1890            .find(|&n| format_features.flags.sample_count_supported(n))
1891            .unwrap_or(1);
1892
1893        let gamma = env::var("ZED_FONTS_GAMMA")
1894            .ok()
1895            .and_then(|v| v.parse().ok())
1896            .unwrap_or(1.8_f32)
1897            .clamp(1.0, 2.2);
1898        let gamma_ratios = get_gamma_correction_ratios(gamma);
1899
1900        let grayscale_enhanced_contrast = env::var("ZED_FONTS_GRAYSCALE_ENHANCED_CONTRAST")
1901            .ok()
1902            .and_then(|v| v.parse().ok())
1903            .unwrap_or(1.0_f32)
1904            .max(0.0);
1905
1906        let subpixel_enhanced_contrast = env::var("ZED_FONTS_SUBPIXEL_ENHANCED_CONTRAST")
1907            .ok()
1908            .and_then(|v| v.parse().ok())
1909            .unwrap_or(0.5_f32)
1910            .max(0.0);
1911
1912        Self {
1913            path_sample_count,
1914            gamma_ratios,
1915            grayscale_enhanced_contrast,
1916            subpixel_enhanced_contrast,
1917        }
1918    }
1919}