fyrox_impl/renderer/
mod.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Renderer is a "workhorse" of the engine, it draws scenes (both 3D and 2D), user interface,
22//! debug geometry and has an ability to add user-defined render passes. Current renderer
23//! implementation is not very flexible, but should cover 95% of use cases.
24//!
25//! # Implementation details
26//!
27//! Renderer is based on OpenGL 3.3+ Core.
28
29#![warn(missing_docs)]
30
31pub mod framework;
32
33pub mod bundle;
34pub mod cache;
35pub mod debug_renderer;
36pub mod storage;
37pub mod ui_renderer;
38pub mod visibility;
39
40mod bloom;
41mod flat_shader;
42mod forward_renderer;
43mod fxaa;
44mod gbuffer;
45mod hdr;
46mod light;
47mod light_volume;
48mod occlusion;
49mod shadow;
50mod skybox_shader;
51mod ssao;
52mod stats;
53
54use crate::{
55    asset::{event::ResourceEvent, manager::ResourceManager},
56    core::{
57        algebra::{Matrix4, Vector2, Vector3, Vector4},
58        array_as_u8_slice,
59        color::Color,
60        instant,
61        log::{Log, MessageKind},
62        math::Rect,
63        pool::Handle,
64        reflect::prelude::*,
65        sstorage::ImmutableString,
66        uuid_provider,
67    },
68    engine::error::EngineError,
69    graph::SceneGraph,
70    gui::draw::DrawingContext,
71    material::shader::{Shader, ShaderDefinition},
72    renderer::{
73        bloom::BloomRenderer,
74        bundle::{ObserverInfo, RenderDataBundleStorage, RenderDataBundleStorageOptions},
75        cache::{
76            geometry::GeometryCache, shader::ShaderCache, texture::TextureCache,
77            uniform::UniformBufferCache, uniform::UniformMemoryAllocator,
78        },
79        debug_renderer::DebugRenderer,
80        flat_shader::FlatShader,
81        forward_renderer::{ForwardRenderContext, ForwardRenderer},
82        framework::{
83            buffer::{Buffer, BufferKind, BufferUsage},
84            error::FrameworkError,
85            framebuffer::{
86                Attachment, AttachmentKind, BufferLocation, FrameBuffer, ResourceBindGroup,
87                ResourceBinding,
88            },
89            geometry_buffer::GeometryBuffer,
90            gpu_program::SamplerFallback,
91            gpu_texture::{GpuTexture, GpuTextureDescriptor, GpuTextureKind, PixelKind},
92            server::{GraphicsServer, SharedGraphicsServer},
93            uniform::StaticUniformBuffer,
94            DrawParameters, ElementRange, GeometryBufferExt, PolygonFace, PolygonFillMode,
95        },
96        fxaa::FxaaRenderer,
97        gbuffer::{GBuffer, GBufferRenderContext},
98        hdr::HighDynamicRangeRenderer,
99        light::{DeferredLightRenderer, DeferredRendererContext},
100        ui_renderer::{UiRenderContext, UiRenderer},
101        visibility::VisibilityCache,
102    },
103    resource::texture::{Texture, TextureKind, TextureResource},
104    scene::{camera::Camera, mesh::surface::SurfaceData, Scene, SceneContainer},
105};
106use fxhash::FxHashMap;
107use fyrox_graphics::framebuffer::DrawCallStatistics;
108use lazy_static::lazy_static;
109use serde::{Deserialize, Serialize};
110pub use stats::*;
111use std::{any::TypeId, cell::RefCell, collections::hash_map::Entry, rc::Rc, sync::mpsc::Receiver};
112use strum_macros::{AsRefStr, EnumString, VariantNames};
113use winit::window::Window;
114
115lazy_static! {
116    static ref GBUFFER_PASS_NAME: ImmutableString = ImmutableString::new("GBuffer");
117    static ref DIRECTIONAL_SHADOW_PASS_NAME: ImmutableString =
118        ImmutableString::new("DirectionalShadow");
119    static ref SPOT_SHADOW_PASS_NAME: ImmutableString = ImmutableString::new("SpotShadow");
120    static ref POINT_SHADOW_PASS_NAME: ImmutableString = ImmutableString::new("PointShadow");
121}
122
123/// Checks whether the provided render pass name is one of the names of built-in shadow render passes.
124pub fn is_shadow_pass(render_pass_name: &str) -> bool {
125    render_pass_name == &**DIRECTIONAL_SHADOW_PASS_NAME
126        || render_pass_name == &**SPOT_SHADOW_PASS_NAME
127        || render_pass_name == &**POINT_SHADOW_PASS_NAME
128}
129
130/// Shadow map precision allows you to select compromise between quality and performance.
131#[derive(
132    Copy,
133    Clone,
134    Hash,
135    PartialOrd,
136    PartialEq,
137    Eq,
138    Ord,
139    Debug,
140    Serialize,
141    Deserialize,
142    Reflect,
143    AsRefStr,
144    EnumString,
145    VariantNames,
146)]
147pub enum ShadowMapPrecision {
148    /// Shadow map will use 2 times less memory by switching to 16bit pixel format,
149    /// but "shadow acne" may occur.
150    Half,
151    /// Shadow map will use 32bit pixel format. This option gives highest quality,
152    /// but could be less performant than `Half`.
153    Full,
154}
155
156uuid_provider!(ShadowMapPrecision = "f9b2755b-248e-46ba-bcab-473eac1acdb8");
157
158/// Cascaded-shadow maps settings.
159#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, Reflect, Eq)]
160pub struct CsmSettings {
161    /// Whether cascaded shadow maps enabled or not.
162    pub enabled: bool,
163
164    /// Size of texture for each cascade.
165    pub size: usize,
166
167    /// Bit-wise precision for each cascade, the lower precision the better performance is,
168    /// but the more artifacts may occur.
169    pub precision: ShadowMapPrecision,
170
171    /// Whether to use Percentage-Closer Filtering or not.
172    pub pcf: bool,
173}
174
175impl Default for CsmSettings {
176    fn default() -> Self {
177        Self {
178            enabled: true,
179            size: 2048,
180            precision: ShadowMapPrecision::Full,
181            pcf: true,
182        }
183    }
184}
185
186/// Quality settings allows you to find optimal balance between performance and
187/// graphics quality.
188#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, Reflect)]
189pub struct QualitySettings {
190    /// Point shadows
191    /// Size of cube map face of shadow map texture in pixels.
192    pub point_shadow_map_size: usize,
193    /// Use or not percentage close filtering (smoothing) for point shadows.
194    pub point_soft_shadows: bool,
195    /// Point shadows enabled or not.
196    pub point_shadows_enabled: bool,
197    /// Maximum distance from camera to draw shadows.
198    pub point_shadows_distance: f32,
199    /// Point shadow map precision. Allows you to select compromise between
200    /// quality and performance.
201    pub point_shadow_map_precision: ShadowMapPrecision,
202    /// Point shadows fade out range.
203    /// Specifies the distance from the camera at which point shadows start to fade out.
204    /// Shadows beyond this distance will gradually become less visible.
205    pub point_shadows_fade_out_range: f32,
206
207    /// Spot shadows
208    /// Size of square shadow map texture in pixels
209    pub spot_shadow_map_size: usize,
210    /// Use or not percentage close filtering (smoothing) for spot shadows.
211    pub spot_soft_shadows: bool,
212    /// Spot shadows enabled or not.
213    pub spot_shadows_enabled: bool,
214    /// Maximum distance from camera to draw shadows.
215    pub spot_shadows_distance: f32,
216    /// Spot shadow map precision. Allows you to select compromise between
217    /// quality and performance.
218    pub spot_shadow_map_precision: ShadowMapPrecision,
219    /// Specifies the distance from the camera at which spot shadows start to fade out.
220    /// Shadows beyond this distance will gradually become less visible.
221    pub spot_shadows_fade_out_range: f32,
222
223    /// Cascaded-shadow maps settings.
224    pub csm_settings: CsmSettings,
225
226    /// Whether to use screen space ambient occlusion or not.
227    pub use_ssao: bool,
228    /// Radius of sampling hemisphere used in SSAO, it defines much ambient
229    /// occlusion will be in your scene.
230    pub ssao_radius: f32,
231
232    /// Global switch to enable or disable light scattering. Each light can have
233    /// its own scatter switch, but this one is able to globally disable scatter.
234    pub light_scatter_enabled: bool,
235
236    /// Whether to use Fast Approximate AntiAliasing or not.
237    pub fxaa: bool,
238
239    /// Whether to use Parallax Mapping or not.
240    pub use_parallax_mapping: bool,
241
242    /// Whether to use bloom effect.
243    pub use_bloom: bool,
244
245    /// Whether to use occlusion culling for geometry or not. Warning: this is experimental feature
246    /// that may have bugs and unstable behavior. Disabled by default.
247    #[serde(default)]
248    pub use_occlusion_culling: bool,
249
250    /// Whether to use occlusion culling for light sources or not. Warning: this is experimental
251    /// feature that may have bugs and unstable behavior. Disabled by default.
252    #[serde(default)]
253    pub use_light_occlusion_culling: bool,
254}
255
256impl Default for QualitySettings {
257    fn default() -> Self {
258        Self::high()
259    }
260}
261
262impl QualitySettings {
263    /// Highest possible graphics quality. Requires very powerful GPU.
264    pub fn ultra() -> Self {
265        Self {
266            point_shadow_map_size: 2048,
267            point_shadows_distance: 20.0,
268            point_shadows_enabled: true,
269            point_soft_shadows: true,
270            point_shadows_fade_out_range: 1.0,
271
272            spot_shadow_map_size: 2048,
273            spot_shadows_distance: 20.0,
274            spot_shadows_enabled: true,
275            spot_soft_shadows: true,
276            spot_shadows_fade_out_range: 1.0,
277
278            use_ssao: true,
279            ssao_radius: 0.5,
280
281            light_scatter_enabled: true,
282
283            point_shadow_map_precision: ShadowMapPrecision::Full,
284            spot_shadow_map_precision: ShadowMapPrecision::Full,
285
286            fxaa: true,
287
288            use_bloom: true,
289
290            use_parallax_mapping: true,
291
292            csm_settings: Default::default(),
293
294            use_occlusion_culling: false,
295            use_light_occlusion_culling: false,
296        }
297    }
298
299    /// High graphics quality, includes all graphical effects. Requires powerful GPU.
300    pub fn high() -> Self {
301        Self {
302            point_shadow_map_size: 1024,
303            point_shadows_distance: 15.0,
304            point_shadows_enabled: true,
305            point_soft_shadows: true,
306            point_shadows_fade_out_range: 1.0,
307
308            spot_shadow_map_size: 1024,
309            spot_shadows_distance: 15.0,
310            spot_shadows_enabled: true,
311            spot_soft_shadows: true,
312            spot_shadows_fade_out_range: 1.0,
313
314            use_ssao: true,
315            ssao_radius: 0.5,
316
317            light_scatter_enabled: true,
318
319            point_shadow_map_precision: ShadowMapPrecision::Full,
320            spot_shadow_map_precision: ShadowMapPrecision::Full,
321
322            fxaa: true,
323
324            use_bloom: true,
325
326            use_parallax_mapping: true,
327
328            csm_settings: CsmSettings {
329                enabled: true,
330                size: 2048,
331                precision: ShadowMapPrecision::Full,
332                pcf: true,
333            },
334
335            use_occlusion_culling: false,
336            use_light_occlusion_culling: false,
337        }
338    }
339
340    /// Medium graphics quality, some of effects are disabled, shadows will have sharp edges.
341    pub fn medium() -> Self {
342        Self {
343            point_shadow_map_size: 512,
344            point_shadows_distance: 5.0,
345            point_shadows_enabled: true,
346            point_soft_shadows: false,
347            point_shadows_fade_out_range: 1.0,
348
349            spot_shadow_map_size: 512,
350            spot_shadows_distance: 5.0,
351            spot_shadows_enabled: true,
352            spot_soft_shadows: false,
353            spot_shadows_fade_out_range: 1.0,
354
355            use_ssao: true,
356            ssao_radius: 0.5,
357
358            light_scatter_enabled: false,
359
360            point_shadow_map_precision: ShadowMapPrecision::Half,
361            spot_shadow_map_precision: ShadowMapPrecision::Half,
362
363            fxaa: true,
364
365            use_bloom: true,
366
367            use_parallax_mapping: false,
368
369            csm_settings: CsmSettings {
370                enabled: true,
371                size: 512,
372                precision: ShadowMapPrecision::Full,
373                pcf: false,
374            },
375
376            use_occlusion_culling: false,
377            use_light_occlusion_culling: false,
378        }
379    }
380
381    /// Lowest graphics quality, all effects are disabled.
382    pub fn low() -> Self {
383        Self {
384            point_shadow_map_size: 1, // Zero is unsupported.
385            point_shadows_distance: 0.0,
386            point_shadows_enabled: false,
387            point_soft_shadows: false,
388            point_shadows_fade_out_range: 1.0,
389
390            spot_shadow_map_size: 1,
391            spot_shadows_distance: 0.0,
392            spot_shadows_enabled: false,
393            spot_soft_shadows: false,
394            spot_shadows_fade_out_range: 1.0,
395
396            use_ssao: false,
397            ssao_radius: 0.5,
398
399            light_scatter_enabled: false,
400
401            point_shadow_map_precision: ShadowMapPrecision::Half,
402            spot_shadow_map_precision: ShadowMapPrecision::Half,
403
404            fxaa: false,
405
406            use_bloom: false,
407
408            use_parallax_mapping: false,
409
410            csm_settings: CsmSettings {
411                enabled: true,
412                size: 512,
413                precision: ShadowMapPrecision::Half,
414                pcf: false,
415            },
416
417            use_occlusion_culling: false,
418            use_light_occlusion_culling: false,
419        }
420    }
421}
422
423impl Statistics {
424    /// Must be called before render anything.
425    fn begin_frame(&mut self) {
426        self.frame_start_time = instant::Instant::now();
427        self.geometry = Default::default();
428        self.lighting = Default::default();
429    }
430
431    /// Must be called before SwapBuffers but after all rendering is done.
432    fn end_frame(&mut self) {
433        let current_time = instant::Instant::now();
434
435        self.pure_frame_time = current_time
436            .duration_since(self.frame_start_time)
437            .as_secs_f32();
438        self.frame_counter += 1;
439
440        if current_time
441            .duration_since(self.last_fps_commit_time)
442            .as_secs_f32()
443            >= 1.0
444        {
445            self.last_fps_commit_time = current_time;
446            self.frames_per_second = self.frame_counter;
447            self.frame_counter = 0;
448        }
449    }
450
451    /// Must be called after SwapBuffers to get capped frame time.
452    fn finalize(&mut self) {
453        self.capped_frame_time = instant::Instant::now()
454            .duration_since(self.frame_start_time)
455            .as_secs_f32();
456    }
457}
458
459impl Default for Statistics {
460    fn default() -> Self {
461        Self {
462            pipeline: Default::default(),
463            lighting: Default::default(),
464            geometry: Default::default(),
465            pure_frame_time: 0.0,
466            capped_frame_time: 0.0,
467            frames_per_second: 0,
468            texture_cache_size: 0,
469            geometry_cache_size: 0,
470            shader_cache_size: 0,
471            uniform_buffer_cache_size: 0,
472            frame_counter: 0,
473            frame_start_time: instant::Instant::now(),
474            last_fps_commit_time: instant::Instant::now(),
475        }
476    }
477}
478
479/// A set of frame buffers, renderers, that contains scene-specific data.
480pub struct AssociatedSceneData {
481    /// G-Buffer of the scene.
482    pub gbuffer: GBuffer,
483
484    /// Intermediate high dynamic range frame buffer.
485    pub hdr_scene_framebuffer: Box<dyn FrameBuffer>,
486
487    /// Final frame of the scene. Tone mapped + gamma corrected.
488    pub ldr_scene_framebuffer: Box<dyn FrameBuffer>,
489
490    /// Additional frame buffer for post processing.
491    pub ldr_temp_framebuffer: Box<dyn FrameBuffer>,
492
493    /// HDR renderer has be created per scene, because it contains
494    /// scene luminance.
495    pub hdr_renderer: HighDynamicRangeRenderer,
496
497    /// Bloom contains only overly bright pixels that creates light
498    /// bleeding effect (glow effect).
499    pub bloom_renderer: BloomRenderer,
500
501    /// Rendering statistics for a scene.
502    pub statistics: SceneStatistics,
503}
504
505impl AssociatedSceneData {
506    /// Creates new scene data.
507    pub fn new(
508        server: &dyn GraphicsServer,
509        width: usize,
510        height: usize,
511    ) -> Result<Self, FrameworkError> {
512        let depth_stencil = server.create_2d_render_target(PixelKind::D24S8, width, height)?;
513        // Intermediate scene frame will be rendered in HDR render target.
514        let hdr_frame_texture =
515            server.create_2d_render_target(PixelKind::RGBA16F, width, height)?;
516
517        let hdr_scene_framebuffer = server.create_frame_buffer(
518            Some(Attachment {
519                kind: AttachmentKind::DepthStencil,
520                texture: depth_stencil.clone(),
521            }),
522            vec![Attachment {
523                kind: AttachmentKind::Color,
524                texture: hdr_frame_texture,
525            }],
526        )?;
527
528        let ldr_frame_texture = server.create_texture(GpuTextureDescriptor {
529            kind: GpuTextureKind::Rectangle { width, height },
530            // Final scene frame is in standard sRGB space.
531            pixel_kind: PixelKind::RGBA8,
532            ..Default::default()
533        })?;
534
535        let ldr_scene_framebuffer = server.create_frame_buffer(
536            Some(Attachment {
537                kind: AttachmentKind::DepthStencil,
538                texture: depth_stencil.clone(),
539            }),
540            vec![Attachment {
541                kind: AttachmentKind::Color,
542                texture: ldr_frame_texture,
543            }],
544        )?;
545
546        let ldr_temp_texture = server.create_texture(GpuTextureDescriptor {
547            kind: GpuTextureKind::Rectangle { width, height },
548            // Final scene frame is in standard sRGB space.
549            pixel_kind: PixelKind::RGBA8,
550            ..Default::default()
551        })?;
552
553        let ldr_temp_framebuffer = server.create_frame_buffer(
554            Some(Attachment {
555                kind: AttachmentKind::DepthStencil,
556                texture: depth_stencil,
557            }),
558            vec![Attachment {
559                kind: AttachmentKind::Color,
560                texture: ldr_temp_texture,
561            }],
562        )?;
563
564        Ok(Self {
565            gbuffer: GBuffer::new(server, width, height)?,
566            hdr_renderer: HighDynamicRangeRenderer::new(server)?,
567            bloom_renderer: BloomRenderer::new(server, width, height)?,
568            hdr_scene_framebuffer,
569            ldr_scene_framebuffer,
570            ldr_temp_framebuffer,
571            statistics: Default::default(),
572        })
573    }
574
575    fn copy_depth_stencil_to_scene_framebuffer(&mut self) {
576        self.gbuffer.framebuffer().blit_to(
577            &*self.hdr_scene_framebuffer,
578            0,
579            0,
580            self.gbuffer.width,
581            self.gbuffer.height,
582            0,
583            0,
584            self.gbuffer.width,
585            self.gbuffer.height,
586            false,
587            true,
588            true,
589        );
590    }
591
592    /// Returns high-dynamic range frame buffer texture.
593    pub fn hdr_scene_frame_texture(&self) -> Rc<RefCell<dyn GpuTexture>> {
594        self.hdr_scene_framebuffer.color_attachments()[0]
595            .texture
596            .clone()
597    }
598
599    /// Returns low-dynamic range frame buffer texture (final frame).
600    pub fn ldr_scene_frame_texture(&self) -> Rc<RefCell<dyn GpuTexture>> {
601        self.ldr_scene_framebuffer.color_attachments()[0]
602            .texture
603            .clone()
604    }
605
606    /// Returns low-dynamic range frame buffer texture (accumulation frame).
607    pub fn ldr_temp_frame_texture(&self) -> Rc<RefCell<dyn GpuTexture>> {
608        self.ldr_temp_framebuffer.color_attachments()[0]
609            .texture
610            .clone()
611    }
612}
613
614/// Creates a view-projection matrix that projects unit quad a screen with the specified viewport.
615pub fn make_viewport_matrix(viewport: Rect<i32>) -> Matrix4<f32> {
616    Matrix4::new_orthographic(
617        0.0,
618        viewport.w() as f32,
619        viewport.h() as f32,
620        0.0,
621        -1.0,
622        1.0,
623    ) * Matrix4::new_nonuniform_scaling(&Vector3::new(
624        viewport.w() as f32,
625        viewport.h() as f32,
626        0.0,
627    ))
628}
629
630/// A set of textures of certain kinds that could be used as a stub in cases when you don't have
631/// your own texture of this kind.
632pub struct FallbackResources {
633    /// White, one pixel, texture which will be used as stub when rendering something without
634    /// a texture specified.
635    pub white_dummy: Rc<RefCell<dyn GpuTexture>>,
636    /// Black, one pixel, texture.
637    pub black_dummy: Rc<RefCell<dyn GpuTexture>>,
638    /// A cube map with 6 textures of 1x1 black pixel in size.
639    pub environment_dummy: Rc<RefCell<dyn GpuTexture>>,
640    /// One pixel texture with (0, 1, 0) vector is used as stub when rendering something without a
641    /// normal map.
642    pub normal_dummy: Rc<RefCell<dyn GpuTexture>>,
643    /// One pixel texture used as stub when rendering something without a  metallic texture. Default
644    /// metalness is 0.0
645    pub metallic_dummy: Rc<RefCell<dyn GpuTexture>>,
646    /// One pixel volume texture.
647    pub volume_dummy: Rc<RefCell<dyn GpuTexture>>,
648    /// A stub uniform buffer for situation when there's no actual bone matrices.
649    pub bone_matrices_stub_uniform_buffer: Box<dyn Buffer>,
650}
651
652impl FallbackResources {
653    /// Picks a texture that corresponds to the actual value of the given sampler fallback.
654    pub fn sampler_fallback(
655        &self,
656        sampler_fallback: SamplerFallback,
657    ) -> &Rc<RefCell<dyn GpuTexture>> {
658        match sampler_fallback {
659            SamplerFallback::White => &self.white_dummy,
660            SamplerFallback::Normal => &self.normal_dummy,
661            SamplerFallback::Black => &self.black_dummy,
662            SamplerFallback::Volume => &self.volume_dummy,
663        }
664    }
665}
666
667/// See module docs.
668pub struct Renderer {
669    backbuffer: Box<dyn FrameBuffer>,
670    scene_render_passes: Vec<Rc<RefCell<dyn SceneRenderPass>>>,
671    deferred_light_renderer: DeferredLightRenderer,
672    flat_shader: FlatShader,
673    /// A set of textures of certain kinds that could be used as a stub in cases when you don't have
674    /// your own texture of this kind.
675    pub fallback_resources: FallbackResources,
676    /// User interface renderer.
677    pub ui_renderer: UiRenderer,
678    statistics: Statistics,
679    quad: Box<dyn GeometryBuffer>,
680    frame_size: (u32, u32),
681    quality_settings: QualitySettings,
682    /// Debug renderer instance can be used for debugging purposes
683    pub debug_renderer: DebugRenderer,
684    /// Screen space debug renderer instance can be used for debugging purposes to draw lines directly
685    /// on screen. It is useful to debug some rendering algorithms.
686    pub screen_space_debug_renderer: DebugRenderer,
687    /// A set of associated data for each scene that was rendered.
688    pub scene_data_map: FxHashMap<Handle<Scene>, AssociatedSceneData>,
689    backbuffer_clear_color: Color,
690    /// Texture cache with GPU textures.
691    pub texture_cache: TextureCache,
692    /// Uniform buffer cache.
693    pub uniform_buffer_cache: UniformBufferCache,
694    shader_cache: ShaderCache,
695    geometry_cache: GeometryCache,
696    forward_renderer: ForwardRenderer,
697    fxaa_renderer: FxaaRenderer,
698    texture_event_receiver: Receiver<ResourceEvent>,
699    shader_event_receiver: Receiver<ResourceEvent>,
700    // TextureId -> FrameBuffer mapping. This mapping is used for temporal frame buffers
701    // like ones used to render UI instances.
702    ui_frame_buffers: FxHashMap<u64, Box<dyn FrameBuffer>>,
703    uniform_memory_allocator: UniformMemoryAllocator,
704    /// Visibility cache based on occlusion query.
705    pub visibility_cache: VisibilityCache,
706    /// Graphics server.
707    pub server: SharedGraphicsServer,
708}
709
710fn make_ui_frame_buffer(
711    frame_size: Vector2<f32>,
712    server: &dyn GraphicsServer,
713    pixel_kind: PixelKind,
714) -> Result<Box<dyn FrameBuffer>, FrameworkError> {
715    let color_texture = server.create_texture(GpuTextureDescriptor {
716        kind: GpuTextureKind::Rectangle {
717            width: frame_size.x as usize,
718            height: frame_size.y as usize,
719        },
720        pixel_kind,
721        ..Default::default()
722    })?;
723
724    let depth_stencil = server.create_2d_render_target(
725        PixelKind::D24S8,
726        frame_size.x as usize,
727        frame_size.y as usize,
728    )?;
729
730    server.create_frame_buffer(
731        Some(Attachment {
732            kind: AttachmentKind::DepthStencil,
733            texture: depth_stencil,
734        }),
735        vec![Attachment {
736            kind: AttachmentKind::Color,
737            texture: color_texture,
738        }],
739    )
740}
741
742/// A context for custom scene render passes.
743pub struct SceneRenderPassContext<'a, 'b> {
744    /// Amount of time (in seconds) that passed from creation of the engine. Keep in mind, that
745    /// this value is **not** guaranteed to match real time. A user can change delta time with
746    /// which the engine "ticks" and this delta time affects elapsed time.
747    pub elapsed_time: f32,
748    /// A graphics server that is used as a wrapper to underlying graphics API.
749    pub server: &'a dyn GraphicsServer,
750
751    /// A texture cache that uploads engine's `Texture` as internal `GpuTexture` to GPU.
752    /// Use this to get a corresponding GPU texture by an instance of a `Texture`.
753    pub texture_cache: &'a mut TextureCache,
754
755    /// A geometry cache that uploads engine's `SurfaceData` as internal `GeometryBuffer` to GPU.
756    /// Use this to get a corresponding GPU geometry buffer (essentially it is just a VAO) by an
757    /// instance of a `SurfaceData`.
758    pub geometry_cache: &'a mut GeometryCache,
759
760    /// A cache that stores all native shaders associated with a shader resource. You can use it
761    /// to get a ready-to-use set of shaders for your shader resource, which could be obtained
762    /// from a material.
763    pub shader_cache: &'a mut ShaderCache,
764
765    /// A storage that contains "pre-compiled" groups of render data (batches).
766    pub bundle_storage: &'a RenderDataBundleStorage,
767
768    /// Current quality settings of the renderer.
769    pub quality_settings: &'a QualitySettings,
770
771    /// Current framebuffer to which scene is being rendered to.
772    pub framebuffer: &'a mut dyn FrameBuffer,
773
774    /// A scene being rendered.
775    pub scene: &'b Scene,
776
777    /// A camera from the scene that is used as "eyes".
778    pub camera: &'b Camera,
779
780    /// A viewport of the camera.
781    pub viewport: Rect<i32>,
782
783    /// A handle of the scene being rendered.
784    pub scene_handle: Handle<Scene>,
785
786    /// A set of textures of certain kinds that could be used as a stub in cases when you don't have
787    /// your own texture of this kind.
788    pub fallback_resources: &'a FallbackResources,
789
790    /// A texture with depth values from G-Buffer.
791    ///
792    /// # Important notes
793    ///
794    /// Keep in mind that G-Buffer cannot be modified in custom render passes, so you don't
795    /// have an ability to write to this texture. However, you can still write to depth of
796    /// the frame buffer as you'd normally do.
797    pub depth_texture: Rc<RefCell<dyn GpuTexture>>,
798
799    /// A texture with world-space normals from G-Buffer.
800    ///
801    /// # Important notes
802    ///
803    /// Keep in mind that G-Buffer cannot be modified in custom render passes, so you don't
804    /// have an ability to write to this texture.
805    pub normal_texture: Rc<RefCell<dyn GpuTexture>>,
806
807    /// A texture with ambient lighting values from G-Buffer.
808    ///
809    /// # Important notes
810    ///
811    /// Keep in mind that G-Buffer cannot be modified in custom render passes, so you don't
812    /// have an ability to write to this texture.
813    pub ambient_texture: Rc<RefCell<dyn GpuTexture>>,
814
815    /// User interface renderer.
816    pub ui_renderer: &'a mut UiRenderer,
817
818    /// A cache of uniform buffers.
819    pub uniform_buffer_cache: &'a mut UniformBufferCache,
820
821    /// Memory allocator for uniform buffers that tries to pack uniforms densely into large uniform
822    /// buffers, giving you offsets to the data.
823    pub uniform_memory_allocator: &'a mut UniformMemoryAllocator,
824}
825
826/// A trait for custom scene rendering pass. It could be used to add your own rendering techniques.
827pub trait SceneRenderPass {
828    /// Renders scene into high dynamic range target. It will be called for **each** scene
829    /// registered in the engine, but you are able to filter out scene by its handle.
830    fn on_hdr_render(
831        &mut self,
832        _ctx: SceneRenderPassContext,
833    ) -> Result<RenderPassStatistics, FrameworkError> {
834        Ok(RenderPassStatistics::default())
835    }
836
837    /// Renders scene into low dynamic range target. It will be called for **each** scene
838    /// registered in the engine, but you are able to filter out scene by its handle.
839    fn on_ldr_render(
840        &mut self,
841        _ctx: SceneRenderPassContext,
842    ) -> Result<RenderPassStatistics, FrameworkError> {
843        Ok(RenderPassStatistics::default())
844    }
845
846    /// Should return type id of a plugin, that holds this render pass. **WARNING:** Setting incorrect
847    /// (anything else, than a real plugin's type id) value here will result in hard crash with happy
848    /// debugging times.
849    fn source_type_id(&self) -> TypeId;
850}
851
852fn blit_pixels(
853    uniform_buffer_cache: &mut UniformBufferCache,
854    framebuffer: &mut dyn FrameBuffer,
855    texture: Rc<RefCell<dyn GpuTexture>>,
856    shader: &FlatShader,
857    viewport: Rect<i32>,
858    quad: &dyn GeometryBuffer,
859) -> Result<DrawCallStatistics, FrameworkError> {
860    let matrix = make_viewport_matrix(viewport);
861    let uniform_buffer =
862        uniform_buffer_cache.write(StaticUniformBuffer::<256>::new().with(&matrix))?;
863    framebuffer.draw(
864        quad,
865        viewport,
866        &*shader.program,
867        &DrawParameters {
868            cull_face: None,
869            color_write: Default::default(),
870            depth_write: true,
871            stencil_test: None,
872            depth_test: None,
873            blend: None,
874            stencil_op: Default::default(),
875            scissor_box: None,
876        },
877        &[ResourceBindGroup {
878            bindings: &[
879                ResourceBinding::texture(&texture, &shader.diffuse_texture),
880                ResourceBinding::Buffer {
881                    buffer: uniform_buffer,
882                    binding: BufferLocation::Auto {
883                        shader_location: shader.uniform_buffer_binding,
884                    },
885                    data_usage: Default::default(),
886                },
887            ],
888        }],
889        ElementRange::Full,
890    )
891}
892
893#[allow(missing_docs)] // TODO
894pub struct LightData<const N: usize = 16> {
895    pub count: usize,
896    pub color_radius: [Vector4<f32>; N],
897    pub position: [Vector3<f32>; N],
898    pub direction: [Vector3<f32>; N],
899    pub parameters: [Vector2<f32>; N],
900}
901
902impl<const N: usize> Default for LightData<N> {
903    fn default() -> Self {
904        Self {
905            count: 0,
906            color_radius: [Default::default(); N],
907            position: [Default::default(); N],
908            direction: [Default::default(); N],
909            parameters: [Default::default(); N],
910        }
911    }
912}
913
914impl Renderer {
915    /// Creates a new renderer with the given graphics server.
916    pub fn new(
917        server: Rc<dyn GraphicsServer>,
918        frame_size: (u32, u32),
919        resource_manager: &ResourceManager,
920    ) -> Result<Self, EngineError> {
921        let settings = QualitySettings::default();
922
923        let (texture_event_sender, texture_event_receiver) = std::sync::mpsc::channel();
924
925        resource_manager
926            .state()
927            .event_broadcaster
928            .add(texture_event_sender);
929
930        let (shader_event_sender, shader_event_receiver) = std::sync::mpsc::channel();
931
932        resource_manager
933            .state()
934            .event_broadcaster
935            .add(shader_event_sender);
936
937        let caps = server.capabilities();
938        Log::info(format!("Graphics Server Capabilities\n{caps:?}",));
939
940        let shader_cache = ShaderCache::default();
941
942        let one_megabyte = 1024 * 1024;
943        let uniform_memory_allocator = UniformMemoryAllocator::new(
944            // Clamp max uniform block size from the upper bound, to prevent allocating huge
945            // uniform buffers when GPU supports it. Some AMD GPUs are able to allocate ~500 Mb
946            // uniform buffers, which will lead to ridiculous VRAM consumption.
947            caps.max_uniform_block_size.min(one_megabyte),
948            caps.uniform_buffer_offset_alignment,
949        );
950
951        let fallback_resources = FallbackResources {
952            white_dummy: server.create_texture(GpuTextureDescriptor {
953                kind: GpuTextureKind::Rectangle {
954                    width: 1,
955                    height: 1,
956                },
957                pixel_kind: PixelKind::RGBA8,
958                data: Some(&[255u8, 255u8, 255u8, 255u8]),
959                ..Default::default()
960            })?,
961            black_dummy: server.create_texture(GpuTextureDescriptor {
962                kind: GpuTextureKind::Rectangle {
963                    width: 1,
964                    height: 1,
965                },
966                pixel_kind: PixelKind::RGBA8,
967                data: Some(&[0u8, 0u8, 0u8, 255u8]),
968                ..Default::default()
969            })?,
970            environment_dummy: server.create_texture(GpuTextureDescriptor {
971                kind: GpuTextureKind::Cube {
972                    width: 1,
973                    height: 1,
974                },
975                pixel_kind: PixelKind::RGBA8,
976                data: Some(&[
977                    0u8, 0u8, 0u8, 255u8, // pos-x
978                    0u8, 0u8, 0u8, 255u8, // neg-x
979                    0u8, 0u8, 0u8, 255u8, // pos-y
980                    0u8, 0u8, 0u8, 255u8, // neg-y
981                    0u8, 0u8, 0u8, 255u8, // pos-z
982                    0u8, 0u8, 0u8, 255u8, // neg-z
983                ]),
984                ..Default::default()
985            })?,
986            normal_dummy: server.create_texture(GpuTextureDescriptor {
987                kind: GpuTextureKind::Rectangle {
988                    width: 1,
989                    height: 1,
990                },
991                pixel_kind: PixelKind::RGBA8,
992                data: Some(&[128u8, 128u8, 255u8, 255u8]),
993                ..Default::default()
994            })?,
995            metallic_dummy: server.create_texture(GpuTextureDescriptor {
996                kind: GpuTextureKind::Rectangle {
997                    width: 1,
998                    height: 1,
999                },
1000                pixel_kind: PixelKind::RGBA8,
1001                data: Some(&[0u8, 0u8, 0u8, 0u8]),
1002                ..Default::default()
1003            })?,
1004            volume_dummy: server.create_texture(GpuTextureDescriptor {
1005                kind: GpuTextureKind::Volume {
1006                    width: 1,
1007                    height: 1,
1008                    depth: 1,
1009                },
1010                pixel_kind: PixelKind::RGBA8,
1011                data: Some(&[0u8, 0u8, 0u8, 0u8]),
1012                ..Default::default()
1013            })?,
1014            bone_matrices_stub_uniform_buffer: {
1015                let buffer = server.create_buffer(
1016                    ShaderDefinition::MAX_BONE_MATRICES * size_of::<Matrix4<f32>>(),
1017                    BufferKind::Uniform,
1018                    BufferUsage::StaticDraw,
1019                )?;
1020                const SIZE: usize = ShaderDefinition::MAX_BONE_MATRICES * size_of::<Matrix4<f32>>();
1021                let zeros = [0.0; SIZE];
1022                buffer.write_data(array_as_u8_slice(&zeros))?;
1023                buffer
1024            },
1025        };
1026
1027        Ok(Self {
1028            backbuffer: server.back_buffer(),
1029            frame_size,
1030            deferred_light_renderer: DeferredLightRenderer::new(&*server, frame_size, &settings)?,
1031            flat_shader: FlatShader::new(&*server)?,
1032            fallback_resources,
1033            quad: <dyn GeometryBuffer>::from_surface_data(
1034                &SurfaceData::make_unit_xy_quad(),
1035                BufferUsage::StaticDraw,
1036                &*server,
1037            )?,
1038
1039            ui_renderer: UiRenderer::new(&*server)?,
1040            quality_settings: settings,
1041            debug_renderer: DebugRenderer::new(&*server)?,
1042            screen_space_debug_renderer: DebugRenderer::new(&*server)?,
1043            scene_data_map: Default::default(),
1044            backbuffer_clear_color: Color::BLACK,
1045            texture_cache: Default::default(),
1046            geometry_cache: Default::default(),
1047            forward_renderer: ForwardRenderer::new(),
1048            ui_frame_buffers: Default::default(),
1049            fxaa_renderer: FxaaRenderer::new(&*server)?,
1050            statistics: Statistics::default(),
1051            shader_event_receiver,
1052            texture_event_receiver,
1053            shader_cache,
1054            scene_render_passes: Default::default(),
1055            uniform_buffer_cache: UniformBufferCache::new(server.clone()),
1056            server,
1057            visibility_cache: Default::default(),
1058            uniform_memory_allocator,
1059        })
1060    }
1061
1062    /// Adds a custom render pass.
1063    pub fn add_render_pass(&mut self, pass: Rc<RefCell<dyn SceneRenderPass>>) {
1064        self.scene_render_passes.push(pass);
1065    }
1066
1067    /// Removes specified render pass.
1068    pub fn remove_render_pass(&mut self, pass: Rc<RefCell<dyn SceneRenderPass>>) {
1069        if let Some(index) = self
1070            .scene_render_passes
1071            .iter()
1072            .position(|p| Rc::ptr_eq(p, &pass))
1073        {
1074            self.scene_render_passes.remove(index);
1075        }
1076    }
1077
1078    /// Returns a slice with every registered render passes.
1079    pub fn render_passes(&self) -> &[Rc<RefCell<dyn SceneRenderPass>>] {
1080        &self.scene_render_passes
1081    }
1082
1083    /// Removes all render passes from the renderer.
1084    pub fn clear_render_passes(&mut self) {
1085        self.scene_render_passes.clear()
1086    }
1087
1088    /// Returns statistics for last frame.
1089    pub fn get_statistics(&self) -> Statistics {
1090        self.statistics
1091    }
1092
1093    /// Unloads texture from GPU memory.
1094    pub fn unload_texture(&mut self, texture: TextureResource) {
1095        self.texture_cache.unload(texture)
1096    }
1097
1098    /// Sets color which will be used to fill screen when there is nothing to render.
1099    pub fn set_backbuffer_clear_color(&mut self, color: Color) {
1100        self.backbuffer_clear_color = color;
1101    }
1102
1103    /// Returns a reference to current graphics server.
1104    pub fn graphics_server(&self) -> &dyn GraphicsServer {
1105        &*self.server
1106    }
1107
1108    /// Sets new frame size. You should call the same method on [`crate::engine::Engine`]
1109    /// instead, which will update the size for the user interface and rendering context
1110    /// as well as this one.
1111    ///
1112    /// # Notes
1113    ///
1114    /// Input values will be set to 1 pixel if new size is 0. Rendering cannot
1115    /// be performed into 0x0 texture.
1116    pub(crate) fn set_frame_size(&mut self, new_size: (u32, u32)) -> Result<(), FrameworkError> {
1117        self.frame_size.0 = new_size.0.max(1);
1118        self.frame_size.1 = new_size.1.max(1);
1119
1120        self.deferred_light_renderer
1121            .set_frame_size(&*self.server, new_size)?;
1122
1123        self.graphics_server().set_frame_size(new_size);
1124
1125        Ok(())
1126    }
1127
1128    /// Returns current (width, height) pair of back buffer size.
1129    pub fn get_frame_size(&self) -> (u32, u32) {
1130        self.frame_size
1131    }
1132
1133    /// Returns current bounds of back buffer.
1134    pub fn get_frame_bounds(&self) -> Vector2<f32> {
1135        Vector2::new(self.frame_size.0 as f32, self.frame_size.1 as f32)
1136    }
1137
1138    /// Sets new quality settings for renderer. Never call this method in a loop, otherwise
1139    /// you may get **significant** lags. Always check if current quality setting differs
1140    /// from new!
1141    pub fn set_quality_settings(
1142        &mut self,
1143        settings: &QualitySettings,
1144    ) -> Result<(), FrameworkError> {
1145        self.quality_settings = *settings;
1146        self.deferred_light_renderer
1147            .set_quality_settings(&*self.server, settings)
1148    }
1149
1150    /// Returns current quality settings.
1151    pub fn get_quality_settings(&self) -> QualitySettings {
1152        self.quality_settings
1153    }
1154
1155    /// Removes all cached GPU data, forces renderer to re-upload data to GPU.
1156    /// Do not call this method until you absolutely need! It may cause **significant**
1157    /// performance lag!
1158    pub fn flush(&mut self) {
1159        self.texture_cache.clear();
1160        self.geometry_cache.clear();
1161    }
1162
1163    /// Renders given UI into specified render target. This method is especially useful if you need
1164    /// to have off-screen UIs (like interactive touch-screen in Doom 3, Dead Space, etc).
1165    pub fn render_ui_to_texture(
1166        &mut self,
1167        render_target: TextureResource,
1168        screen_size: Vector2<f32>,
1169        drawing_context: &DrawingContext,
1170        clear_color: Color,
1171        pixel_kind: PixelKind,
1172    ) -> Result<(), FrameworkError> {
1173        let new_width = screen_size.x as usize;
1174        let new_height = screen_size.y as usize;
1175
1176        // Create or reuse existing frame buffer.
1177        let frame_buffer = match self.ui_frame_buffers.entry(render_target.key()) {
1178            Entry::Occupied(entry) => {
1179                let frame_buffer = entry.into_mut();
1180                let frame = frame_buffer.color_attachments().first().unwrap();
1181                let color_texture_kind = frame.texture.borrow().kind();
1182                if let GpuTextureKind::Rectangle { width, height } = color_texture_kind {
1183                    if width != new_width
1184                        || height != new_height
1185                        || frame.texture.borrow().pixel_kind() != pixel_kind
1186                    {
1187                        *frame_buffer =
1188                            make_ui_frame_buffer(screen_size, &*self.server, pixel_kind)?;
1189                    }
1190                } else {
1191                    panic!("ui can be rendered only in rectangle texture!")
1192                }
1193                frame_buffer
1194            }
1195            Entry::Vacant(entry) => entry.insert(make_ui_frame_buffer(
1196                screen_size,
1197                &*self.server,
1198                pixel_kind,
1199            )?),
1200        };
1201        let frame_buffer = &mut **frame_buffer;
1202
1203        let viewport = Rect::new(0, 0, new_width as i32, new_height as i32);
1204
1205        frame_buffer.clear(viewport, Some(clear_color), Some(0.0), Some(0));
1206
1207        self.statistics += self.ui_renderer.render(UiRenderContext {
1208            server: &*self.server,
1209            viewport,
1210            frame_buffer,
1211            frame_width: screen_size.x,
1212            frame_height: screen_size.y,
1213            drawing_context,
1214            fallback_resources: &self.fallback_resources,
1215            texture_cache: &mut self.texture_cache,
1216            uniform_buffer_cache: &mut self.uniform_buffer_cache,
1217            flat_shader: &self.flat_shader,
1218        })?;
1219
1220        // Finally register texture in the cache so it will become available as texture in deferred/forward
1221        // renderer.
1222        self.texture_cache.try_register(
1223            &render_target,
1224            frame_buffer
1225                .color_attachments()
1226                .first()
1227                .unwrap()
1228                .texture
1229                .clone(),
1230        );
1231
1232        Ok(())
1233    }
1234
1235    fn update_texture_cache(&mut self, dt: f32) {
1236        // Maximum amount of textures uploaded to GPU per frame. This defines throughput **only** for
1237        // requests from resource manager. This is needed to prevent huge lag when there are tons of
1238        // requests, so this is some kind of work load balancer.
1239        const THROUGHPUT: usize = 5;
1240
1241        let mut uploaded = 0;
1242        while let Ok(event) = self.texture_event_receiver.try_recv() {
1243            if let ResourceEvent::Loaded(resource) | ResourceEvent::Reloaded(resource) = event {
1244                if let Some(texture) = resource.try_cast::<Texture>() {
1245                    match self.texture_cache.upload(&*self.server, &texture) {
1246                        Ok(_) => {
1247                            uploaded += 1;
1248                            if uploaded >= THROUGHPUT {
1249                                break;
1250                            }
1251                        }
1252                        Err(e) => {
1253                            Log::writeln(
1254                                MessageKind::Error,
1255                                format!("Failed to upload texture to GPU. Reason: {e:?}"),
1256                            );
1257                        }
1258                    }
1259                }
1260            }
1261        }
1262
1263        self.texture_cache.update(dt);
1264    }
1265
1266    fn update_shader_cache(&mut self, dt: f32) {
1267        while let Ok(event) = self.shader_event_receiver.try_recv() {
1268            if let ResourceEvent::Loaded(resource) | ResourceEvent::Reloaded(resource) = event {
1269                if let Some(shader) = resource.try_cast::<Shader>() {
1270                    // Remove and immediately "touch" the shader cache to force upload shader.
1271                    self.shader_cache.remove(&shader);
1272                    let _ = self.shader_cache.get(&*self.server, &shader);
1273                }
1274            }
1275        }
1276
1277        self.shader_cache.update(dt)
1278    }
1279
1280    /// Update caches - this will remove timed out resources.
1281    ///
1282    /// Normally, this is called from `Engine::update()`.
1283    /// You should only call this manually if you don't use that method.
1284    pub fn update_caches(&mut self, dt: f32) {
1285        self.update_texture_cache(dt);
1286        self.update_shader_cache(dt);
1287        self.geometry_cache.update(dt);
1288    }
1289
1290    /// Unconditionally renders a scene and returns a reference to a [`AssociatedSceneData`] instance
1291    /// that contains rendered data (including intermediate data, such as G-Buffer content, etc.).
1292    pub fn render_scene(
1293        &mut self,
1294        scene_handle: Handle<Scene>,
1295        scene: &Scene,
1296        elapsed_time: f32,
1297        dt: f32,
1298    ) -> Result<&AssociatedSceneData, FrameworkError> {
1299        let graph = &scene.graph;
1300
1301        let backbuffer_width = self.frame_size.0 as f32;
1302        let backbuffer_height = self.frame_size.1 as f32;
1303
1304        let window_viewport = Rect::new(0, 0, self.frame_size.0 as i32, self.frame_size.1 as i32);
1305
1306        let frame_size = scene
1307            .rendering_options
1308            .render_target
1309            .as_ref()
1310            .map_or_else(
1311                // Use either backbuffer size
1312                || Vector2::new(backbuffer_width, backbuffer_height),
1313                // Or framebuffer size
1314                |rt| {
1315                    if let TextureKind::Rectangle { width, height } = rt.data_ref().kind() {
1316                        Vector2::new(width as f32, height as f32)
1317                    } else {
1318                        panic!("only rectangle textures can be used as render target!")
1319                    }
1320                },
1321            )
1322            // Clamp to [1.0; infinity] range.
1323            .sup(&Vector2::new(1.0, 1.0));
1324
1325        let server = &*self.server;
1326
1327        let scene_associated_data = self
1328            .scene_data_map
1329            .entry(scene_handle)
1330            .and_modify(|data| {
1331                if data.gbuffer.width != frame_size.x as i32
1332                    || data.gbuffer.height != frame_size.y as i32
1333                {
1334                    let width = frame_size.x as usize;
1335                    let height = frame_size.y as usize;
1336
1337                    Log::info(format!(
1338                        "Associated scene rendering data was re-created for scene {}, because render frame size was changed. Old is {}x{}, new {}x{}!",
1339                        scene_handle,
1340                        data.gbuffer.width,data.gbuffer.height,width,height
1341                    ));
1342
1343                    *data = AssociatedSceneData::new(server, width, height).unwrap();
1344                }
1345            })
1346            .or_insert_with(|| {
1347                let width = frame_size.x as usize;
1348                let height = frame_size.y as usize;
1349
1350                Log::info(format!(
1351                    "A new associated scene rendering data was created for scene {scene_handle}!"
1352                ));
1353
1354                AssociatedSceneData::new(server, width, height).unwrap()
1355            });
1356
1357        let pipeline_stats = server.pipeline_statistics();
1358        scene_associated_data.statistics = Default::default();
1359
1360        // If we specified a texture to draw to, we have to register it in texture cache
1361        // so it can be used in later on as texture. This is useful in case if you need
1362        // to draw something on offscreen and then draw it on some mesh.
1363        if let Some(rt) = scene.rendering_options.render_target.clone() {
1364            self.texture_cache
1365                .try_register(&rt, scene_associated_data.ldr_scene_frame_texture());
1366        }
1367
1368        for (camera_handle, camera) in graph.pair_iter().filter_map(|(handle, node)| {
1369            if node.is_globally_enabled() {
1370                if let Some(camera) = node.cast::<Camera>() {
1371                    if camera.is_enabled() {
1372                        return Some((handle, camera));
1373                    }
1374                }
1375            }
1376            None
1377        }) {
1378            let visibility_cache = self.visibility_cache.get_or_register(graph, camera_handle);
1379
1380            let viewport = camera.viewport_pixels(frame_size);
1381
1382            let bundle_storage = RenderDataBundleStorage::from_graph(
1383                graph,
1384                elapsed_time,
1385                ObserverInfo {
1386                    observer_position: camera.global_position(),
1387                    z_near: camera.projection().z_near(),
1388                    z_far: camera.projection().z_far(),
1389                    view_matrix: camera.view_matrix(),
1390                    projection_matrix: camera.projection_matrix(),
1391                },
1392                GBUFFER_PASS_NAME.clone(),
1393                RenderDataBundleStorageOptions {
1394                    collect_lights: true,
1395                },
1396            );
1397
1398            server.set_polygon_fill_mode(
1399                PolygonFace::FrontAndBack,
1400                scene.rendering_options.polygon_rasterization_mode,
1401            );
1402
1403            scene_associated_data.statistics +=
1404                scene_associated_data.gbuffer.fill(GBufferRenderContext {
1405                    server,
1406                    camera,
1407                    geom_cache: &mut self.geometry_cache,
1408                    bundle_storage: &bundle_storage,
1409                    texture_cache: &mut self.texture_cache,
1410                    shader_cache: &mut self.shader_cache,
1411                    quality_settings: &self.quality_settings,
1412                    fallback_resources: &self.fallback_resources,
1413                    graph,
1414                    uniform_buffer_cache: &mut self.uniform_buffer_cache,
1415                    uniform_memory_allocator: &mut self.uniform_memory_allocator,
1416                    screen_space_debug_renderer: &mut self.screen_space_debug_renderer,
1417                    unit_quad: &*self.quad,
1418                })?;
1419
1420            server.set_polygon_fill_mode(PolygonFace::FrontAndBack, PolygonFillMode::Fill);
1421
1422            scene_associated_data.copy_depth_stencil_to_scene_framebuffer();
1423
1424            scene_associated_data.hdr_scene_framebuffer.clear(
1425                viewport,
1426                Some(
1427                    scene
1428                        .rendering_options
1429                        .clear_color
1430                        .unwrap_or(self.backbuffer_clear_color),
1431                ),
1432                None, // Keep depth, we've just copied valid data in it.
1433                Some(0),
1434            );
1435
1436            let (pass_stats, light_stats) =
1437                self.deferred_light_renderer
1438                    .render(DeferredRendererContext {
1439                        elapsed_time,
1440                        server,
1441                        scene,
1442                        camera,
1443                        gbuffer: &mut scene_associated_data.gbuffer,
1444                        ambient_color: scene.rendering_options.ambient_lighting_color,
1445                        render_data_bundle: &bundle_storage,
1446                        settings: &self.quality_settings,
1447                        textures: &mut self.texture_cache,
1448                        geometry_cache: &mut self.geometry_cache,
1449                        frame_buffer: &mut *scene_associated_data.hdr_scene_framebuffer,
1450                        shader_cache: &mut self.shader_cache,
1451                        fallback_resources: &self.fallback_resources,
1452                        uniform_buffer_cache: &mut self.uniform_buffer_cache,
1453                        visibility_cache,
1454                        uniform_memory_allocator: &mut self.uniform_memory_allocator,
1455                    })?;
1456
1457            scene_associated_data.statistics += light_stats;
1458            scene_associated_data.statistics += pass_stats;
1459
1460            let depth = scene_associated_data.gbuffer.depth();
1461
1462            scene_associated_data.statistics +=
1463                self.forward_renderer.render(ForwardRenderContext {
1464                    state: server,
1465                    geom_cache: &mut self.geometry_cache,
1466                    texture_cache: &mut self.texture_cache,
1467                    shader_cache: &mut self.shader_cache,
1468                    bundle_storage: &bundle_storage,
1469                    framebuffer: &mut *scene_associated_data.hdr_scene_framebuffer,
1470                    viewport,
1471                    quality_settings: &self.quality_settings,
1472                    fallback_resources: &self.fallback_resources,
1473                    scene_depth: depth,
1474                    ambient_light: scene.rendering_options.ambient_lighting_color,
1475                    uniform_memory_allocator: &mut self.uniform_memory_allocator,
1476                })?;
1477
1478            for render_pass in self.scene_render_passes.iter() {
1479                scene_associated_data.statistics +=
1480                    render_pass
1481                        .borrow_mut()
1482                        .on_hdr_render(SceneRenderPassContext {
1483                            elapsed_time,
1484                            server,
1485                            texture_cache: &mut self.texture_cache,
1486                            geometry_cache: &mut self.geometry_cache,
1487                            shader_cache: &mut self.shader_cache,
1488                            quality_settings: &self.quality_settings,
1489                            bundle_storage: &bundle_storage,
1490                            viewport,
1491                            scene,
1492                            camera,
1493                            scene_handle,
1494                            fallback_resources: &self.fallback_resources,
1495                            depth_texture: scene_associated_data.gbuffer.depth(),
1496                            normal_texture: scene_associated_data.gbuffer.normal_texture(),
1497                            ambient_texture: scene_associated_data.gbuffer.ambient_texture(),
1498                            framebuffer: &mut *scene_associated_data.hdr_scene_framebuffer,
1499                            ui_renderer: &mut self.ui_renderer,
1500                            uniform_buffer_cache: &mut self.uniform_buffer_cache,
1501                            uniform_memory_allocator: &mut self.uniform_memory_allocator,
1502                        })?;
1503            }
1504
1505            let quad = &self.quad;
1506
1507            // Prepare glow map.
1508            scene_associated_data.statistics += scene_associated_data.bloom_renderer.render(
1509                &**quad,
1510                scene_associated_data.hdr_scene_frame_texture(),
1511                &mut self.uniform_buffer_cache,
1512            )?;
1513
1514            // Convert high dynamic range frame to low dynamic range (sRGB) with tone mapping and gamma correction.
1515            scene_associated_data.statistics += scene_associated_data.hdr_renderer.render(
1516                server,
1517                scene_associated_data.hdr_scene_frame_texture(),
1518                scene_associated_data.bloom_renderer.result(),
1519                &mut *scene_associated_data.ldr_scene_framebuffer,
1520                viewport,
1521                &**quad,
1522                dt,
1523                camera.exposure(),
1524                camera.color_grading_lut_ref(),
1525                camera.color_grading_enabled(),
1526                &mut self.texture_cache,
1527                &mut self.uniform_buffer_cache,
1528            )?;
1529
1530            // Apply FXAA if needed.
1531            if self.quality_settings.fxaa {
1532                scene_associated_data.statistics += self.fxaa_renderer.render(
1533                    viewport,
1534                    scene_associated_data.ldr_scene_frame_texture(),
1535                    &mut *scene_associated_data.ldr_temp_framebuffer,
1536                    &mut self.uniform_buffer_cache,
1537                )?;
1538
1539                let quad = &self.quad;
1540                let temp_frame_texture = scene_associated_data.ldr_temp_frame_texture();
1541                scene_associated_data.statistics += blit_pixels(
1542                    &mut self.uniform_buffer_cache,
1543                    &mut *scene_associated_data.ldr_scene_framebuffer,
1544                    temp_frame_texture,
1545                    &self.flat_shader,
1546                    viewport,
1547                    &**quad,
1548                )?;
1549            }
1550
1551            // Render debug geometry in the LDR frame buffer.
1552            self.debug_renderer.set_lines(&scene.drawing_context.lines);
1553            scene_associated_data.statistics += self.debug_renderer.render(
1554                &mut self.uniform_buffer_cache,
1555                viewport,
1556                &mut *scene_associated_data.ldr_scene_framebuffer,
1557                camera.view_projection_matrix(),
1558            )?;
1559
1560            for render_pass in self.scene_render_passes.iter() {
1561                scene_associated_data.statistics +=
1562                    render_pass
1563                        .borrow_mut()
1564                        .on_ldr_render(SceneRenderPassContext {
1565                            elapsed_time,
1566                            server,
1567                            texture_cache: &mut self.texture_cache,
1568                            geometry_cache: &mut self.geometry_cache,
1569                            shader_cache: &mut self.shader_cache,
1570                            quality_settings: &self.quality_settings,
1571                            bundle_storage: &bundle_storage,
1572                            viewport,
1573                            scene,
1574                            camera,
1575                            scene_handle,
1576                            fallback_resources: &self.fallback_resources,
1577                            depth_texture: scene_associated_data.gbuffer.depth(),
1578                            normal_texture: scene_associated_data.gbuffer.normal_texture(),
1579                            ambient_texture: scene_associated_data.gbuffer.ambient_texture(),
1580                            framebuffer: &mut *scene_associated_data.ldr_scene_framebuffer,
1581                            ui_renderer: &mut self.ui_renderer,
1582                            uniform_buffer_cache: &mut self.uniform_buffer_cache,
1583                            uniform_memory_allocator: &mut self.uniform_memory_allocator,
1584                        })?;
1585            }
1586        }
1587
1588        self.visibility_cache.update(graph);
1589
1590        // Optionally render everything into back buffer.
1591        if scene.rendering_options.render_target.is_none() {
1592            let quad = &self.quad;
1593            scene_associated_data.statistics += blit_pixels(
1594                &mut self.uniform_buffer_cache,
1595                &mut *self.backbuffer,
1596                scene_associated_data.ldr_scene_frame_texture(),
1597                &self.flat_shader,
1598                window_viewport,
1599                &**quad,
1600            )?;
1601        }
1602
1603        self.statistics += scene_associated_data.statistics;
1604        scene_associated_data.statistics.pipeline = server.pipeline_statistics() - pipeline_stats;
1605
1606        Ok(scene_associated_data)
1607    }
1608
1609    fn render_frame<'a>(
1610        &mut self,
1611        scenes: &SceneContainer,
1612        elapsed_time: f32,
1613        drawing_contexts: impl Iterator<Item = &'a DrawingContext>,
1614    ) -> Result<(), FrameworkError> {
1615        if self.frame_size.0 == 0 || self.frame_size.1 == 0 {
1616            return Ok(());
1617        }
1618
1619        self.uniform_buffer_cache.mark_all_unused();
1620        self.uniform_memory_allocator.clear();
1621
1622        // Make sure to drop associated data for destroyed scenes.
1623        self.scene_data_map
1624            .retain(|h, _| scenes.is_valid_handle(*h));
1625
1626        // We have to invalidate resource bindings cache because some textures or programs,
1627        // or other GL resources can be destroyed and then on their "names" some new resource
1628        // are created, but cache still thinks that resource is correctly bound, but it is different
1629        // object have same name.
1630        self.server.invalidate_resource_bindings_cache();
1631        let dt = self.statistics.capped_frame_time;
1632        self.statistics.begin_frame();
1633
1634        let window_viewport = Rect::new(0, 0, self.frame_size.0 as i32, self.frame_size.1 as i32);
1635        self.backbuffer.clear(
1636            window_viewport,
1637            Some(self.backbuffer_clear_color),
1638            Some(1.0),
1639            Some(0),
1640        );
1641
1642        let backbuffer_width = self.frame_size.0 as f32;
1643        let backbuffer_height = self.frame_size.1 as f32;
1644
1645        for (scene_handle, scene) in scenes.pair_iter().filter(|(_, s)| *s.enabled) {
1646            self.render_scene(scene_handle, scene, elapsed_time, dt)?;
1647        }
1648
1649        self.graphics_server()
1650            .set_polygon_fill_mode(PolygonFace::FrontAndBack, PolygonFillMode::Fill);
1651
1652        // Render UI on top of everything without gamma correction.
1653        for drawing_context in drawing_contexts {
1654            self.statistics += self.ui_renderer.render(UiRenderContext {
1655                server: &*self.server,
1656                viewport: window_viewport,
1657                frame_buffer: &mut *self.backbuffer,
1658                frame_width: backbuffer_width,
1659                frame_height: backbuffer_height,
1660                drawing_context,
1661                fallback_resources: &self.fallback_resources,
1662                texture_cache: &mut self.texture_cache,
1663                uniform_buffer_cache: &mut self.uniform_buffer_cache,
1664                flat_shader: &self.flat_shader,
1665            })?;
1666        }
1667
1668        let screen_matrix =
1669            Matrix4::new_orthographic(0.0, backbuffer_width, backbuffer_height, 0.0, -1.0, 1.0);
1670        self.screen_space_debug_renderer.render(
1671            &mut self.uniform_buffer_cache,
1672            window_viewport,
1673            &mut *self.backbuffer,
1674            screen_matrix,
1675        )?;
1676
1677        self.statistics.geometry_cache_size = self.geometry_cache.alive_count();
1678        self.statistics.texture_cache_size = self.texture_cache.alive_count();
1679        self.statistics.shader_cache_size = self.shader_cache.alive_count();
1680        self.statistics.uniform_buffer_cache_size = self.uniform_buffer_cache.alive_count();
1681
1682        Ok(())
1683    }
1684
1685    pub(crate) fn render_and_swap_buffers<'a>(
1686        &mut self,
1687        scenes: &SceneContainer,
1688        elapsed_time: f32,
1689        drawing_contexts: impl Iterator<Item = &'a DrawingContext>,
1690        window: &Window,
1691    ) -> Result<(), FrameworkError> {
1692        self.render_frame(scenes, elapsed_time, drawing_contexts)?;
1693        self.statistics.end_frame();
1694        window.pre_present_notify();
1695        self.graphics_server().swap_buffers()?;
1696        self.statistics.finalize();
1697        self.statistics.pipeline = self.server.pipeline_statistics();
1698        Ok(())
1699    }
1700}