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(Serialize, Deserialize, Default, Debug, PartialEq, Clone, Copy, Visit, Eq, Reflect)]
113pub enum SamplerKind {
114    /// A sampler for a 1D linear texture, a series of values that are indexed by a single coordinate
115    /// and where each component of the value is a float.
116    Sampler1D,
117    /// A sampler for the usual 2D image texture, a flat area of values that are indexed by a pair of coordinates (x, y)
118    /// and where each component of the value is a float.
119    #[default]
120    Sampler2D,
121    /// A sampler for a 3D texture, a volume of values that are indexed by three coordinates (x, y, z)
122    /// and where each component of the value is a float.
123    Sampler3D,
124    /// A sampler for six square 2D images where each image represents one face of a cube.
125    /// 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.
126    /// The sampler follows the direction of the coordinates until it finds a place on one of the six faces of the cube.
127    /// Each component of the resulting value is a float.
128    SamplerCube,
129    /// A sampler for a 1D linear texture, a series of values that are indexed by a single coordinate
130    /// and where each component of the value is an unsigned integer.
131    USampler1D,
132    /// A sampler for the usual 2D image texture, a flat area of values that are indexed by a pair of coordinates (x, y)
133    /// and where each component of the value is an unsigned integer.
134    USampler2D,
135    /// A sampler for a 3D texture, a volume of values that are indexed by three coordinates (x, y, z)
136    /// and where each component of the value is an unsigned integer.
137    USampler3D,
138    /// A sampler for six square 2D images where each image represents one face of a cube.
139    /// 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.
140    /// The sampler follows the direction of the coordinates until it finds a place on one of the six faces of the cube.
141    /// Each component of the resulting value is an unsigned integer.
142    USamplerCube,
143}
144
145/// Shader property with default value.
146#[derive(Serialize, Deserialize, Debug, PartialEq, Reflect, Visit, Clone)]
147pub enum ShaderResourceKind {
148    /// A texture.
149    Texture {
150        /// Kind of the texture.
151        kind: SamplerKind,
152
153        /// Fallback value.
154        ///
155        /// Sometimes you don't want to set a value to a texture binding, or you even don't have the appropriate
156        /// one. There is fallback value that helps you with such situations, it defines a set of values that
157        /// will be fetched from a texture binding point when there is no actual texture.
158        ///
159        /// For example, standard shader has a lot of samplers defined: diffuse, normal, height, emission,
160        /// mask, metallic, roughness, etc. In some situations you may not have all the textures, you have
161        /// only diffuse texture, to keep rendering correct, each other property has appropriate fallback
162        /// value. Normal sampler - a normal vector pointing up (+Y), height - zero, emission - zero, etc.
163        ///
164        /// Fallback value is also helpful to catch missing textures, you'll definitely know the texture is
165        /// missing by very specific value in the fallback texture.
166        fallback: SamplerFallback,
167    },
168    /// A list of properties with names and values that represents a uniform struct within the shader
169    /// and the default values for each field of the struct.
170    PropertyGroup(Vec<ShaderProperty>),
171}
172
173/// A data type and default value for a uniform within a shader.
174/// When a material supplies an actual value, it is done using a `MaterialProperty` value
175/// from the `fyrox-material` crate.
176#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Reflect, Visit)]
177pub enum ShaderPropertyKind {
178    /// Real number.
179    Float {
180        /// Default value
181        #[serde(default)]
182        value: f32,
183    },
184
185    /// Real number array.
186    FloatArray {
187        /// Default value
188        value: Vec<f32>,
189        /// `max_len` defines the maximum number of elements in the shader.
190        max_len: usize,
191    },
192
193    /// Integer number.
194    Int {
195        /// Default value
196        #[serde(default)]
197        value: i32,
198    },
199
200    /// Integer number array.
201    IntArray {
202        /// Default value
203        value: Vec<i32>,
204        /// `max_len` defines the maximum number of elements in the shader.
205        max_len: usize,
206    },
207
208    /// Natural number.
209    UInt {
210        /// Default value
211        #[serde(default)]
212        value: u32,
213    },
214
215    /// Natural number array.
216    UIntArray {
217        /// Default value
218        value: Vec<u32>,
219        /// `max_len` defines the maximum number of elements in the shader.
220        max_len: usize,
221    },
222
223    /// Boolean value.
224    Bool {
225        /// Default value
226        #[serde(default)]
227        value: bool,
228    },
229
230    /// Two-dimensional vector.
231    Vector2 {
232        /// Default value
233        #[serde(default)]
234        value: Vector2<f32>,
235    },
236
237    /// Two-dimensional vector array.
238    Vector2Array {
239        /// Default value
240        value: Vec<Vector2<f32>>,
241        /// `max_len` defines the maximum number of elements in the shader.
242        max_len: usize,
243    },
244
245    /// Three-dimensional vector.
246    Vector3 {
247        /// Default value
248        #[serde(default)]
249        value: Vector3<f32>,
250    },
251
252    /// Three-dimensional vector array.
253    Vector3Array {
254        /// Default value
255        value: Vec<Vector3<f32>>,
256        /// `max_len` defines the maximum number of elements in the shader.
257        max_len: usize,
258    },
259
260    /// Four-dimensional vector.
261    Vector4 {
262        /// Default value
263        #[serde(default)]
264        value: Vector4<f32>,
265    },
266
267    /// Four-dimensional vector array.
268    Vector4Array {
269        /// Default value
270        value: Vec<Vector4<f32>>,
271        /// `max_len` defines the maximum number of elements in the shader.
272        max_len: usize,
273    },
274
275    /// 2x2 Matrix.
276    Matrix2 {
277        /// Default value
278        #[serde(default)]
279        value: Matrix2<f32>,
280    },
281
282    /// 2x2 Matrix array.
283    Matrix2Array {
284        /// Default value
285        value: Vec<Matrix2<f32>>,
286        /// `max_len` defines the maximum number of elements in the shader.
287        max_len: usize,
288    },
289
290    /// 3x3 Matrix.
291    Matrix3 {
292        /// Default value
293        #[serde(default)]
294        value: Matrix3<f32>,
295    },
296
297    /// 3x3 Matrix array.
298    Matrix3Array {
299        /// Default value
300        value: Vec<Matrix3<f32>>,
301        /// `max_len` defines the maximum number of elements in the shader.
302        max_len: usize,
303    },
304
305    /// 4x4 Matrix.
306    Matrix4 {
307        /// Default value
308        #[serde(default)]
309        value: Matrix4<f32>,
310    },
311
312    /// 4x4 Matrix array.
313    Matrix4Array {
314        /// Default value
315        value: Vec<Matrix4<f32>>,
316        /// `max_len` defines the maximum number of elements in the shader.
317        max_len: usize,
318    },
319
320    /// An sRGB color.
321    Color {
322        /// Default Red.
323        #[serde(default = "default_color_component")]
324        r: u8,
325
326        /// Default Green.
327        #[serde(default = "default_color_component")]
328        g: u8,
329
330        /// Default Blue.
331        #[serde(default = "default_color_component")]
332        b: u8,
333
334        /// Default Alpha.
335        #[serde(default = "default_color_component")]
336        a: u8,
337    },
338}
339
340fn default_color_component() -> u8 {
341    255
342}
343
344/// A uniform value that is supplied to a shader by a material.
345#[derive(Serialize, Deserialize, Debug, PartialEq, Reflect, Visit, Clone, Default)]
346pub struct ShaderProperty {
347    /// The name of the value in the shader and when editing the value in the material.
348    pub name: ImmutableString,
349    /// The property's data type and default value.
350    pub kind: ShaderPropertyKind,
351}
352
353impl ShaderProperty {
354    /// Create a property with the given name and value.
355    pub fn new(name: impl Into<ImmutableString>, kind: ShaderPropertyKind) -> Self {
356        Self {
357            name: name.into(),
358            kind,
359        }
360    }
361
362    /// Create a property with the 2x2 identity matrix as its value.
363    pub fn new_matrix2(name: impl Into<ImmutableString>) -> Self {
364        Self::new(
365            name,
366            ShaderPropertyKind::Matrix2 {
367                value: Matrix2::identity(),
368            },
369        )
370    }
371
372    /// Create a property with the 3x3 identity matrix as its value.
373    pub fn new_matrix3(name: impl Into<ImmutableString>) -> Self {
374        Self::new(
375            name,
376            ShaderPropertyKind::Matrix3 {
377                value: Matrix3::identity(),
378            },
379        )
380    }
381
382    /// Create a property with the 4x4 identity matrix as its value.
383    pub fn new_matrix4(name: impl Into<ImmutableString>) -> Self {
384        Self::new(
385            name,
386            ShaderPropertyKind::Matrix4 {
387                value: Matrix4::identity(),
388            },
389        )
390    }
391
392    /// Create a property with the vector (0,0) as its value.
393    pub fn new_vector2(name: impl Into<ImmutableString>) -> Self {
394        Self::new(
395            name,
396            ShaderPropertyKind::Vector2 {
397                value: Default::default(),
398            },
399        )
400    }
401
402    /// Create a property with the vector (0,0,0) as its value.
403    pub fn new_vector3(name: impl Into<ImmutableString>) -> Self {
404        Self::new(
405            name,
406            ShaderPropertyKind::Vector3 {
407                value: Default::default(),
408            },
409        )
410    }
411
412    /// Create a property with the vector (0,0,0,0) as its value.
413    pub fn new_vector4(name: impl Into<ImmutableString>) -> Self {
414        Self::new(
415            name,
416            ShaderPropertyKind::Vector4 {
417                value: Default::default(),
418            },
419        )
420    }
421
422    /// Create a property with the float 0.0 as its value.
423    pub fn new_float(name: impl Into<ImmutableString>) -> Self {
424        Self::new(name, ShaderPropertyKind::Float { value: 0.0 })
425    }
426
427    /// Create a property with false as its value.
428    pub fn new_bool(name: impl Into<ImmutableString>) -> Self {
429        Self::new(name, ShaderPropertyKind::Bool { value: false })
430    }
431
432    /// Create a property with the integer 0 as its value.
433    pub fn new_int(name: impl Into<ImmutableString>) -> Self {
434        Self::new(name, ShaderPropertyKind::Int { value: 0 })
435    }
436
437    /// Create a property with white as its value.
438    pub fn new_color(name: impl Into<ImmutableString>) -> Self {
439        Self::new(
440            name,
441            ShaderPropertyKind::Color {
442                r: 255,
443                g: 255,
444                b: 255,
445                a: 255,
446            },
447        )
448    }
449
450    /// Create a property with an empty list of 4x4 matrices and the given maximum length for the list.
451    pub fn new_mat4_f32_array(name: impl Into<ImmutableString>, max_len: usize) -> Self {
452        Self::new(
453            name,
454            ShaderPropertyKind::Matrix4Array {
455                value: Default::default(),
456                max_len,
457            },
458        )
459    }
460
461    /// Create a property with an empty list of floats and the given maximum length for the list.
462    pub fn new_f32_array(name: impl Into<ImmutableString>, max_len: usize) -> Self {
463        Self::new(
464            name,
465            ShaderPropertyKind::FloatArray {
466                value: Default::default(),
467                max_len,
468            },
469        )
470    }
471
472    /// Create a property with an empty list of vectors and the given maximum length for the list.
473    pub fn new_vec4_f32_array(name: impl Into<ImmutableString>, max_len: usize) -> Self {
474        Self::new(
475            name,
476            ShaderPropertyKind::Vector4Array {
477                value: Default::default(),
478                max_len,
479            },
480        )
481    }
482
483    /// Create a property with an empty list of vectors and the given maximum length for the list.
484    pub fn new_vec3_f32_array(name: impl Into<ImmutableString>, max_len: usize) -> Self {
485        Self::new(
486            name,
487            ShaderPropertyKind::Vector3Array {
488                value: Default::default(),
489                max_len,
490            },
491        )
492    }
493
494    /// Create a property with an empty list of vectors and the given maximum length for the list.
495    pub fn new_vec2_f32_array(name: impl Into<ImmutableString>, max_len: usize) -> Self {
496        Self::new(
497            name,
498            ShaderPropertyKind::Vector2Array {
499                value: Default::default(),
500                max_len,
501            },
502        )
503    }
504}
505
506impl Default for ShaderPropertyKind {
507    fn default() -> Self {
508        Self::Float { value: 0.0 }
509    }
510}
511
512impl Default for ShaderResourceKind {
513    fn default() -> Self {
514        Self::PropertyGroup(Default::default())
515    }
516}
517
518/// Shader resource definition.
519#[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, Reflect, Visit)]
520pub struct ShaderResourceDefinition {
521    /// The name of the uniform as it appears in the source code, ready to be passed to `glGetUniformLocation`.
522    /// If the name begins with "fyrox_" then Fyrox will treat it specially and try to automatically generate
523    /// the uniform's value based on its name, such as "fyrox_sceneDepth".
524    pub name: ImmutableString,
525    /// A kind of resource.
526    pub kind: ShaderResourceKind,
527    /// Each of a program's active uniform blocks has a corresponding uniform buffer binding point.
528    /// Binding points for active uniform blocks are assigned using `glUniformBlockBinding`.
529    /// For textures, `glUniform1i` is used to assign the texture's binding point to the texture uniform.
530    pub binding: usize,
531}
532
533impl ShaderResourceDefinition {
534    /// Fyrox provides certain resources to shaders automatically, without the resources needing
535    /// to be part of the material. This method is used by the `fyrox-impl` crate to decide whether
536    /// it should look for the resource in the material (if `false`) or whether it should assume
537    /// that this resource will be among the automatically provided resources.
538    pub fn is_built_in(&self) -> bool {
539        self.name.starts_with("fyrox_")
540    }
541}