GCC Code Coverage Report


./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 of 260, 0 excluded
0.0%
Functions:
0 of 25, 0 excluded
0.0%
Branches:
0 of 562, 0 excluded
0.0%

libs/render/src/eu/render/shader_resource.cc
Line Branch Exec Source
1 #include "eu/render/shader_resource.h"
2
3 #include "eu/assert/assert.h"
4
5
6
7 #include "eu/render/camera.h"
8 #include "eu/render/constants.h"
9 #include "eu/render/fullscreen.h"
10 #include "eu/render/render_settings.h"
11 #include "eu/render/shader.h"
12 #include "eu/render/shader.source.h"
13
14
15 namespace eu::render
16 {
17
18
19
20 void CameraUniformBuffer::set_props(const CompiledCamera& cc) // NOLINT(readability-make-member-function-const)
21 {
22 buffer->set_mat4(clip_from_view_uni, cc.clip_from_view);
23 buffer->set_mat4(view_from_world_uni, cc.view_from_world);
24 }
25
26
27
28 LoadedShader_SingleColor::LoadedShader_SingleColor(
29 std::shared_ptr<ShaderProgram> p, core::CompiledGeomVertexAttributes l, const CameraUniformBuffer& desc
30 )
31 : program(std::move(p))
32 , geom_layout(std::move(l))
33 , tint_color_uni(program->get_uniform("u_material.diffuse_tint"))
34 , world_from_local_uni(program->get_uniform("u_world_from_local"))
35 {
36 program->setup_uniform_block(desc.setup);
37 }
38
39
40
41 LoadedShader_Skybox::LoadedShader_Skybox(
42 std::shared_ptr<ShaderProgram> p, core::CompiledGeomVertexAttributes l, const CameraUniformBuffer& desc
43 )
44 : program(std::move(p))
45 , geom_layout(std::move(l))
46 , tex_skybox_uniform(program->get_uniform("u_skybox_tex"))
47 {
48 setup_textures(program.get(), {&tex_skybox_uniform});
49 program->setup_uniform_block(desc.setup);
50 }
51
52 LoadedShader_OnlyDepth::LoadedShader_OnlyDepth(
53 TransformSource model_source,
54 std::shared_ptr<ShaderProgram> p,
55 core::CompiledGeomVertexAttributes l,
56 const CameraUniformBuffer& desc
57 )
58 : program(std::move(p))
59 , geom_layout(std::move(l))
60 , world_from_local_uni(
61 model_source == TransformSource::Uniform ? std::optional<Uniform>{program->get_uniform("u_world_from_local")}
62 : std::nullopt
63 )
64 {
65 program->setup_uniform_block(desc.setup);
66 }
67
68 LoadedShader_Unlit::LoadedShader_Unlit(
69 TransformSource model_source,
70 std::shared_ptr<ShaderProgram> p,
71 const CameraUniformBuffer& desc
72 )
73 : program(std::move(p))
74 , tint_color_uni(program->get_uniform("u_material.diffuse_tint"))
75 , tex_diffuse_uniform(program->get_uniform("u_material.diffuse_tex"))
76 , world_from_local_uni(
77 model_source == TransformSource::Uniform ? std::optional<Uniform>{program->get_uniform("u_world_from_local")} : std::nullopt
78 )
79 {
80 setup_textures(program.get(), {&tex_diffuse_uniform});
81 program->setup_uniform_block(desc.setup);
82 }
83
84
85
86 DirectionalLightUniforms::DirectionalLightUniforms(const ShaderProgram* program, const std::string& base)
87 : light_diffuse_color_uni(program->get_uniform(base + "diffuse"))
88 , light_specular_color_uni(program->get_uniform(base + "specular"))
89 , dir_uni(program->get_uniform(base + "dir"))
90 {
91 }
92
93
94
95 PointLightUniforms::PointLightUniforms(const ShaderProgram* program, const std::string& base)
96 : light_diffuse_color_uni(program->get_uniform(base + "diffuse"))
97 , light_specular_color_uni(program->get_uniform(base + "specular"))
98 , light_attenuation_uni(program->get_uniform(base + "attenuation"))
99 , light_world_uni(program->get_uniform(base + "world_pos"))
100 {
101 }
102
103
104
105 FrustumLightUniforms::FrustumLightUniforms(const ShaderProgram* program, const std::string& base)
106 : diffuse_uni(program->get_uniform(base + "diffuse"))
107 , specular_uni(program->get_uniform(base + "specular"))
108 , attenuation_uni(program->get_uniform(base + "attenuation"))
109 , clip_from_world_uni(program->get_uniform(base + "clip_from_world"))
110 , world_pos_uni(program->get_uniform(base + "world_pos"))
111 , tex_cookie_uniform(program->get_uniform(base + "cookie"))
112 {
113 }
114
115
116
117 PostProcSetup operator|(PostProcSetup lhs, PostProcSetup rhs)
118 {
119 return static_cast<PostProcSetup>(base_cast(lhs) | base_cast(rhs));
120 }
121
122
123
124 std::optional<Uniform> get_uniform(
125 ShaderProgram& prog, const std::string& name, PostProcSetup setup, PostProcSetup flag
126 )
127 {
128 if (is_flag_set(setup, flag))
129 {
130 return prog.get_uniform(name);
131 }
132 else
133 {
134 return std::nullopt;
135 }
136 }
137
138
139
140 LoadedPostProcShader::LoadedPostProcShader(std::shared_ptr<ShaderProgram> s, PostProcSetup setup)
141 : program(std::move(s))
142 , tex_input_uniform(program->get_uniform("u_texture"))
143 , factor_uni(get_uniform(*program, "u_factor", setup, PostProcSetup::factor))
144 , resolution_uni(get_uniform(*program, "u_resolution", setup, PostProcSetup::resolution))
145 , time_uni(get_uniform(*program, "u_time", setup, PostProcSetup::time))
146 {
147 setup_textures(program.get(), {&tex_input_uniform});
148 }
149
150
151
152 LoadedShader_Default::LoadedShader_Default(
153 TransformSource model_source,
154 std::shared_ptr<ShaderProgram> p,
155 const RenderSettings& settings,
156 const CameraUniformBuffer& desc
157 )
158 : program(std::move(p))
159 , tint_color_uni(program->get_uniform("u_material.diffuse_tint"))
160 , tex_directional_light_depth_uni(program->get_uniform("u_directional_light_depth_tex"))
161 , directional_shadow_clip_from_world_uni(program->get_uniform("u_directional_shadow_clip_from_world"))
162 , tex_diffuse_uniform(program->get_uniform("u_material.diffuse_tex"))
163 , tex_specular_uniform(program->get_uniform("u_material.specular_tex"))
164 , tex_emissive_uniform(program->get_uniform("u_material.emissive_tex"))
165 , ambient_tint_uni(program->get_uniform("u_material.ambient_tint"))
166 , specular_color_uni(program->get_uniform("u_material.specular_tint"))
167 , shininess_uni(program->get_uniform("u_material.shininess"))
168 , emissive_factor_uni(program->get_uniform("u_material.emissive_factor"))
169 , world_from_local_uni(
170 model_source == TransformSource::Uniform ? std::optional<Uniform>{program->get_uniform("u_world_from_local")} : std::nullopt
171 )
172 , view_position_uni(program->get_uniform("u_view_position"))
173 , light_ambient_color_uni(program->get_uniform("u_ambient_light"))
174 {
175 for (int index = 0; index < settings.number_of_directional_lights; index += 1)
176 {
177 const std::string base = fmt::format("u_directional_lights[{}].", index);
178 directional_lights.emplace_back(program.get(), base);
179 }
180
181 for (int index = 0; index < settings.number_of_point_lights; index += 1)
182 {
183 const std::string base = fmt::format("u_point_lights[{}].", index);
184 point_lights.emplace_back(program.get(), base);
185 }
186
187 for (int index = 0; index < settings.number_of_frustum_lights; index += 1)
188 {
189 const std::string base = fmt::format("u_frustum_lights[{}].", index);
190 frustum_lights.emplace_back(program.get(), base);
191 }
192
193 std::vector<Uniform*> textures = {&tex_directional_light_depth_uni, &tex_diffuse_uniform, &tex_specular_uniform, &tex_emissive_uniform};
194 for (auto& fl: frustum_lights)
195 {
196 textures.emplace_back(&fl.tex_cookie_uniform);
197 }
198
199 setup_textures(program.get(), textures);
200 program->setup_uniform_block(desc.setup);
201 }
202
203
204
205 bool LoadedShader_Unlit_Container::is_loaded() const
206 {
207 return default_shader.program->is_loaded() && transparency_shader.program->is_loaded();
208 }
209
210
211
212 const LoadedShader_Unlit& shader_from_container(const LoadedShader_Unlit_Container& container, const RenderContext& rc)
213 {
214 return rc.use_transparency == UseTransparency::yes ? container.transparency_shader : container.default_shader;
215 }
216
217 const LoadedShader_Default& shader_from_container(const LoadedShader_Default_Container& container, const RenderContext& rc)
218 {
219 switch (rc.model_source)
220 {
221 case TransformSource::Uniform:
222 return rc.use_transparency == UseTransparency::yes ? container.transparency_shader : container.default_shader;
223 case TransformSource::Instanced_mat4:
224 ASSERT(rc.use_transparency == UseTransparency::no); // not currently supporting instanced transparency
225 return container.default_shader_instance;
226 default: ASSERT(false && "unhandled"); return container.default_shader;
227 }
228 }
229
230
231
232
233 bool LoadedShader_Default_Container::is_loaded() const
234 {
235 return default_shader.program->is_loaded() && transparency_shader.program->is_loaded();
236 }
237
238
239
240
241 RealizeShader::RealizeShader(std::shared_ptr<ShaderProgram> s)
242 : program(std::move(s))
243 , tex_input_uniform(program->get_uniform("u_texture"))
244 , tex_blurred_bloom_uniform(program->get_uniform("u_blurred_bloom"))
245 , use_blur_uniform(program->get_uniform("u_use_blur"))
246 , gamma_uniform(program->get_uniform("u_gamma"))
247 , exposure_uniform(program->get_uniform("u_exposure"))
248 {
249 setup_textures(program.get(), {&tex_input_uniform, &tex_blurred_bloom_uniform});
250 }
251
252
253
254 ExtractShader::ExtractShader(std::shared_ptr<LoadedPostProcShader>&& sh)
255 : shader(std::move(sh))
256 , cutoff_uniform(shader->program->get_uniform("u_cutoff"))
257 , softness_uniform(shader->program->get_uniform("u_softness"))
258 {
259 }
260
261 PingPongBlurShader::PingPongBlurShader(std::shared_ptr<LoadedPostProcShader>&& sh)
262 : shader(std::move(sh))
263 , is_horizontal_uniform(shader->program->get_uniform("u_is_horizontal"))
264 {
265 }
266
267
268
269 bool ShaderResource::is_loaded() const
270 {
271 return single_color_shader.program->is_loaded()
272 && depth_transform_uniform.program->is_loaded()
273 && depth_transform_instanced_mat4.program->is_loaded()
274 && skybox_shader.program->is_loaded()
275 && unlit_shader_container.is_loaded()
276 && default_shader_container.is_loaded()
277 && pp_realize.program->is_loaded();
278 }
279
280
281
282 using BaseShaderData = std::vector<core::VertexType>;
283
284
285
286 template<std::size_t count>
287 BaseShaderData get_vertex_types(const std::array<const core::ShaderVertexAttributes*, count>& vas)
288 {
289 std::set<core::VertexType> unique_types;
290 auto ret = BaseShaderData{};
291 for (const auto& va: vas)
292 {
293 for (const auto& v: *va)
294 {
295 const auto [_, is_unique] = unique_types.insert(v.type);
296 if (is_unique)
297 {
298 ret.emplace_back(v.type);
299 }
300 }
301 }
302 return ret;
303 }
304
305
306
307 // todo(Gustav): should this be a tuple instead? this way the members are named
308 struct LoadedShader
309 {
310 LoadedShader(std::shared_ptr<ShaderProgram> p, core::CompiledGeomVertexAttributes l)
311 : program(std::move(p))
312 , geom_layout(std::move(l))
313 {}
314
315 std::shared_ptr<ShaderProgram> program;
316 core::CompiledGeomVertexAttributes geom_layout;
317 };
318
319 std::optional<int> get_instance_start_index(const LoadedShader* shader)
320 {
321 if (shader == nullptr)
322 {
323 return std::nullopt;
324 }
325
326 const core::CompiledGeomVertexAttributes& layout = shader->geom_layout;
327
328 int max = 0;
329
330 for (const auto& entry: layout.elements)
331 {
332 max = std::max(entry.index, max);
333 }
334
335 return max + 1;
336 }
337
338 LoadedShader load_shader(DEBUG_LABEL_ARG_MANY const BaseShaderData& base_layout, const ShaderSource_withLayout& source, TransformSource model_source, const LoadedShader* instance_base = nullptr)
339 {
340 auto layout_compiler = compile_attribute_layouts(base_layout, {source.layout});
341 const auto geom_layout = get_geom_layout(layout_compiler);
342
343 std::optional<core::InstanceProp> instance_prop = std::nullopt;
344 std::optional<int> start_index = std::nullopt;
345 switch (model_source)
346 {
347 case TransformSource::Instanced_mat4:
348 instance_prop = core::InstanceProp{core::VertexType::instance_transform, "u_world_from_local"};
349 start_index = get_instance_start_index(instance_base);
350 break;
351 case TransformSource::Uniform: break;
352 default: ASSERT(false && "unhandled ModelSource");
353 }
354
355 const auto compiled_layout = compile_shader_layout(layout_compiler, source.layout, instance_prop, start_index);
356
357 auto program = std::make_shared<ShaderProgram>(USE_DEBUG_LABEL_MANY(debug_label) source.vertex, source.fragment, compiled_layout);
358
359 return {program, geom_layout};
360 }
361
362
363
364 ShaderResource load_shaders(const Assets& assets, const CameraUniformBuffer& desc, const RenderSettings& settings, const FullScreenGeom& full_screen)
365 {
366 const auto& default_shader_source = assets.default_shader_source;
367 const auto& skybox_shader_source = assets.skybox_shader_source;
368
369 const auto single_color_shader = load_shader_source(default_shader_source, {}, desc.setup.source);
370
371 ShaderOptions depth_shader_options;
372 depth_shader_options.only_depth = true;
373 const auto depth_transform_uniform = load_shader_source(default_shader_source, depth_shader_options, desc.setup.source);
374 const auto depth_transform_instanced_mat4 = load_shader_source(default_shader_source, depth_shader_options.with_instanced_mat4(), desc.setup.source);
375
376 const auto skybox_source = load_skybox_source(skybox_shader_source, desc.setup.source);
377 const auto skybox_shader = ShaderSource_withLayout{
378 core::ShaderVertexAttributes{{core::VertexType::position3, "a_position"}}, skybox_source.vertex, skybox_source.fragment
379 };
380
381 const BaseShaderData global_shader_data = get_vertex_types<3>
382 ({
383 &single_color_shader.layout,
384 &depth_transform_uniform.layout,
385 &depth_transform_instanced_mat4.layout
386 });
387
388 ShaderOptions unlit_shader_options;
389 unlit_shader_options.use_texture = true;
390
391 ShaderOptions default_shader_options;
392 default_shader_options.use_lights = true;
393 default_shader_options.use_texture = true;
394 default_shader_options.number_of_directional_lights = settings.number_of_directional_lights;
395 default_shader_options.number_of_point_lights = settings.number_of_point_lights;
396 default_shader_options.number_of_frustum_lights = settings.number_of_frustum_lights;
397
398 auto loaded_unlit = load_shader(
399 USE_DEBUG_LABEL_MANY("unlit")
400 global_shader_data,
401 load_shader_source(default_shader_source, unlit_shader_options.with_transparent_cutoff(), desc.setup.source),
402 TransformSource::Uniform
403 );
404 auto loaded_default = load_shader(
405 USE_DEBUG_LABEL_MANY("default")
406 global_shader_data,
407 load_shader_source(default_shader_source, default_shader_options.with_transparent_cutoff(), desc.setup.source),
408 TransformSource::Uniform
409 );
410 auto loaded_default_instanced = load_shader(
411 USE_DEBUG_LABEL_MANY("default instanced")
412 global_shader_data,
413 load_shader_source(default_shader_source, default_shader_options.with_transparent_cutoff().with_instanced_mat4(), desc.setup.source),
414 TransformSource::Instanced_mat4
415 );
416
417 auto loaded_unlit_transparency = load_shader(
418 USE_DEBUG_LABEL_MANY("unlit transparency")
419 global_shader_data, load_shader_source(default_shader_source, unlit_shader_options, desc.setup.source), TransformSource::Uniform
420 );
421 auto loaded_default_transparency = load_shader(
422 USE_DEBUG_LABEL_MANY("default transparency")
423 global_shader_data, load_shader_source(default_shader_source, default_shader_options, desc.setup.source), TransformSource::Uniform
424 );
425
426 // todo(Gustav): should the asserts here be runtime errors? currently all setups are compile-time...
427 ASSERT(loaded_unlit.geom_layout.debug_types == loaded_unlit_transparency.geom_layout.debug_types);
428 ASSERT(loaded_default.geom_layout.debug_types == loaded_default_transparency.geom_layout.debug_types);
429 ASSERT(
430 loaded_default.geom_layout.debug_types == loaded_default_instanced.geom_layout.debug_types
431 ); // is this valid? should this fail?
432
433 #if 0
434
435 auto pp_invert = std::make_shared<LoadedPostProcShader>(
436 std::make_shared<ShaderProgram>(
437 USE_DEBUG_LABEL_MANY("pp invert")
438 std::string{PP_VERT_GLSL}, std::string{PP_INVERT_FRAG_GLSL}, full_screen.layout
439 ),
440 PostProcSetup::factor
441 );
442 auto pp_grayscale = std::make_shared<LoadedPostProcShader>(
443 std::make_shared<ShaderProgram>(
444 USE_DEBUG_LABEL_MANY("pp grayscale")
445 std::string{PP_VERT_GLSL}, std::string{PP_GRAYSCALE_FRAG_GLSL}, full_screen.layout
446 ),
447 PostProcSetup::factor
448 );
449 auto pp_damage = std::make_shared<LoadedPostProcShader>(
450 std::make_shared<ShaderProgram>(
451 USE_DEBUG_LABEL_MANY("pp damage")
452 std::string{PP_VERT_GLSL}, std::string{PP_DAMAGE_FRAG_GLSL}, full_screen.layout
453 ),
454 PostProcSetup::factor | PostProcSetup::resolution | PostProcSetup::time
455 );
456
457 constexpr IsGauss use_gauss =
458 #if FF_HAS(BLUR_USE_GAUSS)
459 IsGauss::yes
460 #else
461 IsGauss::no
462 #endif
463 ;
464
465 auto pp_blurv = std::make_shared<LoadedPostProcShader>(
466 std::make_shared<ShaderProgram>(
467 USE_DEBUG_LABEL_MANY("pp blur vert")
468 std::string{PP_VERT_GLSL},
469 generate_blur(PP_BLUR_FRAG_GLSL, {BlurType::vertical, BLUR_SAMPLES, use_gauss}),
470 full_screen.layout
471 ),
472 PostProcSetup::factor
473 );
474 auto pp_blurh = std::make_shared<LoadedPostProcShader>(
475 std::make_shared<ShaderProgram>(
476 USE_DEBUG_LABEL_MANY("pp blur hor")
477 std::string{PP_VERT_GLSL},
478 generate_blur(PP_BLUR_FRAG_GLSL, {BlurType::horizontal, BLUR_SAMPLES, use_gauss}),
479 full_screen.layout
480 ),
481 PostProcSetup::factor | PostProcSetup::resolution
482 );
483 #endif
484
485 auto pp_realize = RealizeShader{std::make_shared<ShaderProgram>(
486 USE_DEBUG_LABEL_MANY("pp realize")
487 assets.pp_vert_glsl, assets.pp_realize_frag_glsl, full_screen.layout
488 )};
489 auto pp_extract = ExtractShader{std::make_shared<LoadedPostProcShader>(
490 std::make_shared<ShaderProgram>(
491 USE_DEBUG_LABEL_MANY("pp extract") assets.pp_vert_glsl,
492 assets.pp_extract_frag_glsl,
493 full_screen.layout
494 ),
495 PostProcSetup::none
496 )};
497 auto pp_ping = PingPongBlurShader{std::make_shared<LoadedPostProcShader>(
498 std::make_shared<ShaderProgram>(
499 USE_DEBUG_LABEL_MANY("pp ping-pong") assets.pp_vert_glsl,
500 assets.pp_ping_pong_blur_frag_glsl,
501 full_screen.layout
502 ),
503 PostProcSetup::none
504 )};
505
506 auto loaded_single_color = load_shader(
507 USE_DEBUG_LABEL_MANY("single color") global_shader_data, single_color_shader, TransformSource::Uniform
508 );
509 auto loaded_depth_transform_uniform = load_shader(
510 USE_DEBUG_LABEL_MANY("depth transform uniform") global_shader_data, depth_transform_uniform, TransformSource::Uniform
511 );
512 auto loaded_depth_transform_instanced_mat4 = load_shader(
513 USE_DEBUG_LABEL_MANY("depth transform instanced") global_shader_data, depth_transform_instanced_mat4, TransformSource::Instanced_mat4, &loaded_default_instanced
514 );
515 auto loaded_skybox_shader
516 = load_shader(USE_DEBUG_LABEL_MANY("skybox"){}, skybox_shader, TransformSource::Uniform);
517
518
519 return ShaderResource{
520 // todo(Gustav): not really happy with sending "the same" argument twice, loaded_X.program and loaded_X.geom_layout
521 .single_color_shader = LoadedShader_SingleColor{std::move(loaded_single_color.program), loaded_single_color.geom_layout, desc},
522 .depth_transform_uniform = LoadedShader_OnlyDepth{
523 TransformSource::Uniform, std::move(loaded_depth_transform_uniform.program),
524 loaded_depth_transform_uniform.geom_layout,
525 desc
526 },
527 .depth_transform_instanced_mat4 = LoadedShader_OnlyDepth{
528 TransformSource::Instanced_mat4,
529 std::move(loaded_depth_transform_instanced_mat4.program),
530 loaded_depth_transform_instanced_mat4.geom_layout,
531 desc
532 },
533 .skybox_shader = LoadedShader_Skybox{std::move(loaded_skybox_shader.program), loaded_skybox_shader.geom_layout, desc},
534 .unlit_shader_container = LoadedShader_Unlit_Container{
535 loaded_unlit.geom_layout,
536 LoadedShader_Unlit{TransformSource::Uniform, std::move(loaded_unlit.program), desc},
537 LoadedShader_Unlit{TransformSource::Uniform, std::move(loaded_unlit_transparency.program), desc}
538 },
539 .default_shader_container = LoadedShader_Default_Container{
540 loaded_default.geom_layout,
541 LoadedShader_Default{TransformSource::Uniform, std::move(loaded_default.program), settings, desc},
542 LoadedShader_Default{TransformSource::Uniform, std::move(loaded_default_transparency.program), settings, desc},
543 LoadedShader_Default{TransformSource::Instanced_mat4, std::move(loaded_default_instanced.program), settings, desc}
544 },
545 // .pp_invert = pp_invert,
546 // .pp_grayscale = pp_grayscale,
547 // .pp_damage = pp_damage,
548 // .pp_blurv = pp_blurv,
549 // .pp_blurh = pp_blurh,
550 .pp_realize = pp_realize,
551 .pp_extract = pp_extract,
552 .pp_ping = pp_ping
553 };
554 }
555
556
557
558 } // namespace eu::render
559