1mod binding;
2mod compiler;
3pub(super) mod drawer;
4mod locals;
6mod pipeline_creation;
7mod rain_occlusion_map;
8mod screenshot;
9mod shaders;
10mod shadow_map;
11
12use locals::Locals;
13use pipeline_creation::{
14 IngameAndShadowPipelines, InterfacePipelines, PipelineCreation, Pipelines, ShadowPipelines,
15};
16use shaders::Shaders;
17use shadow_map::{ShadowMap, ShadowMapRenderer};
18
19use self::{pipeline_creation::RainOcclusionPipelines, rain_occlusion_map::RainOcclusionMap};
20
21use super::{
22 AddressMode, FilterMode, OtherModes, PipelineModes, PresentMode, RenderError, RenderMode,
23 ShadowMapMode, ShadowMode, Vertex,
24 buffer::Buffer,
25 consts::Consts,
26 instances::Instances,
27 mesh::Mesh,
28 model::{DynamicModel, Model},
29 pipelines::{
30 GlobalsBindGroup, GlobalsLayouts, ShadowTexturesBindGroup, blit, bloom, clouds, debug,
31 figure, postprocess, rain_occlusion, rope, shadow, sprite, terrain, ui,
32 },
33 texture::Texture,
34};
35use common::assets::{self, AssetExt, AssetHandle, ReloadWatcher};
36use common_base::span;
37use core::convert::TryFrom;
38use std::sync::Arc;
39use tracing::{error, info, warn};
40use vek::*;
41
42const QUAD_INDEX_BUFFER_U16_START_VERT_LEN: u16 = 3000;
43const QUAD_INDEX_BUFFER_U32_START_VERT_LEN: u32 = 3000;
44
45struct ImmutableLayouts {
48 global: GlobalsLayouts,
49
50 debug: debug::DebugLayout,
51 figure: figure::FigureLayout,
52 shadow: shadow::ShadowLayout,
53 rain_occlusion: rain_occlusion::RainOcclusionLayout,
54 sprite: sprite::SpriteLayout,
55 terrain: terrain::TerrainLayout,
56 rope: rope::RopeLayout,
57 clouds: clouds::CloudsLayout,
58 bloom: bloom::BloomLayout,
59 ui: ui::UiLayout,
60 premultiply_alpha: ui::PremultiplyAlphaLayout,
61 blit: blit::BlitLayout,
62}
63
64struct Layouts {
66 immutable: Arc<ImmutableLayouts>,
67
68 postprocess: Arc<postprocess::PostProcessLayout>,
69}
70
71impl core::ops::Deref for Layouts {
72 type Target = ImmutableLayouts;
73
74 fn deref(&self) -> &Self::Target { &self.immutable }
75}
76
77struct Views {
79 _win_depth: wgpu::TextureView,
81
82 tgt_color: wgpu::TextureView,
83 tgt_mat: wgpu::TextureView,
84 tgt_depth: wgpu::TextureView,
85
86 bloom_tgts: Option<[wgpu::TextureView; bloom::NUM_SIZES]>,
87 tgt_color_pp: wgpu::TextureView,
89}
90
91struct Shadow {
93 rain_map: RainOcclusionMap,
94 map: ShadowMap,
95 bind: ShadowTexturesBindGroup,
96}
97
98#[expect(clippy::large_enum_variant)]
102enum State {
103 Nothing,
105 Interface {
106 pipelines: InterfacePipelines,
107 shadow_views: Option<(Texture, Texture)>,
108 rain_occlusion_view: Option<Texture>,
109 creating: PipelineCreation<IngameAndShadowPipelines>,
111 },
112 Complete {
113 pipelines: Pipelines,
114 shadow: Shadow,
115 recreating: Option<(
116 PipelineModes,
117 PipelineCreation<
118 Result<
119 (
120 Pipelines,
121 ShadowPipelines,
122 RainOcclusionPipelines,
123 Arc<postprocess::PostProcessLayout>,
124 ),
125 RenderError,
126 >,
127 >,
128 )>,
129 },
130}
131
132pub struct Renderer {
137 device: wgpu::Device,
138 queue: wgpu::Queue,
139 surface: wgpu::Surface<'static>,
140 surface_config: wgpu::SurfaceConfiguration,
141
142 sampler: wgpu::Sampler,
143 depth_sampler: wgpu::Sampler,
144
145 state: State,
146 recreation_pending: Option<PipelineModes>,
149
150 layouts: Layouts,
151 locals: Locals,
154 views: Views,
155 noise_tex: Texture,
156
157 quad_index_buffer_u16: Buffer<u16>,
158 quad_index_buffer_u32: Buffer<u32>,
159
160 shaders: AssetHandle<Shaders>,
161 shaders_watcher: ReloadWatcher,
162
163 pipeline_modes: PipelineModes,
164 other_modes: OtherModes,
165 resolution: Vec2<u32>,
166
167 take_screenshot: Option<screenshot::ScreenshotFn>,
169
170 profiler: wgpu_profiler::GpuProfiler,
171 profile_times: Vec<wgpu_profiler::GpuTimerQueryResult>,
172 profiler_features_enabled: bool,
173
174 ui_premultiply_uploads: ui::BatchedUploads,
175
176 #[cfg(feature = "egui-ui")]
177 egui_renderer: egui_wgpu::Renderer,
178
179 is_minimized: bool,
182
183 graphics_backend: String,
185
186 intermediate_format: wgpu::TextureFormat,
188
189 present_modes: Vec<PresentMode>,
191 max_texture_size: u32,
193}
194
195impl Renderer {
196 pub fn new(
199 window: Arc<winit::window::Window>,
200 mode: RenderMode,
201 runtime: &tokio::runtime::Runtime,
202 ) -> Result<Self, RenderError> {
203 let (pipeline_modes, mut other_modes) = mode.split();
204 let backends = std::env::var("WGPU_BACKEND")
214 .ok()
215 .and_then(|backend| match backend.to_lowercase().as_str() {
216 "vulkan" | "vk" => Some(wgpu::Backends::VULKAN),
217 "metal" => Some(wgpu::Backends::METAL),
218 "dx12" => Some(wgpu::Backends::DX12),
219 "primary" => Some(wgpu::Backends::PRIMARY),
220 "opengl" | "gl" => Some(wgpu::Backends::GL),
221 "secondary" => Some(wgpu::Backends::SECONDARY),
222 "all" => Some(wgpu::Backends::all()),
223 _ => None,
224 })
225 .unwrap_or(wgpu::Backends::PRIMARY | wgpu::Backends::SECONDARY);
226
227 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
228 backends,
229 flags: wgpu::InstanceFlags::from_build_config().with_env(),
231 backend_options: wgpu::BackendOptions::default(),
232 memory_budget_thresholds: wgpu::MemoryBudgetThresholds::default(),
233 });
234
235 let dims = window.inner_size();
236
237 let surface = instance
238 .create_surface(window)
239 .expect("Failed to create a surface");
240
241 let adapters = instance.enumerate_adapters(backends);
242
243 for (i, adapter) in adapters.iter().enumerate() {
244 let info = adapter.get_info();
245 info!(
246 ?info.name,
247 ?info.vendor,
248 ?info.backend,
249 ?info.device,
250 ?info.device_type,
251 "graphics device #{}", i,
252 );
253 }
254
255 let adapter = match std::env::var("WGPU_ADAPTER").ok() {
256 Some(filter) if !filter.is_empty() => adapters
257 .into_iter()
258 .enumerate()
259 .find_map(|(i, adapter)| {
260 let info = adapter.get_info();
261
262 let full_name = format!("#{} {} {:?}", i, info.name, info.device_type,);
263
264 full_name.contains(&filter).then_some(adapter)
265 })
266 .ok_or(RenderError::CouldNotFindAdapter)?,
267 Some(_) | None => {
268 runtime.block_on(instance.request_adapter(&wgpu::RequestAdapterOptionsBase {
269 power_preference: wgpu::PowerPreference::HighPerformance,
270 compatible_surface: Some(&surface),
271 force_fallback_adapter: false,
272 }))?
273 },
274 };
275
276 let info = adapter.get_info();
277 info!(
278 ?info.name,
279 ?info.vendor,
280 ?info.backend,
281 ?info.device,
282 ?info.device_type,
283 "selected graphics device"
284 );
285 let graphics_backend = format!("{:?}", &info.backend);
286
287 let required_limits = wgpu::Limits {
288 max_push_constant_size: 64,
289 ..Default::default()
290 };
291
292 #[cfg(any())] let trace = if let Some(v) = std::env::var_os("WGPU_TRACE_DIR") {
294 let path = std::path::Path::new(&v);
295 assert!(
297 path.exists(),
298 "WGPU_TRACE_DIR is set to the path \"{}\" which doesn't exist",
299 path.display()
300 );
301 assert!(
302 path.is_dir(),
303 "WGPU_TRACE_DIR is set to the path \"{}\" which is not a directory",
304 path.display()
305 );
306 assert!(
307 path.read_dir()
308 .expect("Could not read the directory that is specified by WGPU_TRACE_DIR")
309 .next()
310 .is_none(),
311 "WGPU_TRACE_DIR is set to the path \"{}\" which already contains other files",
312 path.display()
313 );
314
315 wgpu::Trace::Directory(path)
316 } else {
317 wgpu::Trace::Off
318 };
319
320 let (device, queue) =
321 runtime.block_on(adapter.request_device(&wgpu::DeviceDescriptor {
322 label: None,
324 required_features: wgpu::Features::DEPTH_CLIP_CONTROL
325 | wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER
326 | wgpu::Features::PUSH_CONSTANTS
327 | (adapter.features() & wgpu_profiler::GpuProfiler::ALL_WGPU_TIMER_FEATURES),
328 required_limits,
329 experimental_features: wgpu::ExperimentalFeatures::disabled(),
330 memory_hints: wgpu::MemoryHints::Performance,
331 trace: wgpu::Trace::Off,
332 }))?;
333
334 device.on_uncaptured_error(Arc::new(move |error| {
338 error!("{}", &error);
339 panic!(
340 "wgpu error (handling all wgpu errors as fatal):\n{:?}\n{:?}",
341 &error, &info,
342 );
343 }));
344
345 let profiler_features_enabled = device
346 .features()
347 .intersects(wgpu_profiler::GpuProfiler::ALL_WGPU_TIMER_FEATURES);
348 if !profiler_features_enabled {
349 info!(
350 "The features for GPU profiling (timestamp queries) are not available on this \
351 adapter"
352 );
353 }
354
355 let max_texture_size = device.limits().max_texture_dimension_2d;
356
357 let surface_capabilities = surface.get_capabilities(&adapter);
358 let format = surface_capabilities.formats[0];
359 info!("Using {:?} as the surface format", format);
360
361 let present_mode = other_modes.present_mode.into();
362 let surface_config = wgpu::SurfaceConfiguration {
363 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
364 desired_maximum_frame_latency: 2,
365 format,
366 width: dims.width,
367 height: dims.height,
368 present_mode: if surface_capabilities.present_modes.contains(&present_mode) {
369 present_mode
370 } else {
371 *surface_capabilities
372 .present_modes
373 .iter()
374 .find(|mode| PresentMode::try_from(**mode).is_ok())
375 .expect("There should never be no supported present modes")
376 },
377 alpha_mode: wgpu::CompositeAlphaMode::Opaque,
378 view_formats: Vec::new(),
379 };
380
381 let supported_internal_formats = [wgpu::TextureFormat::Rgba16Float, format];
382 let intermediate_format = supported_internal_formats
383 .into_iter()
384 .find(|format| {
385 use wgpu::TextureUsages as Usages;
386 use wgpu::TextureFormatFeatureFlags as Flags;
387 use super::AaMode;
388
389 let features = adapter
390 .get_texture_format_features(*format);
391
392 let usage_ok = features
393 .allowed_usages
394 .contains(Usages::RENDER_ATTACHMENT | Usages::COPY_SRC | Usages::TEXTURE_BINDING);
395
396 let msaa_flags = match pipeline_modes.aa {
397 AaMode::None | AaMode::Fxaa | AaMode::Hqx | AaMode::FxUpscale | AaMode::Bilinear => Flags::empty(),
398 AaMode::MsaaX4 => Flags::MULTISAMPLE_X4,
399 AaMode::MsaaX8 => Flags::MULTISAMPLE_X8,
400 AaMode::MsaaX16 => Flags::MULTISAMPLE_X8, };
402
403 let flags_ok = features.flags.contains(Flags::FILTERABLE | msaa_flags);
404
405 usage_ok && flags_ok
406 })
407 .expect("No supported intermediate format");
410 info!("Using {:?} as the intermediate format", intermediate_format);
411
412 surface.configure(&device, &surface_config);
413
414 let shadow_views = ShadowMap::create_shadow_views(
415 &device,
416 (dims.width, dims.height),
417 &ShadowMapMode::try_from(pipeline_modes.shadow).unwrap_or_default(),
418 max_texture_size,
419 )
420 .map_err(|err| {
421 warn!("Could not create shadow map views: {:?}", err);
422 })
423 .ok();
424
425 let rain_occlusion_view = RainOcclusionMap::create_view(
426 &device,
427 &pipeline_modes.rain_occlusion,
428 max_texture_size,
429 )
430 .map_err(|err| {
431 warn!("Could not create rain occlusion map views: {:?}", err);
432 })
433 .ok();
434
435 let shaders = Shaders::load_expect("");
436 let shaders_watcher = shaders.reload_watcher();
437
438 let layouts = {
439 let global = GlobalsLayouts::new(&device);
440
441 let debug = debug::DebugLayout::new(&device);
442 let figure = figure::FigureLayout::new(&device);
443 let shadow = shadow::ShadowLayout::new(&device);
444 let rain_occlusion = rain_occlusion::RainOcclusionLayout::new(&device);
445 let sprite = sprite::SpriteLayout::new(&device);
446 let terrain = terrain::TerrainLayout::new(&device);
447 let rope = rope::RopeLayout::new(&device);
448 let clouds = clouds::CloudsLayout::new(&device);
449 let bloom = bloom::BloomLayout::new(&device);
450 let postprocess = Arc::new(postprocess::PostProcessLayout::new(
451 &device,
452 &pipeline_modes,
453 ));
454 let ui = ui::UiLayout::new(&device);
455 let premultiply_alpha = ui::PremultiplyAlphaLayout::new(&device);
456 let blit = blit::BlitLayout::new(&device);
457
458 let immutable = Arc::new(ImmutableLayouts {
459 global,
460
461 debug,
462 figure,
463 shadow,
464 rain_occlusion,
465 sprite,
466 terrain,
467 rope,
468 clouds,
469 bloom,
470 ui,
471 premultiply_alpha,
472 blit,
473 });
474
475 Layouts {
476 immutable,
477 postprocess,
478 }
479 };
480
481 let (interface_pipelines, creating) = pipeline_creation::initial_create_pipelines(
482 device.clone(),
483 Layouts {
484 immutable: Arc::clone(&layouts.immutable),
485 postprocess: Arc::clone(&layouts.postprocess),
486 },
487 shaders.cloned(),
488 pipeline_modes.clone(),
489 surface_config.clone(), shadow_views.is_some(),
491 intermediate_format,
492 )?;
493
494 let state = State::Interface {
495 pipelines: interface_pipelines,
496 shadow_views,
497 rain_occlusion_view,
498 creating,
499 };
500
501 let (views, bloom_sizes) = Self::create_rt_views(
502 &device,
503 (dims.width, dims.height),
504 &pipeline_modes,
505 &other_modes,
506 intermediate_format,
507 );
508
509 let create_sampler = |filter| {
510 device.create_sampler(&wgpu::SamplerDescriptor {
511 label: None,
512 address_mode_u: AddressMode::ClampToEdge,
513 address_mode_v: AddressMode::ClampToEdge,
514 address_mode_w: AddressMode::ClampToEdge,
515 mag_filter: filter,
516 min_filter: filter,
517 mipmap_filter: FilterMode::Nearest,
518 compare: None,
519 ..Default::default()
520 })
521 };
522
523 let sampler = create_sampler(FilterMode::Linear);
524 let depth_sampler = create_sampler(FilterMode::Nearest);
525
526 let noise_tex = Texture::new(
527 &device,
528 &queue,
529 &assets::Image::load_expect("voxygen.texture.noise").read().0,
530 Some(FilterMode::Linear),
531 Some(AddressMode::Repeat),
532 )?;
533
534 let clouds_locals =
535 Self::create_consts_inner(&device, &queue, &[clouds::Locals::default()]);
536 let postprocess_locals =
537 Self::create_consts_inner(&device, &queue, &[postprocess::Locals::default()]);
538
539 let locals = Locals::new(
540 &device,
541 &layouts,
542 clouds_locals,
543 postprocess_locals,
544 &views.tgt_color,
545 &views.tgt_mat,
546 &views.tgt_depth,
547 views.bloom_tgts.as_ref().map(|tgts| locals::BloomParams {
548 locals: bloom_sizes.map(|size| {
549 Self::create_consts_inner(&device, &queue, &[bloom::Locals::new(size)])
550 }),
551 src_views: [&views.tgt_color_pp, &tgts[1], &tgts[2], &tgts[3], &tgts[4]],
552 final_tgt_view: &tgts[0],
553 }),
554 &views.tgt_color_pp,
555 &sampler,
556 &depth_sampler,
557 );
558
559 let quad_index_buffer_u16 =
560 create_quad_index_buffer_u16(&device, QUAD_INDEX_BUFFER_U16_START_VERT_LEN as usize);
561 let quad_index_buffer_u32 =
562 create_quad_index_buffer_u32(&device, QUAD_INDEX_BUFFER_U32_START_VERT_LEN as usize);
563 other_modes.profiler_enabled &= profiler_features_enabled;
564 let profiler =
565 wgpu_profiler::GpuProfiler::new(&device, wgpu_profiler::GpuProfilerSettings {
566 enable_timer_queries: other_modes.profiler_enabled,
567 enable_debug_groups: other_modes.profiler_enabled,
568 max_num_pending_frames: 4,
569 })
570 .expect("Error creating profiler");
571
572 #[cfg(feature = "egui-ui")]
573 let egui_renderer = egui_wgpu::Renderer::new(&device, format, Default::default());
574
575 let present_modes = surface
576 .get_capabilities(&adapter)
577 .present_modes
578 .into_iter()
579 .filter_map(|present_mode| PresentMode::try_from(present_mode).ok())
580 .collect();
581
582 Ok(Self {
583 device,
584 queue,
585 surface,
586 surface_config,
587
588 state,
589 recreation_pending: None,
590
591 layouts,
592 locals,
593 views,
594
595 sampler,
596 depth_sampler,
597 noise_tex,
598
599 quad_index_buffer_u16,
600 quad_index_buffer_u32,
601
602 shaders,
603 shaders_watcher,
604
605 pipeline_modes,
606 other_modes,
607 resolution: Vec2::new(dims.width, dims.height),
608
609 take_screenshot: None,
610
611 profiler,
612 profile_times: Vec::new(),
613 profiler_features_enabled,
614
615 ui_premultiply_uploads: Default::default(),
616
617 #[cfg(feature = "egui-ui")]
618 egui_renderer,
619
620 is_minimized: false,
621
622 graphics_backend,
623
624 intermediate_format,
625
626 present_modes,
627 max_texture_size,
628 })
629 }
630
631 pub fn graphics_backend(&self) -> &str { &self.graphics_backend }
633
634 pub fn pipeline_creation_status(&self) -> Option<(usize, usize)> {
638 if let State::Interface { creating, .. } = &self.state {
639 Some(creating.status())
640 } else {
641 None
642 }
643 }
644
645 pub fn pipeline_recreation_status(&self) -> Option<(usize, usize)> {
649 if let State::Complete { recreating, .. } = &self.state {
650 recreating.as_ref().map(|(_, c)| c.status())
651 } else {
652 None
653 }
654 }
655
656 pub fn set_render_mode(&mut self, mode: RenderMode) -> Result<(), RenderError> {
658 let (pipeline_modes, other_modes) = mode.split();
659
660 if self.other_modes != other_modes {
661 self.other_modes = other_modes;
662
663 if self.present_modes.contains(&self.other_modes.present_mode) {
665 self.surface_config.present_mode = self.other_modes.present_mode.into()
666 }
667
668 self.other_modes.profiler_enabled &= self.profiler_features_enabled;
670 if !self.other_modes.profiler_enabled {
672 core::mem::take(&mut self.profile_times);
674 }
675 self.profiler
676 .change_settings(wgpu_profiler::GpuProfilerSettings {
677 enable_timer_queries: self.other_modes.profiler_enabled,
678 enable_debug_groups: self.other_modes.profiler_enabled,
679 max_num_pending_frames: 4,
680 })
681 .expect("Error creating profiler");
682
683 self.on_resize(self.resolution);
685 }
686
687 if self.pipeline_modes != pipeline_modes
691 || self
692 .recreation_pending
693 .as_ref()
694 .is_some_and(|modes| modes != &pipeline_modes)
695 {
696 self.recreate_pipelines(pipeline_modes);
698 }
699
700 Ok(())
701 }
702
703 pub fn pipeline_modes(&self) -> &PipelineModes { &self.pipeline_modes }
705
706 pub fn present_modes(&self) -> &[PresentMode] { &self.present_modes }
708
709 pub fn timings(&self) -> Vec<(u8, &str, f64)> {
713 fn recursive_collect<'a>(
714 vec: &mut Vec<(u8, &'a str, f64)>,
715 result: &'a wgpu_profiler::GpuTimerQueryResult,
716 nest_level: u8,
717 ) {
718 if let Some(time) = &result.time {
719 vec.push((nest_level, &result.label, time.end - time.start));
720 }
721 result
722 .nested_queries
723 .iter()
724 .for_each(|child| recursive_collect(vec, child, nest_level + 1));
725 }
726 let mut vec = Vec::new();
727 self.profile_times
728 .iter()
729 .for_each(|child| recursive_collect(&mut vec, child, 0));
730 vec
731 }
732
733 pub fn on_resize(&mut self, dims: Vec2<u32>) {
735 if dims.x != 0 && dims.y != 0 {
737 self.is_minimized = false;
738 self.resolution = dims;
740 self.surface_config.width = dims.x;
741 self.surface_config.height = dims.y;
742 self.surface.configure(&self.device, &self.surface_config);
743
744 let (views, bloom_sizes) = Self::create_rt_views(
746 &self.device,
747 (dims.x, dims.y),
748 &self.pipeline_modes,
749 &self.other_modes,
750 self.intermediate_format,
751 );
752 self.views = views;
753
754 let bloom_params = self
755 .views
756 .bloom_tgts
757 .as_ref()
758 .map(|tgts| locals::BloomParams {
759 locals: bloom_sizes.map(|size| {
760 Self::create_consts_inner(&self.device, &self.queue, &[bloom::Locals::new(
761 size,
762 )])
763 }),
764 src_views: [
765 &self.views.tgt_color_pp,
766 &tgts[1],
767 &tgts[2],
768 &tgts[3],
769 &tgts[4],
770 ],
771 final_tgt_view: &tgts[0],
772 });
773
774 self.locals.rebind(
775 &self.device,
776 &self.layouts,
777 &self.views.tgt_color,
778 &self.views.tgt_mat,
779 &self.views.tgt_depth,
780 bloom_params,
781 &self.views.tgt_color_pp,
782 &self.sampler,
783 &self.depth_sampler,
784 );
785
786 let shadow_views = match &mut self.state {
788 State::Interface {
789 shadow_views,
790 rain_occlusion_view,
791 ..
792 } => shadow_views
793 .as_mut()
794 .map(|s| (&mut s.0, &mut s.1))
795 .zip(rain_occlusion_view.as_mut()),
796 State::Complete {
797 shadow:
798 Shadow {
799 map: ShadowMap::Enabled(shadow_map),
800 rain_map: RainOcclusionMap::Enabled(rain_occlusion_map),
801 ..
802 },
803 ..
804 } => Some((
805 (&mut shadow_map.point_depth, &mut shadow_map.directed_depth),
806 &mut rain_occlusion_map.depth,
807 )),
808 State::Complete { .. } => None,
809 State::Nothing => None, };
811
812 let mut update_shadow_bind = false;
813 let (shadow_views, rain_views) = shadow_views.unzip();
814
815 if let (Some((point_depth, directed_depth)), ShadowMode::Map(mode)) =
816 (shadow_views, self.pipeline_modes.shadow)
817 {
818 match ShadowMap::create_shadow_views(
819 &self.device,
820 (dims.x, dims.y),
821 &mode,
822 self.max_texture_size,
823 ) {
824 Ok((new_point_depth, new_directed_depth)) => {
825 *point_depth = new_point_depth;
826 *directed_depth = new_directed_depth;
827
828 update_shadow_bind = true;
829 },
830 Err(err) => {
831 warn!("Could not create shadow map views: {:?}", err);
832 },
833 }
834 }
835 if let Some(rain_depth) = rain_views {
836 match RainOcclusionMap::create_view(
837 &self.device,
838 &self.pipeline_modes.rain_occlusion,
839 self.max_texture_size,
840 ) {
841 Ok(new_rain_depth) => {
842 *rain_depth = new_rain_depth;
843
844 update_shadow_bind = true;
845 },
846 Err(err) => {
847 warn!("Could not create rain occlusion map view: {:?}", err);
848 },
849 }
850 }
851 if update_shadow_bind {
852 if let State::Complete {
854 shadow:
855 Shadow {
856 bind,
857 map: ShadowMap::Enabled(shadow_map),
858 rain_map: RainOcclusionMap::Enabled(rain_occlusion_map),
859 ..
860 },
861 ..
862 } = &mut self.state
863 {
864 *bind = self.layouts.global.bind_shadow_textures(
865 &self.device,
866 &shadow_map.point_depth,
867 &shadow_map.directed_depth,
868 &rain_occlusion_map.depth,
869 );
870 }
871 }
872 } else {
873 self.is_minimized = true;
874 }
875 }
876
877 pub fn maintain(&self) {
878 if self.is_minimized {
879 self.queue.submit(std::iter::empty());
880 }
881
882 let _ = self.device.poll(wgpu::PollType::Poll);
883 }
884
885 fn create_rt_views(
887 device: &wgpu::Device,
888 size: (u32, u32),
889 pipeline_modes: &PipelineModes,
890 other_modes: &OtherModes,
891 format: wgpu::TextureFormat,
892 ) -> (Views, [Vec2<f32>; bloom::NUM_SIZES]) {
893 let upscaled = Vec2::<u32>::from(size)
894 .map(|e| (e as f32 * other_modes.upscale_mode.factor) as u32)
895 .into_tuple();
896 let (width, height) = upscaled;
897 let sample_count = pipeline_modes.aa.samples();
898 let levels = 1;
899
900 let color_view = |width, height, format| {
901 let tex = device.create_texture(&wgpu::TextureDescriptor {
902 label: None,
903 size: wgpu::Extent3d {
904 width,
905 height,
906 depth_or_array_layers: 1,
907 },
908 mip_level_count: levels,
909 sample_count,
910 dimension: wgpu::TextureDimension::D2,
911 format,
912 usage: wgpu::TextureUsages::TEXTURE_BINDING
913 | wgpu::TextureUsages::RENDER_ATTACHMENT,
914 view_formats: &[],
915 });
916
917 tex.create_view(&wgpu::TextureViewDescriptor {
918 label: None,
919 format: Some(format),
920 dimension: Some(wgpu::TextureViewDimension::D2),
921 usage: None,
922 aspect: wgpu::TextureAspect::All,
924 base_mip_level: 0,
925 mip_level_count: None,
926 base_array_layer: 0,
927 array_layer_count: None,
928 })
929 };
930
931 let tgt_color_view = color_view(width, height, format);
932 let tgt_color_pp_view = color_view(width, height, format);
933
934 let tgt_mat_view = color_view(width, height, wgpu::TextureFormat::Rgba8Uint);
935
936 let mut size_shift = 0;
937 let bloom_sizes = [(); bloom::NUM_SIZES].map(|()| {
939 let size = Vec2::new(width, height).map(|e| (e >> size_shift).max(1));
941 size_shift += 1;
942 size
943 });
944
945 let bloom_tgt_views = pipeline_modes
946 .bloom
947 .is_on()
948 .then(|| bloom_sizes.map(|size| color_view(size.x, size.y, format)));
949
950 let tgt_depth_tex = device.create_texture(&wgpu::TextureDescriptor {
951 label: None,
952 size: wgpu::Extent3d {
953 width,
954 height,
955 depth_or_array_layers: 1,
956 },
957 mip_level_count: levels,
958 sample_count,
959 dimension: wgpu::TextureDimension::D2,
960 format: wgpu::TextureFormat::Depth32Float,
961 usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
962 view_formats: &[],
963 });
964 let tgt_depth_view = tgt_depth_tex.create_view(&wgpu::TextureViewDescriptor {
965 label: None,
966 format: Some(wgpu::TextureFormat::Depth32Float),
967 dimension: Some(wgpu::TextureViewDimension::D2),
968 usage: None,
969 aspect: wgpu::TextureAspect::DepthOnly,
970 base_mip_level: 0,
971 mip_level_count: None,
972 base_array_layer: 0,
973 array_layer_count: None,
974 });
975
976 let win_depth_tex = device.create_texture(&wgpu::TextureDescriptor {
977 label: None,
978 size: wgpu::Extent3d {
979 width: size.0,
980 height: size.1,
981 depth_or_array_layers: 1,
982 },
983 mip_level_count: levels,
984 sample_count,
985 dimension: wgpu::TextureDimension::D2,
986 format: wgpu::TextureFormat::Depth32Float,
987 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
988 view_formats: &[],
989 });
990 let win_depth_view = win_depth_tex.create_view(&wgpu::TextureViewDescriptor {
992 label: None,
993 format: Some(wgpu::TextureFormat::Depth32Float),
994 dimension: Some(wgpu::TextureViewDimension::D2),
995 usage: None,
996 aspect: wgpu::TextureAspect::DepthOnly,
997 base_mip_level: 0,
998 mip_level_count: None,
999 base_array_layer: 0,
1000 array_layer_count: None,
1001 });
1002
1003 (
1004 Views {
1005 tgt_color: tgt_color_view,
1006 tgt_mat: tgt_mat_view,
1007 tgt_depth: tgt_depth_view,
1008 bloom_tgts: bloom_tgt_views,
1009 tgt_color_pp: tgt_color_pp_view,
1010 _win_depth: win_depth_view,
1011 },
1012 bloom_sizes.map(|s| s.map(|e| e as f32)),
1013 )
1014 }
1015
1016 pub fn resolution(&self) -> Vec2<u32> { self.resolution }
1018
1019 pub fn get_shadow_resolution(&self) -> (Vec2<u32>, Vec2<u32>) {
1021 match &self.state {
1022 State::Interface { shadow_views, .. } => shadow_views.as_ref().map(|s| (&s.0, &s.1)),
1023 State::Complete {
1024 shadow:
1025 Shadow {
1026 map: ShadowMap::Enabled(shadow_map),
1027 ..
1028 },
1029 ..
1030 } => Some((&shadow_map.point_depth, &shadow_map.directed_depth)),
1031 State::Complete { .. } | State::Nothing => None,
1032 }
1033 .map(|(point, directed)| (point.get_dimensions().xy(), directed.get_dimensions().xy()))
1034 .unwrap_or_else(|| (Vec2::new(1, 1), Vec2::new(1, 1)))
1035 }
1036
1037 pub fn start_recording_frame<'a>(
1043 &'a mut self,
1044 globals: &'a GlobalsBindGroup,
1045 ) -> Result<Option<drawer::Drawer<'a>>, RenderError> {
1046 span!(
1047 _guard,
1048 "start_recording_frame",
1049 "Renderer::start_recording_frame"
1050 );
1051
1052 if self.is_minimized {
1053 return Ok(None);
1054 }
1055
1056 if self.other_modes.profiler_enabled {
1058 let timestamp_period = self.queue.get_timestamp_period();
1060 if let Some(profile_times) = self.profiler.process_finished_frame(timestamp_period) {
1061 self.profile_times = profile_times;
1062 }
1063 }
1064
1065 let state = core::mem::replace(&mut self.state, State::Nothing);
1068 let mut trigger_on_resize = false;
1072 self.state = if let State::Interface {
1074 pipelines: interface,
1075 shadow_views,
1076 rain_occlusion_view,
1077 creating,
1078 } = state
1079 {
1080 match creating.try_complete() {
1081 Ok(pipelines) => {
1082 let IngameAndShadowPipelines {
1083 ingame,
1084 shadow,
1085 rain_occlusion,
1086 } = pipelines;
1087
1088 let pipelines = Pipelines::consolidate(interface, ingame);
1089
1090 let shadow_map = ShadowMap::new(
1091 &self.device,
1092 &self.queue,
1093 shadow.point,
1094 shadow.directed,
1095 shadow.figure,
1096 shadow.debug,
1097 shadow_views,
1098 );
1099
1100 let rain_occlusion_map = RainOcclusionMap::new(
1101 &self.device,
1102 &self.queue,
1103 rain_occlusion.terrain,
1104 rain_occlusion.figure,
1105 rain_occlusion_view,
1106 );
1107
1108 let shadow_bind = {
1109 let (point, directed) = shadow_map.textures();
1110 self.layouts.global.bind_shadow_textures(
1111 &self.device,
1112 point,
1113 directed,
1114 rain_occlusion_map.texture(),
1115 )
1116 };
1117
1118 let shadow = Shadow {
1119 rain_map: rain_occlusion_map,
1120 map: shadow_map,
1121 bind: shadow_bind,
1122 };
1123
1124 State::Complete {
1125 pipelines,
1126 shadow,
1127 recreating: None,
1128 }
1129 },
1130 Err(creating) => State::Interface {
1132 pipelines: interface,
1133 shadow_views,
1134 rain_occlusion_view,
1135 creating,
1136 },
1137 }
1138 } else if let State::Complete {
1140 pipelines,
1141 mut shadow,
1142 recreating: Some((new_pipeline_modes, pipeline_creation)),
1143 } = state
1144 {
1145 match pipeline_creation.try_complete() {
1146 Ok(Ok((
1147 pipelines,
1148 shadow_pipelines,
1149 rain_occlusion_pipelines,
1150 postprocess_layout,
1151 ))) => {
1152 if let (
1153 Some(point_pipeline),
1154 Some(terrain_directed_pipeline),
1155 Some(figure_directed_pipeline),
1156 Some(debug_directed_pipeline),
1157 ShadowMap::Enabled(shadow_map),
1158 ) = (
1159 shadow_pipelines.point,
1160 shadow_pipelines.directed,
1161 shadow_pipelines.figure,
1162 shadow_pipelines.debug,
1163 &mut shadow.map,
1164 ) {
1165 shadow_map.point_pipeline = point_pipeline;
1166 shadow_map.terrain_directed_pipeline = terrain_directed_pipeline;
1167 shadow_map.figure_directed_pipeline = figure_directed_pipeline;
1168 shadow_map.debug_directed_pipeline = debug_directed_pipeline;
1169 }
1170
1171 if let (
1172 Some(terrain_directed_pipeline),
1173 Some(figure_directed_pipeline),
1174 RainOcclusionMap::Enabled(rain_occlusion_map),
1175 ) = (
1176 rain_occlusion_pipelines.terrain,
1177 rain_occlusion_pipelines.figure,
1178 &mut shadow.rain_map,
1179 ) {
1180 rain_occlusion_map.terrain_pipeline = terrain_directed_pipeline;
1181 rain_occlusion_map.figure_pipeline = figure_directed_pipeline;
1182 }
1183
1184 self.pipeline_modes = new_pipeline_modes;
1185 self.layouts.postprocess = postprocess_layout;
1186 trigger_on_resize = true;
1190
1191 State::Complete {
1192 pipelines,
1193 shadow,
1194 recreating: None,
1195 }
1196 },
1197 Ok(Err(e)) => {
1198 error!(?e, "Could not recreate shaders from assets due to an error");
1199 State::Complete {
1200 pipelines,
1201 shadow,
1202 recreating: None,
1203 }
1204 },
1205 Err(pipeline_creation) => State::Complete {
1207 pipelines,
1208 shadow,
1209 recreating: Some((new_pipeline_modes, pipeline_creation)),
1210 },
1211 }
1212 } else {
1213 state
1214 };
1215
1216 if trigger_on_resize {
1220 self.on_resize(self.resolution);
1221 }
1222
1223 if self.shaders_watcher.reloaded() {
1225 self.recreate_pipelines(self.pipeline_modes.clone());
1226 }
1227
1228 if matches!(&self.state, State::Complete {
1230 recreating: None,
1231 ..
1232 }) && let Some(new_pipeline_modes) = self.recreation_pending.take()
1233 {
1234 self.recreate_pipelines(new_pipeline_modes);
1235 }
1236
1237 let texture = match self.surface.get_current_texture() {
1238 Ok(texture) => {
1239 if texture.suboptimal {
1240 warn!("Suboptimal swap chain, recreating");
1241 drop(texture);
1242 self.surface.configure(&self.device, &self.surface_config);
1243 return Ok(None);
1244 } else {
1245 texture
1246 }
1247 },
1248 Err(err @ wgpu::SurfaceError::Lost) => {
1250 warn!("{}. Recreating swap chain. A frame will be missed", err);
1251 self.surface.configure(&self.device, &self.surface_config);
1252 return Ok(None);
1253 },
1254 Err(wgpu::SurfaceError::Timeout) => {
1255 return Ok(None);
1259 },
1260 Err(err @ wgpu::SurfaceError::Outdated) => {
1261 warn!("{}. Recreating the swapchain", err);
1262 self.surface.configure(&self.device, &self.surface_config);
1263 return Ok(None);
1264 },
1265 Err(err @ (wgpu::SurfaceError::OutOfMemory | wgpu::SurfaceError::Other)) => {
1266 return Err(err.into());
1267 },
1268 };
1269 let encoder = self
1270 .device
1271 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
1272 label: Some("A render encoder"),
1273 });
1274
1275 Ok(Some(drawer::Drawer::new(encoder, self, texture, globals)))
1276 }
1277
1278 fn recreate_pipelines(&mut self, pipeline_modes: PipelineModes) {
1280 match &mut self.state {
1281 State::Complete { recreating, .. } if recreating.is_some() => {
1282 self.recreation_pending = Some(pipeline_modes);
1285 },
1286 State::Complete {
1287 recreating, shadow, ..
1288 } => {
1289 *recreating = Some((
1290 pipeline_modes.clone(),
1291 pipeline_creation::recreate_pipelines(
1292 self.device.clone(),
1293 Arc::clone(&self.layouts.immutable),
1294 self.shaders.cloned(),
1295 pipeline_modes,
1296 self.surface_config.clone(), shadow.map.is_enabled(),
1302 self.intermediate_format,
1303 ),
1304 ));
1305 },
1306 State::Interface { .. } => {
1307 self.recreation_pending = Some(pipeline_modes);
1310 },
1311 State::Nothing => {},
1312 }
1313 }
1314
1315 pub fn create_consts<T: Copy + bytemuck::Pod>(&mut self, vals: &[T]) -> Consts<T> {
1317 Self::create_consts_inner(&self.device, &self.queue, vals)
1318 }
1319
1320 pub fn create_consts_inner<T: Copy + bytemuck::Pod>(
1321 device: &wgpu::Device,
1322 queue: &wgpu::Queue,
1323 vals: &[T],
1324 ) -> Consts<T> {
1325 let mut consts = Consts::new(device, vals.len());
1326 consts.update(queue, vals, 0);
1327 consts
1328 }
1329
1330 pub fn update_consts<T: Copy + bytemuck::Pod>(&self, consts: &mut Consts<T>, vals: &[T]) {
1332 consts.update(&self.queue, vals, 0)
1333 }
1334
1335 pub fn update_clouds_locals(&mut self, new_val: clouds::Locals) {
1336 self.locals.clouds.update(&self.queue, &[new_val], 0)
1337 }
1338
1339 pub fn update_postprocess_locals(&mut self, new_val: postprocess::Locals) {
1340 self.locals.postprocess.update(&self.queue, &[new_val], 0)
1341 }
1342
1343 pub fn create_instances<T: Copy + bytemuck::Pod>(&mut self, vals: &[T]) -> Instances<T> {
1345 let mut instances = Instances::new(&self.device, vals.len());
1346 instances.update(&self.queue, vals, 0);
1347 instances
1348 }
1349
1350 pub(super) fn ensure_sufficient_index_length<V: Vertex>(
1353 &mut self,
1354 vert_length: usize,
1356 ) {
1357 let quad_index_length = vert_length / 4 * 6;
1358
1359 match V::QUADS_INDEX {
1360 Some(wgpu::IndexFormat::Uint16) => {
1361 if self.quad_index_buffer_u16.len() < quad_index_length {
1363 if vert_length > u16::MAX as usize {
1365 panic!(
1366 "Vertex type: {} needs to use a larger index type, length: {}",
1367 core::any::type_name::<V>(),
1368 vert_length
1369 );
1370 }
1371 self.quad_index_buffer_u16 =
1372 create_quad_index_buffer_u16(&self.device, vert_length);
1373 }
1374 },
1375 Some(wgpu::IndexFormat::Uint32) => {
1376 if self.quad_index_buffer_u32.len() < quad_index_length {
1378 if vert_length > u32::MAX as usize {
1380 panic!(
1381 "More than u32::MAX({}) verts({}) for type({}) using an index buffer!",
1382 u32::MAX,
1383 vert_length,
1384 core::any::type_name::<V>()
1385 );
1386 }
1387 self.quad_index_buffer_u32 =
1388 create_quad_index_buffer_u32(&self.device, vert_length);
1389 }
1390 },
1391 None => {},
1392 }
1393 }
1394
1395 pub fn create_sprite_verts(&mut self, mesh: Mesh<sprite::Vertex>) -> sprite::SpriteVerts {
1396 self.ensure_sufficient_index_length::<sprite::Vertex>(sprite::VERT_PAGE_SIZE as usize);
1397 sprite::create_verts_buffer(&self.device, mesh)
1398 }
1399
1400 pub fn create_model<V: Vertex>(&mut self, mesh: &Mesh<V>) -> Option<Model<V>> {
1403 self.ensure_sufficient_index_length::<V>(mesh.vertices().len());
1404 Model::new(&self.device, mesh)
1405 }
1406
1407 pub fn create_dynamic_model<V: Vertex>(&mut self, size: usize) -> DynamicModel<V> {
1409 self.ensure_sufficient_index_length::<V>(size);
1410 DynamicModel::new(&self.device, size)
1411 }
1412
1413 pub fn update_model<V: Vertex>(&self, model: &DynamicModel<V>, mesh: &Mesh<V>, offset: usize) {
1415 model.update(&self.queue, mesh, offset)
1416 }
1417
1418 pub fn max_texture_size(&self) -> u32 { self.max_texture_size }
1420
1421 pub fn create_texture_with_data_raw(
1426 &mut self,
1427 texture_info: &wgpu::TextureDescriptor,
1428 view_info: &wgpu::TextureViewDescriptor,
1429 sampler_info: &wgpu::SamplerDescriptor,
1430 data: &[u8],
1431 ) -> Texture {
1432 let tex = Texture::new_raw(&self.device, texture_info, view_info, sampler_info);
1433
1434 let size = texture_info.size;
1435 let block_size = texture_info.format.block_copy_size(None).unwrap();
1436 assert_eq!(
1437 size.width as usize
1438 * size.height as usize
1439 * size.depth_or_array_layers as usize
1440 * block_size as usize,
1441 data.len(),
1442 "Provided data length {} does not fill the provided texture size {:?}",
1443 data.len(),
1444 size,
1445 );
1446
1447 tex.update(
1448 &self.queue,
1449 [0; 2],
1450 [texture_info.size.width, texture_info.size.height],
1451 data,
1452 );
1453
1454 tex
1455 }
1456
1457 pub fn create_texture_raw(
1459 &mut self,
1460 texture_info: &wgpu::TextureDescriptor,
1461 view_info: &wgpu::TextureViewDescriptor,
1462 sampler_info: &wgpu::SamplerDescriptor,
1463 ) -> Texture {
1464 let texture = Texture::new_raw(&self.device, texture_info, view_info, sampler_info);
1465 texture.clear(&self.queue); texture
1467 }
1468
1469 pub fn create_texture(
1471 &mut self,
1472 image: &image::DynamicImage,
1473 filter_method: Option<FilterMode>,
1474 address_mode: Option<AddressMode>,
1475 ) -> Result<Texture, RenderError> {
1476 Texture::new(
1477 &self.device,
1478 &self.queue,
1479 image,
1480 filter_method,
1481 address_mode,
1482 )
1483 }
1484
1485 pub fn create_dynamic_texture(&mut self, dims: Vec2<u32>) -> Texture {
1489 Texture::new_dynamic(&self.device, &self.queue, dims.x, dims.y)
1490 }
1491
1492 pub fn update_texture<T: bytemuck::Pod>(
1494 &mut self,
1495 texture: &Texture,
1496 offset: [u32; 2],
1497 size: [u32; 2],
1498 data: &[T],
1499 ) {
1500 texture.update(&self.queue, offset, size, bytemuck::cast_slice(data))
1501 }
1502
1503 pub fn ui_premultiply_upload(
1505 &mut self,
1506 target_texture: &Arc<Texture>,
1507 batch: ui::UploadBatchId,
1508 image: &image::RgbaImage,
1509 offset: Vec2<u16>,
1510 ) -> ui::UploadBatchId {
1511 let upload = ui::PremultiplyUpload::prepare(
1512 &self.device,
1513 &self.queue,
1514 &self.layouts.premultiply_alpha,
1515 image,
1516 offset,
1517 );
1518 self.ui_premultiply_uploads
1519 .submit(target_texture, batch, upload)
1520 }
1521
1522 pub fn create_screenshot(
1524 &mut self,
1525 screenshot_handler: impl FnOnce(Result<image::RgbImage, String>) + Send + 'static,
1526 ) {
1527 self.take_screenshot = Some(Box::new(screenshot_handler));
1529 if self.other_modes.profiler_enabled {
1531 let file_name = format!(
1532 "frame-trace_{}.json",
1533 std::time::SystemTime::now()
1534 .duration_since(std::time::SystemTime::UNIX_EPOCH)
1535 .map(|d| d.as_millis())
1536 .unwrap_or(0)
1537 );
1538
1539 if let Err(err) = wgpu_profiler::chrometrace::write_chrometrace(
1540 std::path::Path::new(&file_name),
1541 &self.profile_times,
1542 ) {
1543 error!(?err, "Failed to save GPU timing snapshot");
1544 } else {
1545 info!("Saved GPU timing snapshot as: {}", file_name);
1546 }
1547 }
1548 }
1549
1550 }
1598
1599fn create_quad_index_buffer_u16(device: &wgpu::Device, vert_length: usize) -> Buffer<u16> {
1600 assert!(vert_length <= u16::MAX as usize);
1601 let indices = [0, 1, 2, 2, 1, 3]
1602 .iter()
1603 .cycle()
1604 .copied()
1605 .take(vert_length / 4 * 6)
1606 .enumerate()
1607 .map(|(i, b)| (i / 6 * 4 + b) as u16)
1608 .collect::<Vec<_>>();
1609
1610 Buffer::new(device, wgpu::BufferUsages::INDEX, &indices)
1611}
1612
1613fn create_quad_index_buffer_u32(device: &wgpu::Device, vert_length: usize) -> Buffer<u32> {
1614 assert!(vert_length <= u32::MAX as usize);
1615 let indices = [0, 1, 2, 2, 1, 3]
1616 .iter()
1617 .cycle()
1618 .copied()
1619 .take(vert_length / 4 * 6)
1620 .enumerate()
1621 .map(|(i, b)| (i / 6 * 4 + b) as u32)
1622 .collect::<Vec<_>>();
1623
1624 Buffer::new(device, wgpu::BufferUsages::INDEX, &indices)
1625}
1626
1627pub struct AltIndices {
1638 pub deep_end: usize,
1639 pub underground_end: usize,
1640}
1641
1642#[derive(Copy, Clone, Default)]
1645pub enum CullingMode {
1646 #[default]
1648 None,
1649 Surface,
1652 Underground,
1655}