Luanti 5.15.0-dev
 
Loading...
Searching...
No Matches
shader.h
Go to the documentation of this file.
1// Luanti
2// SPDX-License-Identifier: LGPL-2.1-or-later
3// Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4// Copyright (C) 2013 Kahrl <kahrl@gmx.net>
5
6#pragma once
7
9#include <IMaterialRendererServices.h>
10#include "irr_ptr.h"
11#include <string>
12#include <map>
13#include <variant>
14#include "nodedef.h"
15#include "tile.h" // MaterialType
16
17/*
18 shader.{h,cpp}: Shader handling stuff.
19*/
20
21/*
22 Gets the path to a shader by first checking if the file
23 name_of_shader/filename
24 exists in shader_path and if not, using the data path.
25
26 If not found, returns "".
27
28 Utilizes a thread-safe cache.
29*/
30std::string getShaderPath(const std::string &name_of_shader,
31 const std::string &filename);
32
33/*
34 Abstraction for pushing constants (or what we pretend is) into
35 shaders. These end up as `#define` prepended to the shader source.
36*/
37
38// Shader constants are either an int or a float in GLSL
39typedef std::map<std::string, std::variant<int, float>> ShaderConstants;
40
42public:
43 virtual ~IShaderConstantSetter() = default;
49 virtual void onGenerate(const std::string &name, ShaderConstants &constants) = 0;
50};
51
52/*
53 Abstraction for updating uniforms used by shaders
54*/
55
57public:
58 virtual ~IShaderUniformSetter() = default;
63 virtual void onSetUniforms(video::IMaterialRendererServices *services) = 0;
64 virtual void onSetMaterial(const video::SMaterial& material)
65 { }
66};
67
68class IShaderUniformSetterRC : public IShaderUniformSetter, public IReferenceCounted
69{
70 // Reference counted variant for special use-cases
71};
72
73
75public:
76 virtual ~IShaderUniformSetterFactory() = default;
82 virtual IShaderUniformSetter *create(const std::string &name) = 0;
83};
84
85/*
86 Helpers to set uniforms only when changed.
87
88 Be warned that when using this you can't attach a IShaderUniformSetter to
89 multiple different shaders. But you probably don't want to anyway.
90*/
91
92template <typename T, std::size_t count, bool cache>
94 const char *m_name;
95 T m_sent[count];
96 bool has_been_set = false;
98protected:
99 CachedShaderSetting(const char *name, bool is_pixel) :
100 m_name(name), is_pixel(is_pixel)
101 {}
102public:
103 void set(const T value[count], video::IMaterialRendererServices *services)
104 {
105 if (cache && has_been_set && std::equal(m_sent, m_sent + count, value))
106 return;
107 if (is_pixel)
108 services->setPixelShaderConstant(services->getPixelShaderConstantID(m_name), value, count);
109 else
110 services->setVertexShaderConstant(services->getVertexShaderConstantID(m_name), value, count);
111
112 if (cache) {
113 std::copy(value, value + count, m_sent);
114 has_been_set = true;
115 }
116 }
117
118 /* Type specializations */
119
120 /*
121 * T2 looks redundant here but it is necessary so the compiler won't
122 * resolve the templates at class instantiation and then fail because
123 * some of these methods don't have valid types (= are not usable).
124 * ref: <https://stackoverflow.com/a/6972771>
125 *
126 * Note: a `bool dummy` template parameter would have been easier but MSVC
127 * does not like that. Also make sure not to define different specializations
128 * with the same parameters, MSVC doesn't like that either.
129 * I extend my thanks to Microsoft®
130 */
131#define SPECIALIZE(_type, _count_expr) \
132 template<typename T2 = T> \
133 std::enable_if_t<std::is_same_v<T, T2> && std::is_same_v<T2, _type> && (_count_expr)>
134
135 SPECIALIZE(float, count == 2)
136 set(const v2f value, video::IMaterialRendererServices *services)
137 {
138 float array[2] = { value.X, value.Y };
139 set(array, services);
140 }
141
142 SPECIALIZE(float, count == 3)
143 set(const v3f value, video::IMaterialRendererServices *services)
144 {
145 float array[3] = { value.X, value.Y, value.Z };
146 set(array, services);
147 }
148
149 SPECIALIZE(float, count == 3 || count == 4)
150 set(const video::SColorf value, video::IMaterialRendererServices *services)
151 {
152 if constexpr (count == 3) {
153 float array[3] = { value.r, value.g, value.b };
154 set(array, services);
155 } else {
156 float array[4] = { value.r, value.g, value.b, value.a };
157 set(array, services);
158 }
159 }
160
161 SPECIALIZE(float, count == 16)
162 set(const core::matrix4 &value, video::IMaterialRendererServices *services)
163 {
164 set(value.pointer(), services);
165 }
166
167#undef SPECIALIZE
168};
169
170template <typename T, std::size_t count = 1, bool cache=true>
171class CachedPixelShaderSetting : public CachedShaderSetting<T, count, cache> {
172public:
173 CachedPixelShaderSetting(const char *name) :
174 CachedShaderSetting<T, count, cache>(name, true){}
175};
176
177template <typename T, std::size_t count = 1, bool cache=true>
178class CachedVertexShaderSetting : public CachedShaderSetting<T, count, cache> {
179public:
180 CachedVertexShaderSetting(const char *name) :
181 CachedShaderSetting<T, count, cache>(name, false){}
182};
183
184template <typename T, std::size_t count, bool cache, bool is_pixel>
186 const char *m_name;
187 T m_sent[count];
188 bool has_been_set = false;
189 std::array<const char*, count> m_fields;
190public:
191 CachedStructShaderSetting(const char *name, std::array<const char*, count> &&fields) :
192 m_name(name), m_fields(std::move(fields))
193 {}
194
195 void set(const T value[count], video::IMaterialRendererServices *services)
196 {
197 if (cache && has_been_set && std::equal(m_sent, m_sent + count, value))
198 return;
199
200 for (std::size_t i = 0; i < count; i++) {
201 std::string uniform_name = std::string(m_name) + "." + m_fields[i];
202
203 if (is_pixel)
204 services->setPixelShaderConstant(services->getPixelShaderConstantID(uniform_name.c_str()), value + i, 1);
205 else
206 services->setVertexShaderConstant(services->getVertexShaderConstantID(uniform_name.c_str()), value + i, 1);
207 }
208
209 if (cache) {
210 std::copy(value, value + count, m_sent);
211 has_been_set = true;
212 }
213 }
214};
215
216template<typename T, std::size_t count, bool cache = true>
218
219template<typename T, std::size_t count, bool cache = true>
221
222/*
223 ShaderSource creates and caches shaders.
224
225 A "shader" could more precisely be called a "shader material" and comprises
226 a vertex, fragment and optional geometry shader.
227 It is uniquely identified by a name, base material and the input constants.
228*/
229
231 std::string name;
232 video::E_MATERIAL_TYPE base_material = video::EMT_INVALID;
233 // Material ID the shader has received from Irrlicht
234 video::E_MATERIAL_TYPE material = video::EMT_INVALID;
235 // Input constants
237 // Extra uniform callback
238 irr_ptr<IShaderUniformSetterRC> setter_cb;
239};
240
242public:
243 IShaderSource() = default;
244 virtual ~IShaderSource() = default;
245
251 virtual const ShaderInfo &getShaderInfo(u32 id) = 0;
252
265 virtual u32 getShader(const std::string &name,
266 const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat,
267 IShaderUniformSetterRC *setter_cb = nullptr) = 0;
268
270 u32 getShader(const std::string &name,
271 MaterialType material_type, NodeDrawType drawtype = NDT_NORMAL,
272 bool array_texture = false);
273
280 inline u32 getShaderRaw(const std::string &name, bool blendAlpha = false)
281 {
282 auto base_mat = blendAlpha ? video::EMT_TRANSPARENT_ALPHA_CHANNEL :
283 video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
284 return getShader(name, ShaderConstants(), base_mat);
285 }
286
290 virtual bool supportsSampler2DArray() const = 0;
291};
292
294public:
296 virtual ~IWritableShaderSource() = default;
297
298 virtual void processQueue()=0;
299 virtual void insertSourceShader(const std::string &name_of_shader,
300 const std::string &filename, const std::string &program)=0;
301 virtual void rebuildShaders()=0;
302
304 virtual void addShaderConstantSetter(std::unique_ptr<IShaderConstantSetter> setter) = 0;
305
307 virtual void addShaderUniformSetterFactory(std::unique_ptr<IShaderUniformSetterFactory> setter) = 0;
308};
309
311
312void dumpShaderProgram(std::ostream &output_stream,
313 const std::string &program_type, std::string_view program);
Definition shader.h:171
CachedPixelShaderSetting(const char *name)
Definition shader.h:173
Definition shader.h:93
bool is_pixel
Definition shader.h:97
CachedShaderSetting(const char *name, bool is_pixel)
Definition shader.h:99
T m_sent[count]
Definition shader.h:95
bool has_been_set
Definition shader.h:96
const char * m_name
Definition shader.h:94
void set(const T value[count], video::IMaterialRendererServices *services)
Definition shader.h:103
Definition shader.h:185
void set(const T value[count], video::IMaterialRendererServices *services)
Definition shader.h:195
T m_sent[count]
Definition shader.h:187
std::array< const char *, count > m_fields
Definition shader.h:189
bool has_been_set
Definition shader.h:188
CachedStructShaderSetting(const char *name, std::array< const char *, count > &&fields)
Definition shader.h:191
const char * m_name
Definition shader.h:186
Definition shader.h:178
CachedVertexShaderSetting(const char *name)
Definition shader.h:180
Definition shader.h:41
virtual ~IShaderConstantSetter()=default
virtual void onGenerate(const std::string &name, ShaderConstants &constants)=0
Called when the final shader source is being generated.
Definition shader.h:241
virtual bool supportsSampler2DArray() const =0
Returns true if 'sampler2DArray' is supported in GLSL.
IShaderSource()=default
u32 getShaderRaw(const std::string &name, bool blendAlpha=false)
Helper: Generates or gets a shader for common, general use.
Definition shader.h:280
virtual u32 getShader(const std::string &name, const ShaderConstants &input_const, video::E_MATERIAL_TYPE base_mat, IShaderUniformSetterRC *setter_cb=nullptr)=0
Generates or gets a shader.
virtual ~IShaderSource()=default
virtual const ShaderInfo & getShaderInfo(u32 id)=0
returns information about an existing shader
Definition shader.h:74
virtual ~IShaderUniformSetterFactory()=default
virtual IShaderUniformSetter * create(const std::string &name)=0
Called to create an uniform setter for a specific shader.
Definition shader.h:69
Definition shader.h:56
virtual void onSetMaterial(const video::SMaterial &material)
Definition shader.h:64
virtual ~IShaderUniformSetter()=default
virtual void onSetUniforms(video::IMaterialRendererServices *services)=0
Called when uniforms need to be updated.
Definition shader.h:293
virtual void rebuildShaders()=0
virtual ~IWritableShaderSource()=default
virtual void addShaderUniformSetterFactory(std::unique_ptr< IShaderUniformSetterFactory > setter)=0
IWritableShaderSource()=default
virtual void insertSourceShader(const std::string &name_of_shader, const std::string &filename, const std::string &program)=0
virtual void processQueue()=0
virtual void addShaderConstantSetter(std::unique_ptr< IShaderConstantSetter > setter)=0
core::vector2d< f32 > v2f
Definition irr_v2d.h:11
core::vector3df v3f
Definition irr_v3d.h:11
Definition printing.h:10
Definition clientmap.h:36
NodeDrawType
Definition nodedef.h:182
@ NDT_NORMAL
Definition nodedef.h:184
std::map< std::string, std::variant< int, float > > ShaderConstants
Definition shader.h:39
IWritableShaderSource * createShaderSource()
Definition shader.cpp:459
std::string getShaderPath(const std::string &name_of_shader, const std::string &filename)
Definition shader.cpp:39
#define SPECIALIZE(_type, _count_expr)
Definition shader.h:131
void dumpShaderProgram(std::ostream &output_stream, const std::string &program_type, std::string_view program)
Definition shader.cpp:885
Definition shader.h:230
std::string name
Definition shader.h:231
video::E_MATERIAL_TYPE base_material
Definition shader.h:232
ShaderConstants input_constants
Definition shader.h:236
video::E_MATERIAL_TYPE material
Definition shader.h:234
irr_ptr< IShaderUniformSetterRC > setter_cb
Definition shader.h:238
core::matrix4 matrix4
Definition test_irr_matrix4.cpp:12
MaterialType
Definition tile.h:12