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