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}