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}