Skip to main content

rust_animation/
wgpu_context.rs

1// Copyright (c) 2021 Joone Hur <joone@chromium.org> All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use wgpu;
6
7/// Shared wgpu rendering context
8pub struct WgpuContext {
9  pub device: wgpu::Device,
10  pub queue: wgpu::Queue,
11  pub surface: Option<wgpu::Surface<'static>>,
12  pub surface_config: Option<wgpu::SurfaceConfiguration>,
13}
14
15impl WgpuContext {
16  /// Create a new wgpu context without a surface (for library use)
17  pub async fn new_offscreen() -> Self {
18    // Explicitly specify backends for better compatibility across platforms
19    // On macOS, this ensures Metal backend is used
20    // On other platforms, PRIMARY includes Vulkan, DX12, or other native backends
21    let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
22      backends: wgpu::Backends::PRIMARY,
23      ..Default::default()
24    });
25    let adapter = instance
26      .request_adapter(&wgpu::RequestAdapterOptions {
27        power_preference: wgpu::PowerPreference::default(),
28        compatible_surface: None,
29        force_fallback_adapter: false,
30      })
31      .await
32      .expect("Failed to find an appropriate adapter");
33
34    let (device, queue) = adapter
35      .request_device(
36        &wgpu::DeviceDescriptor {
37          label: Some("Device"),
38          required_features: wgpu::Features::empty(),
39          required_limits: wgpu::Limits::default(),
40          memory_hints: wgpu::MemoryHints::default(),
41        },
42        None,
43      )
44      .await
45      .expect("Failed to create device");
46
47    WgpuContext {
48      device,
49      queue,
50      surface: None,
51      surface_config: None,
52    }
53  }
54
55  /// Create a new wgpu context with a surface for rendering to a window
56  pub async fn new_with_surface(
57    window: impl Into<wgpu::SurfaceTarget<'static>>,
58    width: u32,
59    height: u32,
60  ) -> Self {
61    let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
62      backends: wgpu::Backends::PRIMARY,
63      ..Default::default()
64    });
65
66    let surface = instance
67      .create_surface(window)
68      .expect("Failed to create surface");
69
70    let adapter = instance
71      .request_adapter(&wgpu::RequestAdapterOptions {
72        power_preference: wgpu::PowerPreference::default(),
73        compatible_surface: Some(&surface),
74        force_fallback_adapter: false,
75      })
76      .await
77      .expect("Failed to find an appropriate adapter");
78
79    let (device, queue) = adapter
80      .request_device(
81        &wgpu::DeviceDescriptor {
82          label: Some("Device"),
83          required_features: wgpu::Features::empty(),
84          required_limits: wgpu::Limits::default(),
85          memory_hints: wgpu::MemoryHints::default(),
86        },
87        None,
88      )
89      .await
90      .expect("Failed to create device");
91
92    let surface_caps = surface.get_capabilities(&adapter);
93    let surface_format = surface_caps
94      .formats
95      .iter()
96      .find(|f| f.is_srgb())
97      .copied()
98      .unwrap_or(surface_caps.formats[0]);
99
100    let config = wgpu::SurfaceConfiguration {
101      usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
102      format: surface_format,
103      width,
104      height,
105      present_mode: wgpu::PresentMode::Fifo,
106      alpha_mode: surface_caps.alpha_modes[0],
107      view_formats: vec![],
108      desired_maximum_frame_latency: 2,
109    };
110
111    surface.configure(&device, &config);
112
113    WgpuContext {
114      device,
115      queue,
116      surface: Some(surface),
117      surface_config: Some(config),
118    }
119  }
120
121  /// Resize the surface
122  pub fn resize(&mut self, width: u32, height: u32) {
123    if let (Some(surface), Some(config)) = (&self.surface, &mut self.surface_config) {
124      config.width = width;
125      config.height = height;
126      surface.configure(&self.device, config);
127    }
128  }
129}