Skip to main content

fyrox_impl/renderer/
resources.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//! A set of textures of certain kinds. See [`RendererResources`] docs for more info.
22
23use crate::{
24    core::{algebra::Matrix4, array_as_u8_slice},
25    graphics::{
26        buffer::GpuBufferDescriptor,
27        buffer::{BufferKind, BufferUsage, GpuBuffer},
28        error::FrameworkError,
29        geometry_buffer::GpuGeometryBuffer,
30        gpu_program::SamplerFallback,
31        gpu_texture::{GpuTexture, GpuTextureDescriptor, GpuTextureKind, PixelKind},
32        sampler::{
33            GpuSampler, GpuSamplerDescriptor, MagnificationFilter, MinificationFilter, WrapMode,
34        },
35        server::GraphicsServer,
36    },
37    renderer::{cache::shader::RenderPassContainer, framework::GeometryBufferExt},
38    scene::mesh::surface::SurfaceData,
39};
40use fyrox_material::shader::ShaderDefinition;
41
42/// A set of standard shaders used by the engine.
43pub struct ShadersContainer {
44    /// A shader that is used to draw deferred decals.
45    pub decal: RenderPassContainer,
46    /// A spotlight shader for deferred renderer.
47    pub spot_light: RenderPassContainer,
48    /// A point light shader for deferred renderer.
49    pub point_light: RenderPassContainer,
50    /// A directional light shader for deferred renderer.
51    pub directional_light: RenderPassContainer,
52    /// A ambient light shader for deferred renderer.
53    pub ambient_light: RenderPassContainer,
54    /// A shader that is used to mark pixels affected by a light source in deferred renderer.
55    pub volume_marker_lit: RenderPassContainer,
56    /// A simple shader that is used to count pixels.
57    pub pixel_counter: RenderPassContainer,
58    /// Debug shader that is used to draw debug geometry.
59    pub debug: RenderPassContainer,
60    /// Fast approximate antialiasing shader.
61    pub fxaa: RenderPassContainer,
62    /// A shader for volumetric spotlight.
63    pub spot_light_volume: RenderPassContainer,
64    /// A shader for volumetric point light.
65    pub point_light_volume: RenderPassContainer,
66    /// A shader that is used to mark pixels affected by a light source when rendering a light
67    /// volume.
68    pub volume_marker_vol: RenderPassContainer,
69    /// A shader that packs the raw visibility buffer into an optimized version.
70    pub visibility_optimizer: RenderPassContainer,
71    /// Screen-space ambient occlusion shader.
72    pub ssao: RenderPassContainer,
73    /// A shader that is used in visibility test for occlusion culling.
74    pub visibility: RenderPassContainer,
75    /// A shader for simple image blitting.
76    pub blit: RenderPassContainer,
77    /// A shader for eye adaptation for high dynamic range rendering.
78    pub hdr_adaptation: RenderPassContainer,
79    /// A shader for frame luminance calculations for high dynamic range rendering.
80    pub hdr_luminance: RenderPassContainer,
81    /// A shader for frame luminance downscaling for high dynamic range rendering.
82    pub hdr_downscale: RenderPassContainer,
83    /// A shader for tone mapping for high dynamic range rendering.
84    pub hdr_map: RenderPassContainer,
85    /// A shader that extracts bright pixels from an image.
86    pub bloom: RenderPassContainer,
87    /// A shader that is used to render a skybox.
88    pub skybox: RenderPassContainer,
89    /// A gaussian blur shader.
90    pub gaussian_blur: RenderPassContainer,
91    /// A simple box blur shader.
92    pub box_blur: RenderPassContainer,
93    /// User interface shader.
94    pub ui: RenderPassContainer,
95    /// Environment map specular convolution shader.
96    pub environment_map_specular_convolution: RenderPassContainer,
97    /// Environment map irradiance convolution shader.
98    pub environment_map_irradiance_convolution: RenderPassContainer,
99}
100
101impl ShadersContainer {
102    /// Creates a new shaders container.
103    pub fn new(server: &dyn GraphicsServer) -> Result<Self, FrameworkError> {
104        Ok(Self {
105            decal: RenderPassContainer::from_str(server, include_str!("shaders/decal.shader"))?,
106            spot_light: RenderPassContainer::from_str(
107                server,
108                include_str!("shaders/deferred_spot_light.shader"),
109            )?,
110            point_light: RenderPassContainer::from_str(
111                server,
112                include_str!("shaders/deferred_point_light.shader"),
113            )?,
114            directional_light: RenderPassContainer::from_str(
115                server,
116                include_str!("shaders/deferred_directional_light.shader"),
117            )?,
118            ambient_light: RenderPassContainer::from_str(
119                server,
120                include_str!("shaders/ambient_light.shader"),
121            )?,
122            volume_marker_lit: RenderPassContainer::from_str(
123                server,
124                include_str!("shaders/volume_marker_lit.shader"),
125            )?,
126            pixel_counter: RenderPassContainer::from_str(
127                server,
128                include_str!("shaders/pixel_counter.shader"),
129            )?,
130            debug: RenderPassContainer::from_str(server, include_str!("shaders/debug.shader"))?,
131            fxaa: RenderPassContainer::from_str(server, include_str!("shaders/fxaa.shader"))?,
132            spot_light_volume: RenderPassContainer::from_str(
133                server,
134                include_str!("shaders/spot_volumetric.shader"),
135            )?,
136            point_light_volume: RenderPassContainer::from_str(
137                server,
138                include_str!("shaders/point_volumetric.shader"),
139            )?,
140            volume_marker_vol: RenderPassContainer::from_str(
141                server,
142                include_str!("shaders/volume_marker_vol.shader"),
143            )?,
144            visibility_optimizer: RenderPassContainer::from_str(
145                server,
146                include_str!("shaders/visibility_optimizer.shader"),
147            )?,
148            ssao: RenderPassContainer::from_str(server, include_str!("shaders/ssao.shader"))?,
149            visibility: RenderPassContainer::from_str(
150                server,
151                include_str!("shaders/visibility.shader"),
152            )?,
153            blit: RenderPassContainer::from_str(server, include_str!("shaders/blit.shader"))?,
154            hdr_adaptation: RenderPassContainer::from_str(
155                server,
156                include_str!("shaders/hdr_adaptation.shader"),
157            )?,
158            hdr_luminance: RenderPassContainer::from_str(
159                server,
160                include_str!("shaders/hdr_luminance.shader"),
161            )?,
162            hdr_downscale: RenderPassContainer::from_str(
163                server,
164                include_str!("shaders/hdr_downscale.shader"),
165            )?,
166            hdr_map: RenderPassContainer::from_str(server, include_str!("shaders/hdr_map.shader"))?,
167            bloom: RenderPassContainer::from_str(server, include_str!("shaders/bloom.shader"))?,
168            skybox: RenderPassContainer::from_str(server, include_str!("shaders/skybox.shader"))?,
169            gaussian_blur: RenderPassContainer::from_str(
170                server,
171                include_str!("shaders/gaussian_blur.shader"),
172            )?,
173            box_blur: RenderPassContainer::from_str(server, include_str!("shaders/blur.shader"))?,
174            ui: RenderPassContainer::from_str(
175                server,
176                str::from_utf8(
177                    fyrox_material::shader::STANDARD_WIDGET
178                        .data_source
179                        .as_ref()
180                        .unwrap()
181                        .bytes
182                        .as_ref(),
183                )
184                .unwrap(),
185            )?,
186            environment_map_specular_convolution: RenderPassContainer::from_str(
187                server,
188                include_str!("shaders/prefilter.shader"),
189            )?,
190            environment_map_irradiance_convolution: RenderPassContainer::from_str(
191                server,
192                include_str!("shaders/irradiance.shader"),
193            )?,
194        })
195    }
196}
197
198/// A set of textures of certain kinds that could be used as a stub in cases when you don't have
199/// your own texture of this kind.
200pub struct RendererResources {
201    /// White, one pixel, texture which will be used as stub when rendering something without
202    /// a texture specified.
203    pub white_dummy: GpuTexture,
204    /// Black, one pixel, texture.
205    pub black_dummy: GpuTexture,
206    /// A cube map with 6 textures of 1x1 black pixel in size.
207    pub environment_dummy: GpuTexture,
208    /// One pixel texture with (0, 1, 0) vector is used as stub when rendering something without a
209    /// normal map.
210    pub normal_dummy: GpuTexture,
211    /// One pixel texture used as stub when rendering something without a  metallic texture. Default
212    /// metalness is 0.0
213    pub metallic_dummy: GpuTexture,
214    /// One pixel volume texture.
215    pub volume_dummy: GpuTexture,
216    /// A stub uniform buffer for situation when there's no actual bone matrices.
217    pub bone_matrices_stub_uniform_buffer: GpuBuffer,
218    /// A sampler with the linear filtration that clamps incoming UVs to `[0;1]` range.
219    pub linear_clamp_sampler: GpuSampler,
220    /// A sampler with the linear filtration and mipmapping that clamps incoming UVs to `[0;1]` range.
221    pub linear_mipmap_linear_clamp_sampler: GpuSampler,
222    /// A sampler with the linear filtration.
223    pub linear_wrap_sampler: GpuSampler,
224    /// A sampler with the nearest filtration that clamps incoming UVs to `[0;1]` range.
225    pub nearest_clamp_sampler: GpuSampler,
226    /// A sampler with the nearest filtration.
227    pub nearest_wrap_sampler: GpuSampler,
228    /// Unit oXY-oriented quad.
229    pub quad: GpuGeometryBuffer,
230    /// Unit cube centered around the origin.
231    pub cube: GpuGeometryBuffer,
232    /// A set of standard shaders used by the engine.
233    pub shaders: ShadersContainer,
234}
235
236impl RendererResources {
237    /// Creates a new set of renderer resources.
238    pub fn new(server: &dyn GraphicsServer) -> Result<Self, FrameworkError> {
239        Ok(Self {
240            white_dummy: server.create_texture(GpuTextureDescriptor {
241                name: "WhiteDummy",
242                kind: GpuTextureKind::Rectangle {
243                    width: 1,
244                    height: 1,
245                },
246                pixel_kind: PixelKind::RGBA8,
247                data: Some(&[255u8, 255u8, 255u8, 255u8]),
248                ..Default::default()
249            })?,
250            black_dummy: server.create_texture(GpuTextureDescriptor {
251                name: "BlackDummy",
252                kind: GpuTextureKind::Rectangle {
253                    width: 1,
254                    height: 1,
255                },
256                pixel_kind: PixelKind::RGBA8,
257                data: Some(&[0u8, 0u8, 0u8, 255u8]),
258                ..Default::default()
259            })?,
260            environment_dummy: server.create_texture(GpuTextureDescriptor {
261                name: "EnvironmentDummy",
262                kind: GpuTextureKind::Cube { size: 1 },
263                pixel_kind: PixelKind::RGBA8,
264                data: Some(&[
265                    0u8, 0u8, 0u8, 255u8, // pos-x
266                    0u8, 0u8, 0u8, 255u8, // neg-x
267                    0u8, 0u8, 0u8, 255u8, // pos-y
268                    0u8, 0u8, 0u8, 255u8, // neg-y
269                    0u8, 0u8, 0u8, 255u8, // pos-z
270                    0u8, 0u8, 0u8, 255u8, // neg-z
271                ]),
272                ..Default::default()
273            })?,
274            normal_dummy: server.create_texture(GpuTextureDescriptor {
275                name: "NormalDummy",
276                kind: GpuTextureKind::Rectangle {
277                    width: 1,
278                    height: 1,
279                },
280                pixel_kind: PixelKind::RGBA8,
281                data: Some(&[128u8, 128u8, 255u8, 255u8]),
282                ..Default::default()
283            })?,
284            metallic_dummy: server.create_texture(GpuTextureDescriptor {
285                name: "MetallicDummy",
286                kind: GpuTextureKind::Rectangle {
287                    width: 1,
288                    height: 1,
289                },
290                pixel_kind: PixelKind::RGBA8,
291                data: Some(&[0u8, 0u8, 0u8, 0u8]),
292                ..Default::default()
293            })?,
294            volume_dummy: server.create_texture(GpuTextureDescriptor {
295                name: "VolumeDummy",
296                kind: GpuTextureKind::Volume {
297                    width: 1,
298                    height: 1,
299                    depth: 1,
300                },
301                pixel_kind: PixelKind::RGBA8,
302                data: Some(&[0u8, 0u8, 0u8, 0u8]),
303                ..Default::default()
304            })?,
305            bone_matrices_stub_uniform_buffer: {
306                let buffer = server.create_buffer(GpuBufferDescriptor {
307                    name: "BoneMatricesStubBuffer",
308                    size: ShaderDefinition::MAX_BONE_MATRICES * size_of::<Matrix4<f32>>(),
309                    kind: BufferKind::Uniform,
310                    usage: BufferUsage::StaticDraw,
311                })?;
312                const SIZE: usize = ShaderDefinition::MAX_BONE_MATRICES * size_of::<Matrix4<f32>>();
313                let zeros = [0.0; SIZE];
314                buffer.write_data(array_as_u8_slice(&zeros))?;
315                buffer
316            },
317            linear_clamp_sampler: server.create_sampler(GpuSamplerDescriptor {
318                min_filter: MinificationFilter::Linear,
319                mag_filter: MagnificationFilter::Linear,
320                s_wrap_mode: WrapMode::ClampToEdge,
321                t_wrap_mode: WrapMode::ClampToEdge,
322                r_wrap_mode: WrapMode::ClampToEdge,
323                ..Default::default()
324            })?,
325            linear_mipmap_linear_clamp_sampler: server.create_sampler(GpuSamplerDescriptor {
326                min_filter: MinificationFilter::LinearMipMapLinear,
327                mag_filter: MagnificationFilter::Linear,
328                s_wrap_mode: WrapMode::ClampToEdge,
329                t_wrap_mode: WrapMode::ClampToEdge,
330                r_wrap_mode: WrapMode::ClampToEdge,
331                ..Default::default()
332            })?,
333            linear_wrap_sampler: server.create_sampler(GpuSamplerDescriptor {
334                min_filter: MinificationFilter::Linear,
335                mag_filter: MagnificationFilter::Linear,
336                ..Default::default()
337            })?,
338            nearest_clamp_sampler: server.create_sampler(GpuSamplerDescriptor {
339                min_filter: MinificationFilter::Nearest,
340                mag_filter: MagnificationFilter::Nearest,
341                s_wrap_mode: WrapMode::ClampToEdge,
342                t_wrap_mode: WrapMode::ClampToEdge,
343                r_wrap_mode: WrapMode::ClampToEdge,
344                ..Default::default()
345            })?,
346            nearest_wrap_sampler: server.create_sampler(GpuSamplerDescriptor {
347                min_filter: MinificationFilter::Nearest,
348                mag_filter: MagnificationFilter::Nearest,
349                ..Default::default()
350            })?,
351            quad: GpuGeometryBuffer::from_surface_data(
352                "UnitQuad",
353                &SurfaceData::make_unit_xy_quad(),
354                BufferUsage::StaticDraw,
355                server,
356            )?,
357            cube: GpuGeometryBuffer::from_surface_data(
358                "UnitCube",
359                &SurfaceData::make_cube(Matrix4::identity()),
360                BufferUsage::StaticDraw,
361                server,
362            )?,
363            shaders: ShadersContainer::new(server)?,
364        })
365    }
366
367    /// Picks a texture that corresponds to the actual value of the given sampler fallback.
368    pub fn sampler_fallback(&self, sampler_fallback: SamplerFallback) -> &GpuTexture {
369        match sampler_fallback {
370            SamplerFallback::White => &self.white_dummy,
371            SamplerFallback::Normal => &self.normal_dummy,
372            SamplerFallback::Black => &self.black_dummy,
373            SamplerFallback::Volume => &self.volume_dummy,
374        }
375    }
376}