Skip to main content

fyrox_graphics/
gpu_program.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 GPU program is a collection of shaders that are linked together so that they
22//! can run on the GPU to control how rendering is performed.
23
24use crate::{
25    core::{
26        algebra::{Matrix2, Matrix3, Matrix4, Vector2, Vector3, Vector4},
27        reflect::prelude::*,
28        sstorage::ImmutableString,
29        type_traits::prelude::*,
30        visitor::prelude::*,
31    },
32    define_shared_wrapper,
33};
34use fyrox_core::define_as_any_trait;
35use serde::{Deserialize, Serialize};
36use strum_macros::{AsRefStr, EnumString, VariantNames};
37
38define_as_any_trait!(GpuProgramAsAny => GpuProgramTrait);
39/// A trait for whatever objects a graphics server is using to represent programs.
40/// There are no methods because all interactions with programs are done through the server,
41/// such as with [`crate::server::GraphicsServer::create_program`]
42/// and [`crate::framebuffer::GpuFrameBufferTrait::draw`].
43pub trait GpuProgramTrait: GpuProgramAsAny {}
44define_shared_wrapper!(GpuProgram<dyn GpuProgramTrait>);
45
46/// A shader can be either a fragment shader that produces pixels or
47/// a vertex shader that controls where triangles are drawn on the screen.
48pub enum ShaderKind {
49    /// A vertex shader takes vertices in world coordinates and mathematically
50    /// transforms them into screen coordinates for rendering. The vertex shader
51    /// runs before the fragment shader and creates the input to the fragment shader.
52    Vertex,
53    /// The fragment shader determines whether a pixel should be drawn and what color it should be.
54    /// It uses the data produced by the vertex shader after it has been interpolated by the GPU
55    /// for the particular pixel under consideration.
56    Fragment,
57}
58
59define_as_any_trait!(GpuShaderAsAny => GpuShaderTrait);
60/// A trait for whatever objects a graphics server is using to represent shaders.
61/// There are no methods because all interactions with programs are done through the server,
62/// such as with [`crate::server::GraphicsServer::create_shader`].
63pub trait GpuShaderTrait: GpuShaderAsAny {}
64define_shared_wrapper!(GpuShader<dyn GpuShaderTrait>);
65
66/// A fallback value for the sampler.
67///
68/// # Notes
69///
70/// Sometimes you don't want to set a value to a sampler, or you even don't have the appropriate
71/// one. There is fallback value that helps you with such situations, it defines a values that
72/// will be fetched from a sampler when there is no texture.
73///
74/// For example, standard shader has a lot of samplers defined: diffuse, normal, height, emission,
75/// mask, metallic, roughness, etc. In some situations you may not have all the textures, you have
76/// only diffuse texture, to keep rendering correct, each other property has appropriate fallback
77/// value. Normal sampler - a normal vector pointing up (+Y), height - zero, emission - zero, etc.
78///
79/// Fallback value is also helpful to catch missing textures, you'll definitely know the texture is
80/// missing by very specific value in the fallback texture.
81#[derive(
82    Serialize,
83    Deserialize,
84    Default,
85    Debug,
86    PartialEq,
87    Clone,
88    Copy,
89    Visit,
90    Eq,
91    Reflect,
92    AsRefStr,
93    EnumString,
94    VariantNames,
95    TypeUuidProvider,
96)]
97#[type_uuid(id = "791b333c-eb3f-4279-97fe-cf2ba45c6d78")]
98pub enum SamplerFallback {
99    /// A 1x1px white texture.
100    #[default]
101    White,
102    /// A 1x1px texture with (0, 1, 0) vector.
103    Normal,
104    /// A 1x1px black texture.
105    Black,
106    /// A 1x1x1 volume texture with 1 black pixel.
107    Volume,
108}
109
110/// A sampler represents how the data of a texture is accessed, and different kinds of samplers
111/// are intended for different kinds of textures.
112#[derive(
113    Serialize,
114    Deserialize,
115    Default,
116    Debug,
117    PartialEq,
118    Clone,
119    Copy,
120    Visit,
121    Eq,
122    Reflect,
123    AsRefStr,
124    EnumString,
125    VariantNames,
126    TypeUuidProvider,
127)]
128#[type_uuid(id = "50dc9197-f7f7-4a7d-9b64-9f0868785f56")]
129pub enum SamplerKind {
130    /// A sampler for a 1D linear texture, a series of values that are indexed by a single coordinate
131    /// and where each component of the value is a float.
132    Sampler1D,
133    /// A sampler for the usual 2D image texture, a flat area of values that are indexed by a pair of coordinates (x, y)
134    /// and where each component of the value is a float.
135    #[default]
136    Sampler2D,
137    /// A sampler for a 3D texture, a volume of values that are indexed by three coordinates (x, y, z)
138    /// and where each component of the value is a float.
139    Sampler3D,
140    /// A sampler for six square 2D images where each image represents one face of a cube.
141    /// It is indexed by a three coordinate direction from the center of the cube (x, y, z) where the magnitude of the coordinates do not matter.
142    /// The sampler follows the direction of the coordinates until it finds a place on one of the six faces of the cube.
143    /// Each component of the resulting value is a float.
144    SamplerCube,
145    /// A sampler for a 1D linear texture, a series of values that are indexed by a single coordinate
146    /// and where each component of the value is an unsigned integer.
147    USampler1D,
148    /// A sampler for the usual 2D image texture, a flat area of values that are indexed by a pair of coordinates (x, y)
149    /// and where each component of the value is an unsigned integer.
150    USampler2D,
151    /// A sampler for a 3D texture, a volume of values that are indexed by three coordinates (x, y, z)
152    /// and where each component of the value is an unsigned integer.
153    USampler3D,
154    /// A sampler for six square 2D images where each image represents one face of a cube.
155    /// It is indexed by a three coordinate direction from the center of the cube (x, y, z) where the magnitude of the coordinates do not matter.
156    /// The sampler follows the direction of the coordinates until it finds a place on one of the six faces of the cube.
157    /// Each component of the resulting value is an unsigned integer.
158    USamplerCube,
159}
160
161/// Shader property with default value.
162#[derive(
163    Serialize,
164    Deserialize,
165    Debug,
166    PartialEq,
167    Reflect,
168    Visit,
169    Clone,
170    TypeUuidProvider,
171    AsRefStr,
172    EnumString,
173    VariantNames,
174)]
175#[type_uuid(id = "13896a77-dae6-481e-9c76-808a3d4c3ff0")]
176pub enum ShaderResourceKind {
177    /// A texture.
178    Texture {
179        /// Kind of the texture.
180        kind: SamplerKind,
181
182        /// Fallback value.
183        ///
184        /// Sometimes you don't want to set a value to a texture binding, or you even don't have the appropriate
185        /// one. There is fallback value that helps you with such situations, it defines a set of values that
186        /// will be fetched from a texture binding point when there is no actual texture.
187        ///
188        /// For example, standard shader has a lot of samplers defined: diffuse, normal, height, emission,
189        /// mask, metallic, roughness, etc. In some situations you may not have all the textures, you have
190        /// only diffuse texture, to keep rendering correct, each other property has appropriate fallback
191        /// value. Normal sampler - a normal vector pointing up (+Y), height - zero, emission - zero, etc.
192        ///
193        /// Fallback value is also helpful to catch missing textures, you'll definitely know the texture is
194        /// missing by very specific value in the fallback texture.
195        fallback: SamplerFallback,
196    },
197    /// A list of properties with names and values that represents a uniform struct within the shader
198    /// and the default values for each field of the struct.
199    PropertyGroup(Vec<ShaderProperty>),
200}
201
202/// A data type and default value for a uniform within a shader.
203/// When a material supplies an actual value, it is done using a `MaterialProperty` value
204/// from the `fyrox-material` crate.
205#[derive(
206    Serialize,
207    Deserialize,
208    Debug,
209    PartialEq,
210    Clone,
211    Reflect,
212    Visit,
213    TypeUuidProvider,
214    AsRefStr,
215    EnumString,
216    VariantNames,
217)]
218#[type_uuid(id = "0053de9a-0911-4d26-8f8e-8a4f65e1b0a7")]
219pub enum ShaderPropertyKind {
220    /// Real number.
221    Float {
222        /// Default value
223        #[serde(default)]
224        value: f32,
225    },
226
227    /// Real number array.
228    FloatArray {
229        /// Default value
230        value: Vec<f32>,
231        /// `max_len` defines the maximum number of elements in the shader.
232        max_len: usize,
233    },
234
235    /// Integer number.
236    Int {
237        /// Default value
238        #[serde(default)]
239        value: i32,
240    },
241
242    /// Integer number array.
243    IntArray {
244        /// Default value
245        value: Vec<i32>,
246        /// `max_len` defines the maximum number of elements in the shader.
247        max_len: usize,
248    },
249
250    /// Natural number.
251    UInt {
252        /// Default value
253        #[serde(default)]
254        value: u32,
255    },
256
257    /// Natural number array.
258    UIntArray {
259        /// Default value
260        value: Vec<u32>,
261        /// `max_len` defines the maximum number of elements in the shader.
262        max_len: usize,
263    },
264
265    /// Boolean value.
266    Bool {
267        /// Default value
268        #[serde(default)]
269        value: bool,
270    },
271
272    /// Two-dimensional vector.
273    Vector2 {
274        /// Default value
275        #[serde(default)]
276        value: Vector2<f32>,
277    },
278
279    /// Two-dimensional vector array.
280    Vector2Array {
281        /// Default value
282        value: Vec<Vector2<f32>>,
283        /// `max_len` defines the maximum number of elements in the shader.
284        max_len: usize,
285    },
286
287    /// Three-dimensional vector.
288    Vector3 {
289        /// Default value
290        #[serde(default)]
291        value: Vector3<f32>,
292    },
293
294    /// Three-dimensional vector array.
295    Vector3Array {
296        /// Default value
297        value: Vec<Vector3<f32>>,
298        /// `max_len` defines the maximum number of elements in the shader.
299        max_len: usize,
300    },
301
302    /// Four-dimensional vector.
303    Vector4 {
304        /// Default value
305        #[serde(default)]
306        value: Vector4<f32>,
307    },
308
309    /// Four-dimensional vector array.
310    Vector4Array {
311        /// Default value
312        value: Vec<Vector4<f32>>,
313        /// `max_len` defines the maximum number of elements in the shader.
314        max_len: usize,
315    },
316
317    /// 2x2 Matrix.
318    Matrix2 {
319        /// Default value
320        #[serde(default)]
321        value: Matrix2<f32>,
322    },
323
324    /// 2x2 Matrix array.
325    Matrix2Array {
326        /// Default value
327        value: Vec<Matrix2<f32>>,
328        /// `max_len` defines the maximum number of elements in the shader.
329        max_len: usize,
330    },
331
332    /// 3x3 Matrix.
333    Matrix3 {
334        /// Default value
335        #[serde(default)]
336        value: Matrix3<f32>,
337    },
338
339    /// 3x3 Matrix array.
340    Matrix3Array {
341        /// Default value
342        value: Vec<Matrix3<f32>>,
343        /// `max_len` defines the maximum number of elements in the shader.
344        max_len: usize,
345    },
346
347    /// 4x4 Matrix.
348    Matrix4 {
349        /// Default value
350        #[serde(default)]
351        value: Matrix4<f32>,
352    },
353
354    /// 4x4 Matrix array.
355    Matrix4Array {
356        /// Default value
357        value: Vec<Matrix4<f32>>,
358        /// `max_len` defines the maximum number of elements in the shader.
359        max_len: usize,
360    },
361
362    /// An sRGB color.
363    Color {
364        /// Default Red.
365        #[serde(default = "default_color_component")]
366        r: u8,
367
368        /// Default Green.
369        #[serde(default = "default_color_component")]
370        g: u8,
371
372        /// Default Blue.
373        #[serde(default = "default_color_component")]
374        b: u8,
375
376        /// Default Alpha.
377        #[serde(default = "default_color_component")]
378        a: u8,
379    },
380}
381
382fn default_color_component() -> u8 {
383    255
384}
385
386/// A uniform value that is supplied to a shader by a material.
387#[derive(
388    Serialize, Deserialize, Debug, PartialEq, Reflect, Visit, Clone, Default, TypeUuidProvider,
389)]
390#[type_uuid(id = "078b9f26-8fae-4f2f-99d9-9e882c439ebc")]
391pub struct ShaderProperty {
392    /// The name of the value in the shader and when editing the value in the material.
393    pub name: ImmutableString,
394    /// The property's data type and default value.
395    pub kind: ShaderPropertyKind,
396}
397
398impl ShaderProperty {
399    /// Create a property with the given name and value.
400    pub fn new(name: impl Into<ImmutableString>, kind: ShaderPropertyKind) -> Self {
401        Self {
402            name: name.into(),
403            kind,
404        }
405    }
406
407    /// Create a property with the 2x2 identity matrix as its value.
408    pub fn new_matrix2(name: impl Into<ImmutableString>) -> Self {
409        Self::new(
410            name,
411            ShaderPropertyKind::Matrix2 {
412                value: Matrix2::identity(),
413            },
414        )
415    }
416
417    /// Create a property with the 3x3 identity matrix as its value.
418    pub fn new_matrix3(name: impl Into<ImmutableString>) -> Self {
419        Self::new(
420            name,
421            ShaderPropertyKind::Matrix3 {
422                value: Matrix3::identity(),
423            },
424        )
425    }
426
427    /// Create a property with the 4x4 identity matrix as its value.
428    pub fn new_matrix4(name: impl Into<ImmutableString>) -> Self {
429        Self::new(
430            name,
431            ShaderPropertyKind::Matrix4 {
432                value: Matrix4::identity(),
433            },
434        )
435    }
436
437    /// Create a property with the vector (0,0) as its value.
438    pub fn new_vector2(name: impl Into<ImmutableString>) -> Self {
439        Self::new(
440            name,
441            ShaderPropertyKind::Vector2 {
442                value: Default::default(),
443            },
444        )
445    }
446
447    /// Create a property with the vector (0,0,0) as its value.
448    pub fn new_vector3(name: impl Into<ImmutableString>) -> Self {
449        Self::new(
450            name,
451            ShaderPropertyKind::Vector3 {
452                value: Default::default(),
453            },
454        )
455    }
456
457    /// Create a property with the vector (0,0,0,0) as its value.
458    pub fn new_vector4(name: impl Into<ImmutableString>) -> Self {
459        Self::new(
460            name,
461            ShaderPropertyKind::Vector4 {
462                value: Default::default(),
463            },
464        )
465    }
466
467    /// Create a property with the float 0.0 as its value.
468    pub fn new_float(name: impl Into<ImmutableString>) -> Self {
469        Self::new(name, ShaderPropertyKind::Float { value: 0.0 })
470    }
471
472    /// Create a property with false as its value.
473    pub fn new_bool(name: impl Into<ImmutableString>) -> Self {
474        Self::new(name, ShaderPropertyKind::Bool { value: false })
475    }
476
477    /// Create a property with the integer 0 as its value.
478    pub fn new_int(name: impl Into<ImmutableString>) -> Self {
479        Self::new(name, ShaderPropertyKind::Int { value: 0 })
480    }
481
482    /// Create a property with white as its value.
483    pub fn new_color(name: impl Into<ImmutableString>) -> Self {
484        Self::new(
485            name,
486            ShaderPropertyKind::Color {
487                r: 255,
488                g: 255,
489                b: 255,
490                a: 255,
491            },
492        )
493    }
494
495    /// Create a property with an empty list of 4x4 matrices and the given maximum length for the list.
496    pub fn new_mat4_f32_array(name: impl Into<ImmutableString>, max_len: usize) -> Self {
497        Self::new(
498            name,
499            ShaderPropertyKind::Matrix4Array {
500                value: Default::default(),
501                max_len,
502            },
503        )
504    }
505
506    /// Create a property with an empty list of floats and the given maximum length for the list.
507    pub fn new_f32_array(name: impl Into<ImmutableString>, max_len: usize) -> Self {
508        Self::new(
509            name,
510            ShaderPropertyKind::FloatArray {
511                value: Default::default(),
512                max_len,
513            },
514        )
515    }
516
517    /// Create a property with an empty list of vectors and the given maximum length for the list.
518    pub fn new_vec4_f32_array(name: impl Into<ImmutableString>, max_len: usize) -> Self {
519        Self::new(
520            name,
521            ShaderPropertyKind::Vector4Array {
522                value: Default::default(),
523                max_len,
524            },
525        )
526    }
527
528    /// Create a property with an empty list of vectors and the given maximum length for the list.
529    pub fn new_vec3_f32_array(name: impl Into<ImmutableString>, max_len: usize) -> Self {
530        Self::new(
531            name,
532            ShaderPropertyKind::Vector3Array {
533                value: Default::default(),
534                max_len,
535            },
536        )
537    }
538
539    /// Create a property with an empty list of vectors and the given maximum length for the list.
540    pub fn new_vec2_f32_array(name: impl Into<ImmutableString>, max_len: usize) -> Self {
541        Self::new(
542            name,
543            ShaderPropertyKind::Vector2Array {
544                value: Default::default(),
545                max_len,
546            },
547        )
548    }
549}
550
551impl Default for ShaderPropertyKind {
552    fn default() -> Self {
553        Self::Float { value: 0.0 }
554    }
555}
556
557impl Default for ShaderResourceKind {
558    fn default() -> Self {
559        Self::PropertyGroup(Default::default())
560    }
561}
562
563/// Shader resource definition.
564#[derive(
565    Default, Serialize, Deserialize, Clone, Debug, PartialEq, Reflect, Visit, TypeUuidProvider,
566)]
567#[type_uuid(id = "281df21d-ec95-42c7-a17e-a3eb4724dfc9")]
568pub struct ShaderResourceDefinition {
569    /// The name of the uniform as it appears in the source code, ready to be passed to `glGetUniformLocation`.
570    /// If the name begins with "fyrox_" then Fyrox will treat it specially and try to automatically generate
571    /// the uniform's value based on its name, such as "fyrox_sceneDepth".
572    pub name: ImmutableString,
573    /// A kind of resource.
574    pub kind: ShaderResourceKind,
575    /// Each of a program's active uniform blocks has a corresponding uniform buffer binding point.
576    /// Binding points for active uniform blocks are assigned using `glUniformBlockBinding`.
577    /// For textures, `glUniform1i` is used to assign the texture's binding point to the texture uniform.
578    pub binding: usize,
579}
580
581impl ShaderResourceDefinition {
582    /// Fyrox provides certain resources to shaders automatically, without the resources needing
583    /// to be part of the material. This method is used by the `fyrox-impl` crate to decide whether
584    /// it should look for the resource in the material (if `false`) or whether it should assume
585    /// that this resource will be among the automatically provided resources.
586    pub fn is_built_in(&self) -> bool {
587        self.name.starts_with("fyrox_")
588    }
589}