1use crate::*;
2
3pub async fn create_graphics_context(
4 window: &'static Window,
5) -> GraphicsContext {
6 let size = window.inner_size();
7
8 let backends =
9 wgpu::util::backend_bits_from_env().unwrap_or(wgpu::Backends::all());
10
11 let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
12 backends,
14 dx12_shader_compiler: Default::default(),
15 flags: if cfg!(debug_assertions) {
17 wgpu::InstanceFlags::debugging()
18 } else {
19 wgpu::InstanceFlags::VALIDATION
20 },
21 gles_minor_version: wgpu::Gles3MinorVersion::Automatic,
22 });
23
24 let surface =
25 instance.create_surface(window).expect("surface config must be valid");
26
27 trace!("Requesting adapter");
28
29 let adapter = instance
30 .request_adapter(&wgpu::RequestAdapterOptions {
31 power_preference: power_preference_to_wgpu(
32 game_config().power_preference,
33 ),
34 compatible_surface: Some(&surface),
35 force_fallback_adapter: false,
36 })
37 .await
38 .expect("adapter config must be valid");
39
40 info!("Using adapter: {:?}", adapter.get_info().name);
41
42 trace!("Requesting device");
43
44 let max_texture_dim_2d =
45 game_config().max_texture_dimension_2d_override.unwrap_or(4096);
46
47 #[cfg(not(target_arch = "wasm32"))]
48 let limits = wgpu::Limits {
49 max_texture_dimension_2d: max_texture_dim_2d,
50 ..wgpu::Limits::downlevel_defaults()
51 };
52
53 #[cfg(target_arch = "wasm32")]
54 let limits = wgpu::Limits {
55 max_texture_dimension_2d: max_texture_dim_2d,
56 ..wgpu::Limits::downlevel_webgl2_defaults()
57 };
58
59 let (device, queue) = adapter
60 .request_device(
61 &wgpu::DeviceDescriptor {
62 required_features: wgpu::Features::empty(),
63 required_limits: limits,
64 label: None,
65 },
66 None,
67 )
68 .await
69 .expect("failed to create wgpu adapter");
70
71 #[cfg(fature = "ci-release")]
72 device.on_uncaptured_error(Box::new(|err| {
73 error!("WGPU ERROR: {:?}", err);
74 panic!("Exiting due to wgpu error: {:?}", err);
75 }));
76
77 let caps = surface.get_capabilities(&adapter);
78 let supported_formats = caps.formats;
79 info!("Supported formats: {:?}", supported_formats);
80
81 #[cfg(not(target_arch = "wasm32"))]
82 let preferred_format = wgpu::TextureFormat::Bgra8UnormSrgb;
83 #[cfg(target_arch = "wasm32")]
84 let preferred_format = wgpu::TextureFormat::Rgba8UnormSrgb;
85
86 let monitor_surface_format =
87 if supported_formats.contains(&preferred_format) {
88 preferred_format
89 } else {
90 let fallback = supported_formats[0];
91
92 error!(
93 "Unsupported preferred surface format: {:?}. Using first \
94 supported format: {:?}",
95 preferred_format, fallback
96 );
97
98 fallback
99 };
100
101 #[cfg(not(target_arch = "wasm32"))]
102 let surface_usage =
103 wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC;
104 #[cfg(target_arch = "wasm32")]
105 let surface_usage = wgpu::TextureUsages::RENDER_ATTACHMENT;
106
107 let desired_present_mode =
108 match std::env::var("COMFY_VSYNC_OVERRIDE").as_deref() {
109 Ok("0") | Ok("f") | Ok("false") => {
110 info!("VSYNC OVERRIDE via env var, set to VSYNC=off");
111 wgpu::PresentMode::Immediate
112 }
113 Ok("1") | Ok("t") | Ok("true") => {
114 info!("VSYNC OVERRIDE via env var, set to VSYNC=on");
115 wgpu::PresentMode::AutoVsync
116 }
117 _ => {
118 if game_config().vsync_enabled {
119 wgpu::PresentMode::AutoVsync
120 } else {
121 wgpu::PresentMode::Immediate
122 }
123 }
124 };
125
126 let present_mode = if caps.present_modes.contains(&desired_present_mode) {
127 desired_present_mode
128 } else {
129 caps.present_modes[0]
130 };
131
132 info!("ACTUAL PRESENT MODE: {:?}", present_mode);
133
134 let config = wgpu::SurfaceConfiguration {
135 usage: surface_usage,
136 format: monitor_surface_format,
137 width: size.width,
138 height: size.height,
139 present_mode,
140 alpha_mode: caps.alpha_modes[0],
141 view_formats: vec![],
142 desired_maximum_frame_latency: game_config()
143 .desired_maximum_frame_latency,
144 };
145
146 trace!("Configuring surface");
147
148 surface.configure(&device, &config);
149
150 let texture_bind_group_layout =
151 device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
152 entries: &[
153 wgpu::BindGroupLayoutEntry {
154 binding: 0,
155 visibility: wgpu::ShaderStages::FRAGMENT,
156 ty: wgpu::BindingType::Texture {
157 multisampled: false,
158 view_dimension: wgpu::TextureViewDimension::D2,
159 sample_type: wgpu::TextureSampleType::Float {
160 filterable: true,
161 },
162 },
163 count: None,
164 },
165 wgpu::BindGroupLayoutEntry {
166 binding: 1,
167 visibility: wgpu::ShaderStages::FRAGMENT,
168 ty: wgpu::BindingType::Sampler(
169 wgpu::SamplerBindingType::Filtering,
170 ),
171 count: None,
172 },
173 ],
174 label: Some("texture_bind_group_layout"),
175 });
176
177 let textures = Arc::new(Mutex::new(HashMap::new()));
178
179 let device = Arc::new(device);
180 let queue = Arc::new(queue);
181 let texture_layout = Arc::new(texture_bind_group_layout);
182
183 let texture_creator = Arc::new(AtomicRefCell::new(WgpuTextureCreator {
184 textures: textures.clone(),
185 layout: texture_layout.clone(),
186 queue: queue.clone(),
187 device: device.clone(),
188 }));
189
190 GraphicsContext {
191 surface: Arc::new(surface),
192 instance: Arc::new(instance),
193 adapter: Arc::new(adapter),
194 device,
195 queue,
196 texture_layout,
197 config: Arc::new(AtomicRefCell::new(config)),
198 texture_creator,
199 textures,
200 }
201}