./
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
0 / 384
0.0%
Branches:
0 / 478
0.0%
Functions:
0 / 41
0.0%

libs/render/src/eu/render/postproc.cc
Line Branch Exec Source
1 #include "eu/render/postproc.h"
2
3 #include "eu/assert/assert.h"
4
5 #include "eu/log/log.h"
6
7 #include "eu/render/opengl_utils.h"
8 #include "eu/render/postproc.internal.h"
9 #include "eu/render/renderer.h"
10 #include "eu/render/renderer.pimpl.h"
11 #include "eu/render/shader_resource.h"
12 #include "eu/render/shader.h"
13 #include "eu/render/state.h"
14 #include "eu/render/camera.h"
15 #include "eu/render/shadow.h"
16
17 #if FF_HAS(EU_DEBUG_RUNNER)
18 #include "eu/imgui/ui.h"
19 #include "dear_imgui/imgui.h"
20 #endif
21
22
23 namespace eu::render
24 {
25
26
27 ///////////////////////////////////////////////////////////////////////////////////////////////////
28 // Effect
29
30 ✗ bool Effect::enabled() const
31 {
32 ✗ return is_enabled;
33 }
34
35 ✗ void Effect::set_enabled(bool n)
36 {
37
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ if (is_enabled == n)
38 {
39 ✗ return;
40 }
41
42 ✗ is_enabled = n;
43
0/2
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 6 not taken.
✗ if (owner != nullptr)
44 {
45 ✗ owner->dirty = true;
46 }
47 }
48
49
50 ///////////////////////////////////////////////////////////////////////////////////////////////////
51 // RenderWorld
52
53 // todo(Gustav): should this be a user config option? evaluate higher/lower bits, probably 16 or 32 since it needs to be floating point for hdr
54 constexpr ColorBitsPerPixel render_world_color_bits_per_pixel = ColorBitsPerPixel::use_16;
55
56 ✗ static std::optional<BloomRender> build_bloom(const Size& size, ExtractShader* sh, PingPongBlurShader* ping_sh)
57 {
58
0/2
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 4 not taken.
✗ if (sh == nullptr) { return std::nullopt; }
59
60
0/4
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 36 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 34 not taken.
✗ auto bloom_buffer = build_simple_framebuffer(USE_DEBUG_LABEL_MANY("bloom extraction buffer") size);
61
62
0/4
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 42 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 40 not taken.
✗ auto ping_one = build_simple_framebuffer(USE_DEBUG_LABEL_MANY("ping-pong bloom buffer one") size);
63
0/4
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 48 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 46 not taken.
✗ auto ping_two = build_simple_framebuffer(USE_DEBUG_LABEL_MANY("ping-pong bloom buffer two") size);
64
65
0/2
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
✗ return BloomRender
66 {
67 .extract_shader = sh,
68 .bloom_buffer = bloom_buffer,
69 .ping_pong_shader = ping_sh,
70 .ping_pong_buffer = {ping_one, ping_two}
71 ✗ };
72 ✗ }
73
74 ✗ RenderWorld::RenderWorld(const Size& size, RealizeShader* re_sh, ExtractShader* ex_sh, PingPongBlurShader* ping_sh, int msaa_samples, bool* h, float* e)
75 ✗ : window_size(size)
76 ✗ , use_hdr(h)
77 ✗ , exposure(e)
78
0/4
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 34 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 32 not taken.
✗ , msaa_buffer(build_msaa_framebuffer(USE_DEBUG_LABEL_MANY("msaa buffer")
79 size, msaa_samples, render_world_color_bits_per_pixel))
80
0/4
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 40 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 38 not taken.
✗ , realized_buffer(build_hdr_floating_framebuffer(USE_DEBUG_LABEL_MANY("realized msaa buffer") size, render_world_color_bits_per_pixel))
81 ✗ , realize_shader(re_sh)
82
0/2
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 52 not taken.
✗ , bloom_render(build_bloom(size, ex_sh, ping_sh))
83 ✗ , last_bloom_blur_index(0)
84 {
85
0/8
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 24 not taken.
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 50 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 24 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 44 not taken.
✗ ASSERT(use_hdr);
86
0/8
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 31 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 50 not taken.
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 31 not taken.
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 47 not taken.
✗ ASSERT(exposure);
87 ✗ }
88
89 ✗ void RenderWorld::update(const PostProcArg& arg)
90 {
91 // render shadow buffer
92 ✗ const auto shadow_size = arg.renderer->settings.shadow_map_resolution;
93 {
94 ✗ bool update_shadow_buffer = shadow_buffer == nullptr;
95
0/6
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 9 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 9 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
✗ if (shadow_buffer && shadow_buffer->size != shadow_size)
96 {
97 ✗ update_shadow_buffer = true;
98 }
99
100
0/2
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 22 not taken.
✗ if (update_shadow_buffer)
101 {
102
0/4
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 156 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 154 not taken.
✗ shadow_buffer = build_shadow_framebuffer(USE_DEBUG_LABEL_MANY("shadow buffer") shadow_size);
103 }
104 }
105
106 ✗ std::optional<CompiledCamera> opt_compiled_shadow_camera;
107
108
0/2
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 38 not taken.
✗ if (arg.world->lights.directional_lights.empty() == false)
109 {
110
0/2
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 169 not taken.
✗ SCOPED_DEBUG_GROUP("render shadow buffer"sv);
111
112 ✗ const auto compiled_shadow_camera = compile_the_shadow_camera(
113
0/2
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 167 not taken.
✗ *arg.camera, window_size, arg.world->lights.directional_lights[0], arg.renderer->settings, *arg.world
114 );
115
116
0/2
✗ Branch 29 → 30 not taken.
✗ Branch 29 → 161 not taken.
✗ auto bound = BoundFbo{shadow_buffer};
117 ✗ set_gl_viewport({
118 ✗ .width = shadow_buffer->size.width,
119
0/2
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 164 not taken.
✗ .height = shadow_buffer->size.height
120 });
121
0/2
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 165 not taken.
✗ arg.renderer->render_shadows(shadow_size, *arg.world, compiled_shadow_camera);
122 ✗ }
123
124 // render into msaa buffer
125 {
126
0/2
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 179 not taken.
✗ SCOPED_DEBUG_GROUP("rendering into msaa buffer"sv);
127
128
0/2
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 46 not taken.
✗ const ShadowContext shadow_context = opt_compiled_shadow_camera ? ShadowContext{
129 ✗ .directional_shadow_map = shadow_buffer.get(),
130
0/2
✗ Branch 45 → 47 not taken.
✗ Branch 45 → 177 not taken.
✗ .directional_shadow_clip_from_world = opt_compiled_shadow_camera->clip_from_view * opt_compiled_shadow_camera->view_from_world
131 } : ShadowContext{
132 .directional_shadow_map = nullptr,
133 .directional_shadow_clip_from_world = m4_identity
134 ✗ };
135
136
0/2
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 170 not taken.
✗ auto bound = BoundFbo{msaa_buffer};
137 ✗ set_gl_viewport({
138 ✗ .width = msaa_buffer->size.width,
139
0/2
✗ Branch 52 → 53 not taken.
✗ Branch 52 → 173 not taken.
✗ .height = msaa_buffer->size.height
140 });
141
0/4
✗ Branch 53 → 54 not taken.
✗ Branch 53 → 174 not taken.
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 174 not taken.
✗ arg.renderer->render_world(window_size, *arg.world, compile(*arg.camera, window_size), shadow_context);
142 ✗ }
143
144 // copy msaa buffer to realized
145 {
146
0/2
✗ Branch 58 → 59 not taken.
✗ Branch 58 → 182 not taken.
✗ SCOPED_DEBUG_GROUP("resolving msaa buffer"sv);
147
0/2
✗ Branch 61 → 62 not taken.
✗ Branch 61 → 180 not taken.
✗ resolve_multisampled_buffer(*msaa_buffer, realized_buffer.get());
148 ✗ }
149
150 // extract overexposed
151
0/2
✗ Branch 64 → 65 not taken.
✗ Branch 64 → 153 not taken.
✗ if (bloom_render.has_value())
152 {
153 // extract overexposed pixels
154 {
155
0/2
✗ Branch 66 → 67 not taken.
✗ Branch 66 → 191 not taken.
✗ SCOPED_DEBUG_GROUP("extracting to overexposed buffer"sv);
156
0/2
✗ Branch 68 → 69 not taken.
✗ Branch 68 → 183 not taken.
✗ StateChanger{arg.renderer->pimpl->states}
157
0/2
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 183 not taken.
✗ .cull_face(false)
158
0/2
✗ Branch 70 → 71 not taken.
✗ Branch 70 → 183 not taken.
✗ .stencil_test(false)
159
0/2
✗ Branch 71 → 72 not taken.
✗ Branch 71 → 183 not taken.
✗ .depth_test(false)
160
0/2
✗ Branch 72 → 73 not taken.
✗ Branch 72 → 183 not taken.
✗ .depth_mask(false)
161
0/2
✗ Branch 73 → 74 not taken.
✗ Branch 73 → 183 not taken.
✗ .blending(false);
162
163
0/2
✗ Branch 74 → 75 not taken.
✗ Branch 74 → 189 not taken.
✗ glClearColor(0, 0, 0, 1.0f);
164
0/2
✗ Branch 75 → 76 not taken.
✗ Branch 75 → 189 not taken.
✗ glClear(GL_COLOR_BUFFER_BIT);
165
166 // todo(Gustav): why bind this late... shouldn't this be first???
167
0/2
✗ Branch 78 → 79 not taken.
✗ Branch 78 → 184 not taken.
✗ auto bound = BoundFbo{bloom_render->bloom_buffer};
168
169 {
170 ✗ const auto& container = bloom_render->extract_shader;
171 ✗ const auto& shader = container->shader;
172 ✗ const auto& program = shader->program;
173
0/2
✗ Branch 83 → 84 not taken.
✗ Branch 83 → 187 not taken.
✗ program->use();
174
0/2
✗ Branch 85 → 86 not taken.
✗ Branch 85 → 187 not taken.
✗ program->set_float(container->cutoff_uniform, arg.renderer->settings.bloom_cutoff);
175
0/2
✗ Branch 87 → 88 not taken.
✗ Branch 87 → 187 not taken.
✗ program->set_float(container->softness_uniform, arg.renderer->settings.bloom_softness);
176
0/2
✗ Branch 91 → 92 not taken.
✗ Branch 91 → 187 not taken.
✗ bind_texture_2d(arg.renderer->pimpl->states, shader->tex_input_uniform, *realized_buffer);
177
178
0/2
✗ Branch 94 → 95 not taken.
✗ Branch 94 → 187 not taken.
✗ render_geom(*arg.renderer->pimpl->full_screen_geom);
179 }
180 ✗ }
181
182 // blur the buffers
183 {
184
0/2
✗ Branch 98 → 99 not taken.
✗ Branch 98 → 208 not taken.
✗ SCOPED_DEBUG_GROUP("blur extracted pixels for bloom"sv);
185 ✗ bool is_horizontal = true;
186
0/2
✗ Branch 150 → 100 not taken.
✗ Branch 150 → 151 not taken.
✗ for (int blur_iteration = 0; blur_iteration < arg.renderer->settings.bloom_blur_steps; blur_iteration += 1)
187 {
188 ✗ const auto is_first_iteration = blur_iteration == 0;
189
190
0/2
✗ Branch 100 → 101 not taken.
✗ Branch 100 → 102 not taken.
✗ const std::size_t source_index = is_horizontal ? 1 : 0;
191
0/2
✗ Branch 103 → 104 not taken.
✗ Branch 103 → 105 not taken.
✗ const std::size_t target_index = is_horizontal ? 0 : 1;
192 ✗ last_bloom_blur_index = target_index;
193
194
0/8
✗ Branch 106 → 107 not taken.
✗ Branch 106 → 108 not taken.
✗ Branch 109 → 110 not taken.
✗ Branch 109 → 111 not taken.
✗ Branch 112 → 113 not taken.
✗ Branch 112 → 194 not taken.
✗ Branch 113 → 114 not taken.
✗ Branch 113 → 192 not taken.
✗ SCOPED_DEBUG_GROUP(
195 fmt::format("blur pass #{} ({}, {})",
196 blur_iteration,
197 (is_horizontal ? "hori" : "vert"),
198 (is_first_iteration ? "first" : "after"))
199 );
200
0/2
✗ Branch 118 → 119 not taken.
✗ Branch 118 → 196 not taken.
✗ auto bound = BoundFbo{bloom_render->ping_pong_buffer[target_index]};
201
0/2
✗ Branch 121 → 122 not taken.
✗ Branch 121 → 199 not taken.
✗ StateChanger{arg.renderer->pimpl->states}
202
0/2
✗ Branch 122 → 123 not taken.
✗ Branch 122 → 199 not taken.
✗ .cull_face(false)
203
0/2
✗ Branch 123 → 124 not taken.
✗ Branch 123 → 199 not taken.
✗ .stencil_test(false)
204
0/2
✗ Branch 124 → 125 not taken.
✗ Branch 124 → 199 not taken.
✗ .depth_test(false)
205
0/2
✗ Branch 125 → 126 not taken.
✗ Branch 125 → 199 not taken.
✗ .depth_mask(false)
206
0/2
✗ Branch 126 → 127 not taken.
✗ Branch 126 → 199 not taken.
✗ .blending(false);
207
208
0/2
✗ Branch 127 → 128 not taken.
✗ Branch 127 → 200 not taken.
✗ glClearColor(0, 0, 0, 1.0f);
209
0/2
✗ Branch 128 → 129 not taken.
✗ Branch 128 → 200 not taken.
✗ glClear(GL_COLOR_BUFFER_BIT);
210
211 {
212 ✗ const auto& container = bloom_render->ping_pong_shader;
213 ✗ const auto& shader = container->shader;
214 ✗ const auto& program = shader->program;
215
0/2
✗ Branch 132 → 133 not taken.
✗ Branch 132 → 200 not taken.
✗ program->use();
216
0/2
✗ Branch 134 → 135 not taken.
✗ Branch 134 → 200 not taken.
✗ program->set_bool(container->is_horizontal_uniform, is_horizontal);
217
218
0/2
✗ Branch 135 → 136 not taken.
✗ Branch 135 → 138 not taken.
✗ auto& src_texture = is_first_iteration ? bloom_render->bloom_buffer
219 ✗ : bloom_render->ping_pong_buffer[source_index];
220
0/2
✗ Branch 143 → 144 not taken.
✗ Branch 143 → 200 not taken.
✗ bind_texture_2d(arg.renderer->pimpl->states, shader->tex_input_uniform, *src_texture);
221
222
0/2
✗ Branch 146 → 147 not taken.
✗ Branch 146 → 200 not taken.
✗ render_geom(*arg.renderer->pimpl->full_screen_geom);
223 }
224
225 ✗ is_horizontal = ! is_horizontal;
226 ✗ }
227 ✗ }
228 }
229
230 // blur overexposed using ping-pong gaussian blur
231 ✗ }
232
233 ✗ void RenderWorld::render(const PostProcArg& arg)
234 {
235 // render realized (with shader)
236
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 63 not taken.
✗ SCOPED_DEBUG_GROUP("render realized msaa buffer"sv);
237
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 54 not taken.
✗ StateChanger{arg.renderer->pimpl->states}
238
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 54 not taken.
✗ .cull_face(false)
239
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 54 not taken.
✗ .stencil_test(false)
240
0/2
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 54 not taken.
✗ .depth_test(false)
241
0/2
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 54 not taken.
✗ .depth_mask(false)
242
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 54 not taken.
✗ .blending(false);
243
244
0/2
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 61 not taken.
✗ glClearColor(0, 0, 0, 1.0f);
245
0/2
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 61 not taken.
✗ glClear(GL_COLOR_BUFFER_BIT);
246
247
0/8
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 20 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 61 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 20 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 55 not taken.
✗ ASSERT(use_hdr);
248
0/8
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 27 not taken.
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 61 not taken.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 27 not taken.
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 58 not taken.
✗ ASSERT(exposure);
249
250 {
251 ✗ const auto& container = realize_shader;
252 ✗ const auto& program = container->program;
253
0/2
✗ Branch 28 → 29 not taken.
✗ Branch 28 → 61 not taken.
✗ program->use();
254
0/2
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 61 not taken.
✗ program->set_float(container->gamma_uniform, arg.renderer->settings.gamma);
255
0/4
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 34 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 61 not taken.
✗ program->set_float(container->exposure_uniform, *use_hdr ? *exposure : -1.0f);
256
0/2
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 61 not taken.
✗ program->set_bool(container->use_blur_uniform, bloom_render.has_value());
257
0/2
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 61 not taken.
✗ bind_texture_2d(arg.renderer->pimpl->states, container->tex_input_uniform, *realized_buffer);
258
0/2
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 49 not taken.
✗ if (bloom_render.has_value())
259 {
260
0/2
✗ Branch 48 → 49 not taken.
✗ Branch 48 → 61 not taken.
✗ bind_texture_2d(arg.renderer->pimpl->states, container->tex_blurred_bloom_uniform, *bloom_render->ping_pong_buffer[last_bloom_blur_index]);
261 }
262
263
0/2
✗ Branch 51 → 52 not taken.
✗ Branch 51 → 61 not taken.
✗ render_geom(*arg.renderer->pimpl->full_screen_geom);
264 }
265 ✗ }
266
267
268
269 ✗ void RenderWorld::gui(imgui::ImguiShaderCache* cache, const imgui::PropTable& prop)
270 {
271 // todo(Gustav): refactor
272 #if FF_HAS(EU_DEBUG_RUNNER)
273
0/6
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 8 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 8 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 21 not taken.
✗ if (bloom_render && bloom_render->bloom_buffer)
274 {
275 ✗ prop.image("bloom buffer", *bloom_render->bloom_buffer, cache, imgui::ImageShader::tonemap_and_gamma);
276
277 ✗ prop.image("ping-pong A", *bloom_render->ping_pong_buffer[0], cache, imgui::ImageShader::tonemap_and_gamma);
278 ✗ prop.image("ping-pong B", *bloom_render->ping_pong_buffer[1], cache, imgui::ImageShader::tonemap_and_gamma);
279 }
280 #endif
281 ✗ }
282
283
284 ///////////////////////////////////////////////////////////////////////////////////////////////////
285 // RenderTextureWithShader
286
287 ✗ RenderTextureWithShader::RenderTextureWithShader(std::string n, std::shared_ptr<RenderSource> s, std::shared_ptr<FrameBuffer> f, ShaderPropertyProvider* e)
288 ✗ : name(std::move(n))
289 ✗ , source(std::move(s))
290 ✗ , fbo(std::move(f))
291 ✗ , effect(e)
292 {
293
0/8
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 19 not taken.
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 23 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 19 not taken.
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 20 not taken.
✗ ASSERT(effect);
294 ✗ }
295
296 ✗ void RenderTextureWithShader::render(const PostProcArg& arg)
297 {
298
0/8
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 9 not taken.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 38 not taken.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 9 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 28 not taken.
✗ ASSERT(effect);
299
300
0/4
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 33 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 31 not taken.
✗ SCOPED_DEBUG_GROUP(fmt::format("Rendering task {}", name));
301
302
0/2
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 35 not taken.
✗ StateChanger{arg.renderer->pimpl->states}
303
0/2
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 35 not taken.
✗ .cull_face(false)
304
0/2
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 35 not taken.
✗ .stencil_test(false)
305
0/2
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 35 not taken.
✗ .depth_test(false)
306
0/2
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 35 not taken.
✗ .depth_mask(false)
307
0/2
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 35 not taken.
✗ .blending(false);
308
309
0/2
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 36 not taken.
✗ glClearColor(0, 0, 0, 1.0f);
310
0/2
✗ Branch 20 → 21 not taken.
✗ Branch 20 → 36 not taken.
✗ glClear(GL_COLOR_BUFFER_BIT);
311
312
0/2
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 36 not taken.
✗ effect->use_shader(arg, *fbo);
313
0/2
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 36 not taken.
✗ render_geom(*arg.renderer->pimpl->full_screen_geom);
314 ✗ }
315
316 ✗ void RenderTextureWithShader::update(const PostProcArg& arg)
317 {
318
0/4
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 17 not taken.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 15 not taken.
✗ SCOPED_DEBUG_GROUP(fmt::format("Updating task {}", name));
319
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 19 not taken.
✗ auto bound = BoundFbo{fbo};
320
0/2
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 22 not taken.
✗ set_gl_viewport(fbo->size);
321
0/2
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 22 not taken.
✗ source->render(arg);
322 ✗ }
323
324
325 ///////////////////////////////////////////////////////////////////////////////////////////////////
326 // EffectStack
327
328 ✗ void EffectStack::update(float dt) const
329 {
330
0/2
✗ Branch 20 → 4 not taken.
✗ Branch 20 → 21 not taken.
✗ for (const auto& e: effects)
331 {
332
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 9 not taken.
✗ if (e->is_enabled == false)
333 {
334 ✗ continue;
335 }
336
337
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 22 not taken.
✗ e->update(dt);
338 }
339 ✗ }
340
341 ✗ void EffectStack::render(const PostProcArg& arg)
342 {
343 // todo(Gustav): owners are only used when we have added an effect and the effect can change dirty flag
344 // make this a requirement when creating the effect instead and remove this loop?
345
0/2
✗ Branch 19 → 4 not taken.
✗ Branch 19 → 20 not taken.
✗ for (const auto& e: effects)
346 {
347
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 10 not taken.
✗ if (e->owner != this)
348 {
349 ✗ e->owner = this;
350 ✗ dirty = true;
351 }
352 }
353
354
0/2
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 23 not taken.
✗ if (render_world == nullptr)
355 {
356 ✗ dirty = true;
357 }
358
359
0/6
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 28 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
✗ Branch 30 → 31 not taken.
✗ Branch 30 → 33 not taken.
✗ if (window_size.has_value() == false || *window_size != arg.window_size)
360 {
361 ✗ window_size = arg.window_size;
362 ✗ dirty = true;
363 }
364
365 {
366 ✗ const auto latest_msaa = arg.renderer->settings.msaa;
367
0/2
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 35 not taken.
✗ if (current_msaa_setting != latest_msaa)
368 {
369 ✗ current_msaa_setting = latest_msaa;
370 ✗ dirty = true;
371 }
372 }
373
374 ✗ const auto should_use_bloom = arg.renderer->settings.use_bloom;
375 {
376
0/4
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 41 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 41 not taken.
✗ const auto is_currently_using_bloom = render_world && render_world->bloom_render.has_value();
377
0/2
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 44 not taken.
✗ if (is_currently_using_bloom != should_use_bloom)
378 {
379 ✗ dirty = true;
380 }
381 }
382
383 // if dirty, update the compiled state
384
0/2
✗ Branch 44 → 45 not taken.
✗ Branch 44 → 83 not taken.
✗ if (dirty)
385 {
386 ✗ dirty = false;
387
0/6
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 127 not taken.
✗ Branch 46 → 47 not taken.
✗ Branch 46 → 116 not taken.
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 114 not taken.
✗ LOG_INFO("Building effects stack");
388
389 ✗ compiled.targets.clear();
390
391 auto created_world = std::make_shared<RenderWorld>(
392 ✗ arg.window_size,
393 ✗ &arg.renderer->pimpl->shaders_resources.pp_realize,
394 ✗ should_use_bloom ? &arg.renderer->pimpl->shaders_resources.pp_extract : nullptr,
395
0/2
✗ Branch 54 → 55 not taken.
✗ Branch 54 → 57 not taken.
✗ should_use_bloom ? &arg.renderer->pimpl->shaders_resources.pp_ping : nullptr,
396 ✗ current_msaa_setting,
397 ✗ &use_hdr,
398
0/2
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 53 not taken.
✗ &exposure
399
0/2
✗ Branch 59 → 60 not taken.
✗ Branch 59 → 118 not taken.
✗ );
400 ✗ compiled.last_source = created_world;
401 ✗ render_world = created_world;
402
403
0/2
✗ Branch 80 → 64 not taken.
✗ Branch 80 → 81 not taken.
✗ for (auto& e: effects)
404 {
405
0/2
✗ Branch 67 → 68 not taken.
✗ Branch 67 → 71 not taken.
✗ if (e->is_enabled)
406 {
407 ✗ e->build({
408
0/2
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 123 not taken.
✗ .builder = &compiled,
409 .window_size = arg.window_size
410 });
411 }
412 }
413 ✗ }
414
415 // the stack is now compiled
416 // before rendering, update all targets/fbos and present
417 {
418
0/2
✗ Branch 84 → 85 not taken.
✗ Branch 84 → 130 not taken.
✗ SCOPED_DEBUG_GROUP("updating postproc render_world"sv);
419
0/2
✗ Branch 86 → 87 not taken.
✗ Branch 86 → 128 not taken.
✗ render_world->update(arg);
420 ✗ }
421
422 {
423
0/2
✗ Branch 89 → 90 not taken.
✗ Branch 89 → 134 not taken.
✗ SCOPED_DEBUG_GROUP("rendering postproc actions"sv);
424
0/2
✗ Branch 105 → 92 not taken.
✗ Branch 105 → 106 not taken.
✗ for (const auto& action: compiled.targets)
425 {
426
0/2
✗ Branch 95 → 96 not taken.
✗ Branch 95 → 131 not taken.
✗ action->update(arg);
427 }
428 ✗ }
429
430 // render the final image to the screen
431 {
432
0/2
✗ Branch 108 → 109 not taken.
✗ Branch 108 → 137 not taken.
✗ SCOPED_DEBUG_GROUP("rendering postproc to screen"sv);
433
0/2
✗ Branch 109 → 110 not taken.
✗ Branch 109 → 135 not taken.
✗ set_gl_viewport(arg.final_rect);
434
0/2
✗ Branch 111 → 112 not taken.
✗ Branch 111 → 135 not taken.
✗ compiled.last_source->render(arg);
435 ✗ }
436 ✗ }
437
438 ✗ void EffectStack::gui(imgui::ImguiShaderCache* cache, const imgui::PropTable& prop)
439 {
440 #if FF_HAS(EU_DEBUG_RUNNER)
441 ✗ prop.check("HDR", &use_hdr);
442 ✗ prop.slider("Exposure", &exposure, 0.01f, 20.0f);
443
444
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 8 not taken.
✗ if (render_world)
445 {
446 ✗ render_world->gui(cache, prop);
447 }
448 #endif
449 ✗ }
450
451 ✗ void EffectStack::gui_effects()
452 {
453 #if FF_HAS(EU_DEBUG_RUNNER)
454 ✗ int index = 0;
455
0/2
✗ Branch 19 → 4 not taken.
✗ Branch 19 → 20 not taken.
✗ for (const auto& e: effects)
456 {
457
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 21 not taken.
✗ ImGui::PushID(index);
458
0/2
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 21 not taken.
✗ e->gui();
459
0/2
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 21 not taken.
✗ ImGui::PopID();
460 ✗ index += 1;
461 }
462 #endif
463 ✗ }
464
465
466 ///////////////////////////////////////////////////////////////////////////////////////////////////
467 // FactorEffect
468
469 ✗ FactorEffect::FactorEffect()
470 {
471 ✗ set_enabled(false);
472 ✗ }
473
474 ✗ float FactorEffect::get_factor() const
475 {
476 ✗ return factor;
477 }
478
479 ✗ void FactorEffect::set_factor(float f)
480 {
481 ✗ factor = f;
482 ✗ set_enabled(factor > kk::almost_zero);
483 ✗ }
484
485
486
487 ///////////////////////////////////////////////////////////////////////////////////////////////////
488 // FloatDragShaderProp
489
490 ✗ FloatDragShaderProp::FloatDragShaderProp(const LoadedPostProcShader& shader, const std::string& n, float v, float s)
491
0/2
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 9 not taken.
✗ : uniform(shader.program->get_uniform(n))
492
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
✗ , name(n)
493 ✗ , value(v)
494 ✗ , speed(s)
495 {
496 ✗ }
497
498 ✗ void FloatDragShaderProp::use(const PostProcArg&, ShaderProgram& shader)
499 {
500 ✗ shader.set_float(uniform, value);
501 ✗ }
502
503 ✗ void FloatDragShaderProp::gui(const imgui::PropTable& prop)
504 {
505 #if FF_HAS(EU_DEBUG_RUNNER)
506 ✗ prop.drag(name.c_str(), &value, speed);
507 #endif
508 ✗ }
509
510
511
512 ///////////////////////////////////////////////////////////////////////////////////////////////////
513 // FloatSliderShaderProp
514
515 ✗ FloatSliderShaderProp::FloatSliderShaderProp(
516 const LoadedPostProcShader& shader, const std::string& n, float v, float mi, float ma
517 ✗ )
518
0/2
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 9 not taken.
✗ : uniform(shader.program->get_uniform(n))
519
0/2
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 7 not taken.
✗ , name(n)
520 ✗ , value(v)
521 ✗ , min(mi)
522 ✗ , max(ma)
523 {
524 ✗ }
525
526 ✗ void FloatSliderShaderProp::use(const PostProcArg&, ShaderProgram& shader)
527 {
528 ✗ shader.set_float(uniform, value);
529 ✗ }
530
531 ✗ void FloatSliderShaderProp::gui(const imgui::PropTable& prop)
532 {
533 #if FF_HAS(EU_DEBUG_RUNNER)
534 ✗ prop.slider(name.c_str(), &value, min, max);
535 #endif
536 ✗ }
537
538
539 ///////////////////////////////////////////////////////////////////////////////////////////////////
540 // SimpleEffect
541
542 ✗ SimpleEffect::SimpleEffect(std::string n, std::shared_ptr<LoadedPostProcShader> s)
543 ✗ : name(std::move(n))
544 ✗ , shader(std::move(s))
545 {
546
0/8
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 20 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 24 not taken.
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 20 not taken.
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 21 not taken.
✗ ASSERT(shader->factor_uni.has_value());
547 ✗ }
548
549 ✗ void SimpleEffect::add_float_drag_prop(const std::string& prop_name, float value, float speed)
550 {
551
0/4
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 9 not taken.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 7 not taken.
✗ properties.emplace_back(std::make_shared<FloatDragShaderProp>(*shader, prop_name, value, speed));
552 ✗ }
553
554 ✗ void SimpleEffect::add_float_slider_prop(const std::string& prop_name, float value, float min, float max)
555 {
556
0/4
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 9 not taken.
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 7 not taken.
✗ properties.emplace_back(std::make_shared<FloatSliderShaderProp>(*shader, prop_name, value, min, max));
557 ✗ }
558
559 ✗ void SimpleEffect::gui()
560 {
561 #if FF_HAS(EU_DEBUG_RUNNER)
562
0/2
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 5 not taken.
✗ if (properties.empty())
563 {
564 ✗ return;
565 }
566
567 ✗ int index = 0;
568
569
570
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 32 not taken.
✗ if (eu::imgui::header((name.c_str())))
571 {
572
0/4
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 36 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 30 not taken.
✗ if (const auto prop = eu::imgui::PropTable::begin())
573 {
574
0/2
✗ Branch 28 → 13 not taken.
✗ Branch 28 → 29 not taken.
✗ for (auto& p : properties)
575 {
576
0/2
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 33 not taken.
✗ ImGui::PushID(index);
577
0/2
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 33 not taken.
✗ p->gui(prop);
578
0/2
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 33 not taken.
✗ ImGui::PopID();
579 ✗ index += 1;
580 }
581
582 ✗ }
583 }
584 #endif
585 }
586
587 ✗ void SimpleEffect::update(float dt)
588 {
589 ✗ time += dt;
590 ✗ }
591
592 ✗ static v2 v2_from_size(const Size& s)
593 {
594 ✗ return { float_from_int(s.width), float_from_int(s.height) };
595 }
596
597 ✗ void SimpleEffect::use_shader(const PostProcArg& a, const FrameBuffer& t)
598 {
599 ✗ shader->program->use();
600
601 ✗ const auto& shader_factor = shader->factor_uni;
602 ✗ const auto& shader_resolution = shader->resolution_uni;
603 ✗ const auto& shader_time = shader->time_uni;
604
605
0/2
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 15 not taken.
✗ if (shader_factor)
606 {
607 ✗ shader->program->set_float(*shader_factor, get_factor());
608 }
609
0/2
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 23 not taken.
✗ if (shader_resolution)
610 {
611
0/2
✗ Branch 21 → 22 not taken.
✗ Branch 21 → 51 not taken.
✗ shader->program->set_vec2(*shader_resolution, v2_from_size(a.window_size));
612 }
613
0/2
✗ Branch 24 → 25 not taken.
✗ Branch 24 → 29 not taken.
✗ if (shader_time)
614 {
615 ✗ shader->program->set_float(*shader_time, time);
616 }
617
0/2
✗ Branch 46 → 31 not taken.
✗ Branch 46 → 47 not taken.
✗ for (auto& p: properties)
618 {
619
0/2
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 52 not taken.
✗ p->use(a, *shader->program);
620 }
621 ✗ bind_texture_2d(a.renderer->pimpl->states, shader->tex_input_uniform, t);
622 ✗ }
623
624 ✗ void SimpleEffect::build(const BuildArg& arg)
625 {
626 ✗ time = 0.0f;
627
628 // todo(Gustav): reuse buffers created from an earlier postproc build
629 // todo(Gustav): reuse buffers from earlier in the postproc stack, that aren't in use
630
0/4
✗ Branch 2 → 3 not taken.
✗ Branch 2 → 15 not taken.
✗ Branch 3 → 4 not taken.
✗ Branch 3 → 13 not taken.
✗ auto fbo = build_simple_framebuffer(USE_DEBUG_LABEL_MANY(fmt::format("fbo for {}", name)) arg.window_size);
631
632 ✗ auto src = arg.builder->last_source;
633
0/2
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 17 not taken.
✗ auto target = std::make_shared<RenderTextureWithShader>(name, src, fbo, this);
634
635
0/2
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 18 not taken.
✗ arg.builder->targets.emplace_back(target);
636 ✗ arg.builder->last_source = target;
637 ✗ }
638
639
640
641 ///////////////////////////////////////////////////////////////////////////////////////////////////
642 // VertProvider
643
644 ✗ BlurVerticalProvider::BlurVerticalProvider(BlurEffect* b)
645 ✗ : blur(b)
646 {
647 ✗ }
648
649
650 ✗ void BlurVerticalProvider::use_shader(const PostProcArg& a, const FrameBuffer& t)
651 {
652 ✗ blur->use_vert_shader(a, t);
653 ✗ }
654
655
656
657 ///////////////////////////////////////////////////////////////////////////////////////////////////
658 // HoriProvider
659
660 ✗ BurHorizontalProvider::BurHorizontalProvider(BlurEffect* b)
661 ✗ : blur(b)
662 {
663 ✗ }
664
665 ✗ void BurHorizontalProvider::use_shader(const PostProcArg& a, const FrameBuffer& t)
666 {
667 ✗ blur->use_hori_shader(a, t);
668 ✗ }
669
670
671
672
673 ///////////////////////////////////////////////////////////////////////////////////////////////////
674 // BlurEffect
675
676
677 ✗ BlurEffect::BlurEffect(std::string n, std::shared_ptr<LoadedPostProcShader> v, std::shared_ptr<LoadedPostProcShader> h)
678 ✗ : name(std::move(n))
679 ✗ , vert_p(this)
680 ✗ , hori_p(this)
681 ✗ , vert(std::move(v))
682 ✗ , hori(std::move(h))
683
0/4
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 51 not taken.
✗ Branch 19 → 20 not taken.
✗ Branch 19 → 49 not taken.
✗ , blur_size_v(vert->program->get_uniform("u_blur_size"))
684
0/4
✗ Branch 26 → 27 not taken.
✗ Branch 26 → 57 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 55 not taken.
✗ , blur_size_h(hori->program->get_uniform("u_blur_size"))
685 #if FF_HAS(BLUR_USE_GAUSS)
686 , std_dev_v(vert->program->get_uniform("u_std_dev"))
687 , std_dev_h(hori->program->get_uniform("u_std_dev"))
688 #endif
689 {
690
0/8
✗ Branch 32 → 33 not taken.
✗ Branch 32 → 39 not taken.
✗ Branch 33 → 34 not taken.
✗ Branch 33 → 67 not taken.
✗ Branch 34 → 35 not taken.
✗ Branch 34 → 39 not taken.
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 61 not taken.
✗ ASSERT(vert->factor_uni.has_value());
691
0/8
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 48 not taken.
✗ Branch 42 → 43 not taken.
✗ Branch 42 → 67 not taken.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 48 not taken.
✗ Branch 45 → 46 not taken.
✗ Branch 45 → 64 not taken.
✗ ASSERT(hori->factor_uni.has_value());
692 ✗ }
693
694 ✗ void BlurEffect::gui()
695 {
696 #if FF_HAS(EU_DEBUG_RUNNER)
697
0/2
✗ Branch 4 → 5 not taken.
✗ Branch 4 → 11 not taken.
✗ if (eu::imgui::header((name.c_str())))
698 {
699
0/4
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 14 not taken.
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 9 not taken.
✗ if (const auto prop = eu::imgui::PropTable::begin())
700 {
701
702
0/2
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 12 not taken.
✗ prop.slider("Blur size", &blur_size, 0.0f, 0.2f);
703 #if FF_HAS(BLUR_USE_GAUSS)
704 prop.slider("Standard deviation", &std_dev, 0.0f, 0.1f);
705 #endif
706
707 ✗ }
708 }
709 #endif
710 ✗ }
711
712 ✗ void BlurEffect::update(float)
713 {
714 // no update needed
715 ✗ }
716
717 ✗ void BlurEffect::use_vert_shader(const PostProcArg& a, const FrameBuffer& t) const
718 {
719 ✗ const auto& factor_uniform = vert->factor_uni;
720
721 ✗ vert->program->use();
722
0/6
✗ Branch 7 → 8 not taken.
✗ Branch 7 → 14 not taken.
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 14 not taken.
✗ Branch 11 → 12 not taken.
✗ Branch 11 → 28 not taken.
✗ ASSERT(factor_uniform);
723
0/2
✗ Branch 15 → 16 not taken.
✗ Branch 15 → 21 not taken.
✗ if (factor_uniform)
724 {
725 ✗ vert->program->set_float(*factor_uniform, get_factor());
726 }
727 ✗ vert->program->set_float(blur_size_v, blur_size);
728 #if FF_HAS(BLUR_USE_GAUSS)
729 vert->program->set_float(std_dev_v, std_dev);
730 #endif
731 ✗ bind_texture_2d(a.renderer->pimpl->states, vert->tex_input_uniform, t);
732 ✗ }
733
734 ✗ void BlurEffect::use_hori_shader(const PostProcArg& a, const FrameBuffer& t)
735 {
736 ✗ const auto& factor_uniform = hori->factor_uni;
737 ✗ const auto& resolution_uniform = hori->resolution_uni;
738
739 ✗ hori->program->use();
740
0/6
✗ Branch 8 → 9 not taken.
✗ Branch 8 → 15 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 15 not taken.
✗ Branch 12 → 13 not taken.
✗ Branch 12 → 45 not taken.
✗ ASSERT(factor_uniform);
741
0/2
✗ Branch 16 → 17 not taken.
✗ Branch 16 → 22 not taken.
✗ if (factor_uniform)
742 {
743 ✗ hori->program->set_float(*factor_uniform, get_factor());
744 }
745
0/6
✗ Branch 23 → 24 not taken.
✗ Branch 23 → 30 not taken.
✗ Branch 25 → 26 not taken.
✗ Branch 25 → 30 not taken.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 48 not taken.
✗ ASSERT(resolution_uniform);
746
0/2
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 38 not taken.
✗ if (resolution_uniform)
747 {
748
0/2
✗ Branch 36 → 37 not taken.
✗ Branch 36 → 51 not taken.
✗ hori->program->set_vec2(*resolution_uniform, v2_from_size(a.window_size));
749 }
750 ✗ hori->program->set_float(blur_size_h, blur_size);
751 #if FF_HAS(BLUR_USE_GAUSS)
752 hori->program->set_float(std_dev_h, std_dev);
753 #endif
754 ✗ bind_texture_2d(a.renderer->pimpl->states, hori->tex_input_uniform, t);
755 ✗ }
756
757 ✗ void BlurEffect::build(const BuildArg& arg)
758 {
759 ✗ auto src = arg.builder->last_source;
760
761 // todo(Gustav): modify resolution to get better blur and at a lower cost!
762
763 // step 1: vertical
764
0/4
✗ Branch 5 → 6 not taken.
✗ Branch 5 → 28 not taken.
✗ Branch 6 → 7 not taken.
✗ Branch 6 → 26 not taken.
✗ auto fbo_v = build_simple_framebuffer(USE_DEBUG_LABEL_MANY("blur vertical") arg.window_size);
765
0/2
✗ Branch 9 → 10 not taken.
✗ Branch 9 → 32 not taken.
✗ auto target_v = std::make_shared<RenderTextureWithShader>("blur vertical", src, fbo_v, &vert_p);
766
0/2
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 44 not taken.
✗ arg.builder->targets.emplace_back(target_v);
767
768 // step 2: horizontal
769
0/4
✗ Branch 13 → 14 not taken.
✗ Branch 13 → 35 not taken.
✗ Branch 14 → 15 not taken.
✗ Branch 14 → 33 not taken.
✗ auto fbo_h = build_simple_framebuffer(USE_DEBUG_LABEL_MANY("blur horizontal") arg.window_size);
770
0/2
✗ Branch 17 → 18 not taken.
✗ Branch 17 → 39 not taken.
✗ auto target_h = std::make_shared<RenderTextureWithShader>("blur horizontal", target_v, fbo_h, &hori_p);
771
0/2
✗ Branch 18 → 19 not taken.
✗ Branch 18 → 40 not taken.
✗ arg.builder->targets.emplace_back(target_h);
772
773 // done
774 ✗ arg.builder->last_source = target_h;
775 ✗ }
776
777 } // namespace eu::render
778