Blender V5.0
draw_pass_test.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "testing/testing.h"
6
7#include "BLI_math_geom.h"
8#include "BLI_math_matrix.hh"
9#include "GPU_context.hh"
10
11#include "draw_cache.hh"
12#include "draw_manager.hh"
13#include "draw_pass.hh"
14#include "draw_shader.hh"
15#include "draw_testing.hh"
16
17#include <bitset>
18
19namespace blender::draw {
20
22{
23 Texture tex;
24 tex.ensure_2d(blender::gpu::TextureFormat::UNORM_16_16_16_16, int2(1));
25
27 ubo.push_update();
28
30 ssbo.push_update();
31
32 /* Won't be dereferenced. */
33 gpu::VertBuf *vbo = (gpu::VertBuf *)1;
34 gpu::IndexBuf *ibo = (gpu::IndexBuf *)1;
35 gpu::FrameBuffer *fb = nullptr;
36
37 float4 color(1.0f, 1.0f, 1.0f, 0.0f);
38 int3 dispatch_size(1);
39
40 PassSimple pass = {"test.all_commands"};
41 pass.init();
43 pass.clear_color_depth_stencil(float4(0.25f, 0.5f, 100.0f, -2000.0f), 0.5f, 0xF0);
44 pass.state_stencil(0x80, 0x0F, 0x8F);
46 const int color_location = GPU_shader_get_uniform(sh, "color");
47 const int mvp_location = GPU_shader_get_uniform(sh, "ModelViewProjectionMatrix");
48 pass.shader_set(sh);
49 pass.framebuffer_set(&fb);
51 pass.bind_texture("image", tex);
52 pass.bind_texture("image", &tex);
53 pass.bind_image("missing_image", tex); /* Should not crash. */
54 pass.bind_image("missing_image", &tex); /* Should not crash. */
55 pass.bind_ubo("missing_ubo", ubo); /* Should not crash. */
56 pass.bind_ubo("missing_ubo", &ubo); /* Should not crash. */
57 pass.bind_ssbo("missing_ssbo", ssbo); /* Should not crash. */
58 pass.bind_ssbo("missing_ssbo", &ssbo); /* Should not crash. */
59 pass.bind_ssbo("missing_vbo_as_ssbo", vbo); /* Should not crash. */
60 pass.bind_ssbo("missing_vbo_as_ssbo", &vbo); /* Should not crash. */
61 pass.bind_ssbo("missing_ibo_as_ssbo", ibo); /* Should not crash. */
62 pass.bind_ssbo("missing_ibo_as_ssbo", &ibo); /* Should not crash. */
63 pass.push_constant("color", color);
64 pass.push_constant("color", &color);
65 pass.push_constant("ModelViewProjectionMatrix", float4x4::identity());
67
68 /* Should not crash even if shader is not a compute. This is because we only serialize. */
69 /* TODO(fclem): Use real compute shader. */
71 pass.dispatch(dispatch_size);
72 pass.dispatch(&dispatch_size);
74
75 /* Change references. */
76 color[3] = 1.0f;
77 dispatch_size = int3(2);
78
79 std::string result = pass.serialize();
80 std::stringstream expected;
81 expected << ".test.all_commands" << std::endl;
82 expected << " .state_set(2147483654)" << std::endl;
83 expected << " .clear(color=(0.25, 0.5, 100, -2000), depth=0.5, stencil=0b11110000))"
84 << std::endl;
85 expected
86 << " .stencil_set(write_mask=0b10000000, reference=0b00001111, compare_mask=0b10001111)"
87 << std::endl;
88 expected << " .shader_bind(gpu_shader_3D_image_color)" << std::endl;
89 expected << " .framebuffer_bind(nullptr)" << std::endl;
90 expected << " .subpass_transition(" << std::endl;
91 expected << "depth=ignore," << std::endl;
92 expected << "color0=write," << std::endl;
93 expected << "color1=read," << std::endl;
94 expected << "color2=ignore," << std::endl;
95 expected << "color3=ignore," << std::endl;
96 expected << "color4=ignore," << std::endl;
97 expected << "color5=ignore," << std::endl;
98 expected << "color6=ignore," << std::endl;
99 expected << "color7=ignore" << std::endl;
100 expected << ")" << std::endl;
101 expected << " .bind_texture(0, sampler=internal)" << std::endl;
102 expected << " .bind_texture_ref(0, sampler=internal)" << std::endl;
103 expected << " .bind_image(-1)" << std::endl;
104 expected << " .bind_image_ref(-1)" << std::endl;
105 expected << " .bind_uniform_buf(-1)" << std::endl;
106 expected << " .bind_uniform_buf_ref(-1)" << std::endl;
107 expected << " .bind_storage_buf(-1)" << std::endl;
108 expected << " .bind_storage_buf_ref(-1)" << std::endl;
109 expected << " .bind_vertbuf_as_ssbo(-1)" << std::endl;
110 expected << " .bind_vertbuf_as_ssbo_ref(-1)" << std::endl;
111 expected << " .bind_indexbuf_as_ssbo(-1)" << std::endl;
112 expected << " .bind_indexbuf_as_ssbo_ref(-1)" << std::endl;
113 expected << " .push_constant(" << color_location << ", data=(1, 1, 1, 0))" << std::endl;
114 expected << " .push_constant(" << color_location << ", data=(1, 1, 1, 1))" << std::endl;
115 expected << " .push_constant(" << mvp_location << ", data=(" << std::endl;
116 expected << "(1, 0, 0, 0)," << std::endl;
117 expected << "(0, 1, 0, 0)," << std::endl;
118 expected << "(0, 0, 1, 0)," << std::endl;
119 expected << "(0, 0, 0, 1)" << std::endl;
120 expected << ")" << std::endl;
121 expected << ")" << std::endl;
122 expected << " .draw(inst_len=1, vert_len=3, vert_first=0, res_id=0)" << std::endl;
123 expected << " .shader_bind(gpu_shader_3D_image_color)" << std::endl;
124 expected << " .dispatch(1, 1, 1)" << std::endl;
125 expected << " .dispatch_ref(2, 2, 2)" << std::endl;
126 expected << " .barrier(2)" << std::endl;
127
128 EXPECT_EQ(result, expected.str());
129}
130DRAW_TEST(draw_pass_all_commands)
131
133{
134 PassSimple pass = {"test.sub_ordering"};
135 pass.init();
137 pass.push_constant("test_pass", 1);
138
139 PassSimple::Sub &sub1 = pass.sub("Sub1");
140 sub1.push_constant("test_sub1", 11);
141
142 PassSimple::Sub &sub2 = pass.sub("Sub2");
143 sub2.push_constant("test_sub2", 21);
144
145 /* Will execute after both sub. */
146 pass.push_constant("test_pass", 2);
147
148 /* Will execute after sub1. */
149 sub2.push_constant("test_sub2", 22);
150
151 /* Will execute before sub2. */
152 sub1.push_constant("test_sub1", 12);
153
154 /* Will execute before end of pass. */
155 sub2.push_constant("test_sub2", 23);
156
157 std::string result = pass.serialize();
158 std::stringstream expected;
159 expected << ".test.sub_ordering" << std::endl;
160 expected << " .shader_bind(gpu_shader_3D_image_color)" << std::endl;
161 expected << " .push_constant(-1, data=1)" << std::endl;
162 expected << " .Sub1" << std::endl;
163 expected << " .push_constant(-1, data=11)" << std::endl;
164 expected << " .push_constant(-1, data=12)" << std::endl;
165 expected << " .Sub2" << std::endl;
166 expected << " .push_constant(-1, data=21)" << std::endl;
167 expected << " .push_constant(-1, data=22)" << std::endl;
168 expected << " .push_constant(-1, data=23)" << std::endl;
169 expected << " .push_constant(-1, data=2)" << std::endl;
170
171 EXPECT_EQ(result, expected.str());
172}
173DRAW_TEST(draw_pass_sub_ordering)
174
176{
177 PassSimple pass = {"test.simple_draw"};
178 pass.init();
180 /* Each draw procedural type uses a different batch. Groups are drawn in correct order. */
181 pass.draw_procedural(GPU_PRIM_TRIS, 1, 10, 1, {1});
182 pass.draw_procedural(GPU_PRIM_POINTS, 4, 20, 2, {2});
183 pass.draw_procedural(GPU_PRIM_TRIS, 2, 30, 3, {3});
184 pass.draw_procedural(GPU_PRIM_POINTS, 5, 40, 4, ResourceIndex(4, true));
185 pass.draw_procedural(GPU_PRIM_LINES, 1, 50, 5, {5});
186 pass.draw_procedural(GPU_PRIM_POINTS, 6, 60, 6, {5});
187 pass.draw_procedural(GPU_PRIM_TRIS, 3, 70, 7, {6});
188
189 PassSimple::Sub &sub = pass.sub("sub");
190 sub.draw_procedural(GPU_PRIM_TRIS, 3, 80, 8, {8});
191
192 std::string result = pass.serialize();
193 std::stringstream expected;
194 expected << ".test.simple_draw" << std::endl;
195 expected << " .shader_bind(gpu_shader_3D_image_color)" << std::endl;
196 expected << " .draw(inst_len=1, vert_len=10, vert_first=1, res_id=1)" << std::endl;
197 expected << " .draw(inst_len=4, vert_len=20, vert_first=2, res_id=2)" << std::endl;
198 expected << " .draw(inst_len=2, vert_len=30, vert_first=3, res_id=3)" << std::endl;
199 expected << " .draw(inst_len=5, vert_len=40, vert_first=4, res_id=4)" << std::endl;
200 expected << " .draw(inst_len=1, vert_len=50, vert_first=5, res_id=5)" << std::endl;
201 expected << " .draw(inst_len=6, vert_len=60, vert_first=6, res_id=5)" << std::endl;
202 expected << " .draw(inst_len=3, vert_len=70, vert_first=7, res_id=6)" << std::endl;
203 expected << " .sub" << std::endl;
204 expected << " .draw(inst_len=3, vert_len=80, vert_first=8, res_id=8)" << std::endl;
205
206 EXPECT_EQ(result, expected.str());
207}
208DRAW_TEST(draw_pass_simple_draw)
209
211{
212 PassMain pass = {"test.multi_draw"};
213 pass.init();
215 /* Each draw procedural type uses a different batch. Groups are drawn in reverse order. */
216 pass.draw_procedural(GPU_PRIM_TRIS, 1, -1, -1, {1});
217 pass.draw_procedural(GPU_PRIM_POINTS, 4, -1, -1, {2});
218 pass.draw_procedural(GPU_PRIM_TRIS, 2, -1, -1, {3});
219 pass.draw_procedural(GPU_PRIM_POINTS, 5, -1, -1, ResourceIndex(4, true));
220 pass.draw_procedural(GPU_PRIM_LINES, 1, -1, -1, {5});
221 pass.draw_procedural(GPU_PRIM_POINTS, 6, -1, -1, {5});
222 pass.draw_procedural(GPU_PRIM_TRIS, 3, -1, -1, {6});
223 /* Custom calls should use their own group and never be batched. */
224 pass.draw_procedural(GPU_PRIM_TRIS, 2, 2, 2, {7});
225 pass.draw_procedural(GPU_PRIM_TRIS, 2, 2, 2, {8});
226
227 std::string result = pass.serialize();
228 std::stringstream expected;
229 expected << ".test.multi_draw" << std::endl;
230 expected << " .shader_bind(gpu_shader_3D_image_color)" << std::endl;
231 expected << " .draw_multi(5)" << std::endl;
232 expected << " .group(id=4, len=2)" << std::endl;
233 expected << " .proto(instance_len=2, resource_id=8, front_face)" << std::endl;
234 expected << " .group(id=3, len=2)" << std::endl;
235 expected << " .proto(instance_len=2, resource_id=7, front_face)" << std::endl;
236 expected << " .group(id=2, len=1)" << std::endl;
237 expected << " .proto(instance_len=1, resource_id=5, front_face)" << std::endl;
238 expected << " .group(id=1, len=15)" << std::endl;
239 expected << " .proto(instance_len=5, resource_id=4, back_face)" << std::endl;
240 expected << " .proto(instance_len=6, resource_id=5, front_face)" << std::endl;
241 expected << " .proto(instance_len=4, resource_id=2, front_face)" << std::endl;
242 expected << " .group(id=0, len=6)" << std::endl;
243 expected << " .proto(instance_len=3, resource_id=6, front_face)" << std::endl;
244 expected << " .proto(instance_len=2, resource_id=3, front_face)" << std::endl;
245 expected << " .proto(instance_len=1, resource_id=1, front_face)" << std::endl;
246
247 EXPECT_EQ(result, expected.str());
248}
249DRAW_TEST(draw_pass_multi_draw)
250
252{
253 PassSortable pass = {"test.sortable"};
254 pass.init();
255
256 pass.sub("Sub3", 3.0f);
257 pass.sub("Sub2", 2.0f);
258 pass.sub("Sub5", 4.0f);
259 pass.sub("Sub4", 3.0f);
260 pass.sub("Sub1", 1.0f);
261
262 std::string result = pass.serialize();
263 std::stringstream expected;
264 expected << ".test.sortable" << std::endl;
265 expected << " .Sub1" << std::endl;
266 expected << " .Sub2" << std::endl;
267 expected << " .Sub3" << std::endl;
268 expected << " .Sub4" << std::endl;
269 expected << " .Sub5" << std::endl;
270
271 EXPECT_EQ(result, expected.str());
272}
273DRAW_TEST(draw_pass_sortable)
274
276{
278 Texture color_attachment;
279 Framebuffer framebuffer;
280 color_attachment.ensure_2d(blender::gpu::TextureFormat::SFLOAT_32_32_32_32, int2(1));
281 framebuffer.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(color_attachment));
282 framebuffer.bind();
283
284 float4x4 win_mat;
285 orthographic_m4(win_mat.ptr(), -1, 1, -1, 1, -1, 1);
286
287 View view("test_view");
288 view.sync(float4x4::identity(), win_mat);
289
290 Manager drw;
291
294
295 drw.begin_sync();
296 ResourceHandleRange handle1 = drw.resource_handle(obmat_1);
297 ResourceHandleRange handle2 = drw.resource_handle(obmat_1);
298 ResourceHandleRange handle3 = drw.resource_handle(obmat_2);
299 drw.resource_handle(obmat_2, float3(2), float3(1));
300 drw.end_sync();
301
302 {
303 /* Computed on CPU. */
304 PassSimple pass = {"test.resource_id"};
305 pass.init();
306 pass.shader_set(
308 pass.draw_procedural(GPU_PRIM_TRIS, 1, -1, -1, handle2);
309 pass.draw_procedural(GPU_PRIM_POINTS, 4, -1, -1, handle1);
310 pass.draw_procedural(GPU_PRIM_TRIS, 2, -1, -1, handle3);
311 pass.draw_procedural(GPU_PRIM_POINTS, 5, -1, -1, handle1);
312 pass.draw_procedural(GPU_PRIM_LINES, 1, -1, -1, handle3);
313 pass.draw_procedural(GPU_PRIM_POINTS, 6, -1, -1, handle2);
314 pass.draw_procedural(GPU_PRIM_TRIS, 3, -1, -1, handle1);
315
317
318 std::stringstream result;
319 for (auto val : debug.resource_id) {
320 result << val << " ";
321 }
322
323 StringRefNull expected_simple = "0 2 1 1 1 1 3 3 1 1 1 1 1 3 2 2 2 2 2 2 1 1 1 ";
324 EXPECT_EQ(result.str(), expected_simple);
325 }
326
327 {
328 /* Same thing with PassMain (computed on GPU) */
329 PassMain pass = {"test.resource_id"};
330 pass.init();
331 pass.shader_set(
333 pass.draw_procedural(GPU_PRIM_TRIS, 1, -1, -1, handle2);
334 pass.draw_procedural(GPU_PRIM_POINTS, 4, -1, -1, handle1);
335 pass.draw_procedural(GPU_PRIM_TRIS, 2, -1, -1, handle3);
336 pass.draw_procedural(GPU_PRIM_POINTS, 5, -1, -1, handle1);
337 pass.draw_procedural(GPU_PRIM_LINES, 1, -1, -1, handle3);
338 pass.draw_procedural(GPU_PRIM_POINTS, 6, -1, -1, handle2);
339 pass.draw_procedural(GPU_PRIM_TRIS, 3, -1, -1, handle1);
340
342
343 std::stringstream result;
344 for (auto val : debug.resource_id) {
345 result << val << " ";
346 }
347
348 /* When using PassMain the handles are sorted based on their handles and GPUBatches. Different
349 * primitives use different batches.
350 */
351 StringRefNull expected_main = "2 3 3 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 3 ";
352 EXPECT_EQ(result.str(), expected_main);
353 }
354
357}
358DRAW_TEST(draw_resource_id_gen)
359
361{
362 GTEST_SKIP() << "This test needs to be reviewed. It should check visibility checks, but all "
363 "resource handles are visible.";
365 Texture color_attachment;
366 Framebuffer framebuffer;
367 color_attachment.ensure_2d(blender::gpu::TextureFormat::SFLOAT_32_32_32_32, int2(1));
368 framebuffer.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(color_attachment));
369 framebuffer.bind();
370
371 float4x4 win_mat;
372 orthographic_m4(win_mat.ptr(), -1, 1, -1, 1, -1, 1);
373
374 View view("test_view");
375 view.sync(float4x4::identity(), win_mat);
376
377 Manager drw;
378
381
382 drw.begin_sync(); /* Default {0} always visible. */
383 drw.resource_handle(obmat_1); /* No bounds, always visible. */
384 drw.resource_handle(obmat_1, float3(3), float3(1)); /* Out of view. */
385 drw.resource_handle(obmat_2, float3(0), float3(1)); /* Inside view. */
386 drw.end_sync();
387
388 Texture tex;
389 tex.ensure_2d(blender::gpu::TextureFormat::SFLOAT_16_16_16_16, int2(1));
390
391 PassMain pass = {"test.visibility"};
392 pass.init();
394 pass.bind_texture("image", tex);
395 pass.draw_procedural(GPU_PRIM_TRIS, 1, -1);
396
398 Vector<uint32_t> expected_visibility = {0};
399
400 std::stringstream result;
401 for (auto val : debug.visibility) {
403 }
404
405 EXPECT_EQ(result.str(), "11111111111111111111111111111011");
406
409}
410DRAW_TEST(draw_visibility)
411
413{
416
417 /* TODO find a way to create a minimum object to test resource handle creation on it. */
418 Manager drw;
419
420 drw.begin_sync();
421 drw.resource_handle(obmat_1);
422 drw.resource_handle(obmat_2, float3(2), float3(1));
423 drw.end_sync();
424
426
427 std::stringstream result;
428 for (const auto &val : debug.matrices) {
429 result << val;
430 }
431 for (const auto &val : debug.bounds) {
432 result << val;
433 }
434 for (const auto &val : debug.infos) {
435 result << val;
436 }
437
438 std::stringstream expected;
439 expected << "ObjectMatrices(" << std::endl;
440 expected << "model=(" << std::endl;
441 expected << "(1, 0, 0, 0)," << std::endl;
442 expected << "(0, 1, 0, 0)," << std::endl;
443 expected << "(0, 0, 1, 0)," << std::endl;
444 expected << "(0, 0, 0, 1)" << std::endl;
445 expected << ")" << std::endl;
446 expected << ", " << std::endl;
447 expected << "model_inverse=(" << std::endl;
448 expected << "(1, -0, 0, -0)," << std::endl;
449 expected << "(-0, 1, -0, 0)," << std::endl;
450 expected << "(0, -0, 1, -0)," << std::endl;
451 expected << "(-0, 0, -0, 1)" << std::endl;
452 expected << ")" << std::endl;
453 expected << ")" << std::endl;
454 expected << "ObjectMatrices(" << std::endl;
455 expected << "model=(" << std::endl;
456 expected << "(-0.5, 0, 0, 0)," << std::endl;
457 expected << "(0, -0.5, 0, 0)," << std::endl;
458 expected << "(0, 0, -0.5, 0)," << std::endl;
459 expected << "(0, 0, 0, 1)" << std::endl;
460 expected << ")" << std::endl;
461 expected << ", " << std::endl;
462 expected << "model_inverse=(" << std::endl;
463 expected << "(-2, -0, -0, 0)," << std::endl;
464 expected << "(-0, -2, 0, -0)," << std::endl;
465 expected << "(-0, 0, -2, 0)," << std::endl;
466 expected << "(0, -0, 0, 1)" << std::endl;
467 expected << ")" << std::endl;
468 expected << ")" << std::endl;
469 expected << "ObjectMatrices(" << std::endl;
470 expected << "model=(" << std::endl;
471 expected << "(0.5, 0, 0, 0)," << std::endl;
472 expected << "(0, 0.5, 0, 0)," << std::endl;
473 expected << "(0, 0, 0.5, 0)," << std::endl;
474 expected << "(0, 0, 0, 1)" << std::endl;
475 expected << ")" << std::endl;
476 expected << ", " << std::endl;
477 expected << "model_inverse=(" << std::endl;
478 expected << "(2, -0, 0, -0)," << std::endl;
479 expected << "(-0, 2, -0, 0)," << std::endl;
480 expected << "(0, -0, 2, -0)," << std::endl;
481 expected << "(-0, 0, -0, 1)" << std::endl;
482 expected << ")" << std::endl;
483 expected << ")" << std::endl;
484 expected << "ObjectBounds(skipped)" << std::endl;
485 expected << "ObjectBounds(skipped)" << std::endl;
486 expected << "ObjectBounds(" << std::endl;
487 expected << ".bounding_corners[0](1.5, 0.5, 0.5)" << std::endl;
488 expected << ".bounding_corners[1](-1, -0, -0)" << std::endl;
489 expected << ".bounding_corners[2](0, 1, 0)" << std::endl;
490 expected << ".bounding_corners[3](0, 0, 1)" << std::endl;
491 expected << ".sphere=(pos=(1, 1, 1), rad=0.866025" << std::endl;
492 expected << ")" << std::endl;
493 expected << "ObjectInfos(skipped)" << std::endl;
494 expected << "ObjectInfos(skipped)" << std::endl;
495 expected << "ObjectInfos(skipped)" << std::endl;
496
497 EXPECT_EQ(result.str(), expected.str());
498
500}
501DRAW_TEST(draw_manager_sync)
502
504{
505 float4x4 projmat = math::projection::orthographic(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
506 float4x4 viewmat = float4x4::identity();
507
508 Texture color_attachment;
509 Framebuffer framebuffer;
510 color_attachment.ensure_2d(blender::gpu::TextureFormat::SFLOAT_32_32_32_32, int2(1));
511 framebuffer.ensure(GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(color_attachment));
512 framebuffer.bind();
513
514 Manager manager;
515 View view = {"Test"};
516 View view_other = {"Test"};
517 PassSimple pass = {"Test"};
518 PassMain pass_main = {"Test"};
519 PassMain pass_manual = {"Test"};
520
521 manager.begin_sync();
522 manager.end_sync();
523 view.sync(viewmat, projmat);
524 view_other.sync(viewmat, projmat);
525
526 /* Add some draws to prevent empty pass optimization. */
528 pass.init();
529 pass.shader_set(sh);
530 pass.draw_procedural(GPU_PRIM_TRIS, 1, 3);
531 pass_main.init();
532 pass_main.shader_set(sh);
533 pass_main.draw_procedural(GPU_PRIM_TRIS, 1, 3);
534 pass_manual.init();
535 pass_manual.shader_set(sh);
536 pass_manual.draw_procedural(GPU_PRIM_TRIS, 1, 3);
537
538 /* Auto command and visibility computation. */
539 manager.submit(pass);
540 manager.submit(pass_main, view);
541
542 /* Update manager. */
543 manager.begin_sync();
544 manager.end_sync();
545
546 /* Auto command and visibility computation. */
547 manager.submit(pass);
548 manager.submit(pass_main, view);
549
550 /* Update view. */
551 view.sync(viewmat, projmat);
552
553 /* Auto command and visibility computation. */
554 manager.submit(pass);
555 manager.submit(pass_main, view);
556
557 /* Update both. */
558 manager.begin_sync();
559 manager.end_sync();
560 view.sync(viewmat, projmat);
561
562 /* Auto command and visibility computation. */
563 manager.submit(pass);
564 manager.submit(pass_main, view);
565
566 /* Update both. */
567 manager.begin_sync();
568 manager.end_sync();
569 view.sync(viewmat, projmat);
570
571 {
572 /* Manual command and visibility computation. */
573 manager.compute_visibility(view);
574 manager.generate_commands(pass_manual, view);
575 manager.submit_only(pass_manual, view);
576
577 /* Redundant updates. */
578 EXPECT_BLI_ASSERT(manager.compute_visibility(view),
579 "Resources did not changed, no need to update");
580 EXPECT_BLI_ASSERT(manager.generate_commands(pass_manual, view),
581 "Resources and view did not changed no need to update");
582 }
583 {
584 /* Update view. */
585 view.sync(viewmat, projmat);
586
587 /* Submit before visibility. */
588 EXPECT_BLI_ASSERT(manager.submit_only(pass_manual, view),
589 "compute_visibility was not called on this view");
590 /* Update commands before visibility. */
591 EXPECT_BLI_ASSERT(manager.generate_commands(pass_manual, view),
592 "Resources or view changed, but compute_visibility was not called");
593
594 manager.compute_visibility(view);
595
596 /* Submit before command generation. */
597 EXPECT_BLI_ASSERT(manager.submit_only(pass_manual, view),
598 "View have changed since last generate_commands");
599
600 manager.generate_commands(pass_manual, view);
601 manager.submit_only(pass_manual, view);
602 }
603 {
604 /* Update manager. */
605 manager.begin_sync();
606 manager.end_sync();
607
608 /* Update commands before visibility. */
609 EXPECT_BLI_ASSERT(manager.generate_commands(pass_manual, view),
610 "Resources or view changed, but compute_visibility was not called");
611 /* Submit before visibility. */
612 EXPECT_BLI_ASSERT(manager.submit_only(pass_manual, view),
613 "Resources changed since last compute_visibility");
614
615 manager.compute_visibility(view);
616
617 /* Submit with stale commands. */
618 EXPECT_BLI_ASSERT(manager.submit_only(pass_manual, view),
619 "Resources changed since last generate_command");
620
621 manager.generate_commands(pass_manual, view);
622 manager.submit_only(pass_manual, view);
623 }
624 {
625 /* Add some draws to prevent empty pass optimization. */
626 pass_manual.init();
627 pass_manual.shader_set(sh);
628 pass_manual.draw_procedural(GPU_PRIM_TRIS, 1, 3);
629
630 /* Submit before command generation. */
631 EXPECT_BLI_ASSERT(manager.submit_only(pass_manual, view),
632 "generate_command was not called on this pass");
633 manager.generate_commands(pass_manual, view);
634 manager.submit_only(pass_manual, view);
635 }
636 {
637 manager.compute_visibility(view_other);
638
639 /* Submit with a different view before command generation. */
640 EXPECT_BLI_ASSERT(manager.submit_only(pass_manual, view_other),
641 "submitting with a different view");
642 manager.generate_commands(pass_manual, view_other);
643 manager.submit_only(pass_manual, view_other);
644 }
645
647}
648DRAW_TEST(draw_submit_only)
649
650} // namespace blender::draw
EXPECT_EQ(BLI_expr_pylike_eval(expr, nullptr, 0, &result), EXPR_PYLIKE_INVALID)
void orthographic_m4(float mat[4][4], float left, float right, float bottom, float top, float nearClip, float farClip)
static AppView * view
@ GPU_ATTACHMENT_WRITE
@ GPU_ATTACHMENT_READ
@ GPU_ATTACHMENT_IGNORE
void GPU_render_end()
void GPU_render_begin()
#define GPU_ATTACHMENT_TEXTURE(_texture)
#define GPU_ATTACHMENT_NONE
@ GPU_PRIM_LINES
@ GPU_PRIM_POINTS
@ GPU_PRIM_TRIS
int GPU_shader_get_uniform(blender::gpu::Shader *shader, const char *name)
blender::gpu::Shader * GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
@ GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_SHADER_3D_IMAGE_COLOR
@ GPU_BARRIER_SHADER_IMAGE_ACCESS
Definition GPU_state.hh:35
void ensure(GPUAttachment depth=GPU_ATTACHMENT_NONE, GPUAttachment color1=GPU_ATTACHMENT_NONE, GPUAttachment color2=GPU_ATTACHMENT_NONE, GPUAttachment color3=GPU_ATTACHMENT_NONE, GPUAttachment color4=GPU_ATTACHMENT_NONE, GPUAttachment color5=GPU_ATTACHMENT_NONE, GPUAttachment color6=GPU_ATTACHMENT_NONE, GPUAttachment color7=GPU_ATTACHMENT_NONE, GPUAttachment color8=GPU_ATTACHMENT_NONE)
void begin_sync(Object *object_active=nullptr)
SubmitDebugOutput submit_debug(PassSimple &pass, View &view)
void generate_commands(PassMain &pass, View &view)
void compute_visibility(View &view)
void submit_only(PassMain &pass, View &view)
void submit(PassSimple &pass, View &view)
ResourceHandleRange resource_handle(const ObjectRef &ref, float inflate_bounds=0.0f)
DataDebugOutput data_debug()
std::string serialize(std::string line_prefix="") const
Definition draw_pass.hh:585
PassMain::Sub & sub(const char *name, float sorting_value)
Definition draw_pass.hh:568
bool ensure_2d(blender::gpu::TextureFormat format, int2 extent, eGPUTextureUsage usage=GPU_TEXTURE_USAGE_GENERAL, const float *data=nullptr, int mip_len=1)
void sync(const float4x4 &view_mat, const float4x4 &win_mat, int view_id=0)
Definition draw_view.cc:27
void framebuffer_set(gpu::FrameBuffer **framebuffer)
void shader_set(gpu::Shader *shader)
void bind_texture(const char *name, gpu::Texture *texture, GPUSamplerState state=sampler_auto)
void subpass_transition(GPUAttachmentState depth_attachment, Span< GPUAttachmentState > color_attachments)
void bind_image(const char *name, gpu::Texture *image)
void draw_procedural(GPUPrimType primitive, uint instance_len, uint vertex_len, uint vertex_first=-1, ResourceIndexRange res_index={}, uint custom_id=0)
Definition draw_pass.hh:964
PassBase< DrawCommandBufType > & sub(const char *name)
Definition draw_pass.hh:690
void dispatch(int group_len)
void state_set(DRWState state, int clip_plane_count=0)
void barrier(GPUBarrier type)
void state_stencil(uint8_t write_mask, uint8_t reference, uint8_t compare_mask)
void clear_color_depth_stencil(float4 color, float depth, uint8_t stencil)
void bind_ubo(const char *name, gpu::UniformBuf *buffer)
std::string serialize(std::string line_prefix="") const
Definition draw_pass.hh:823
void push_constant(const char *name, const float &data)
void bind_ssbo(const char *name, gpu::StorageBuf *buffer)
detail::PassBase< command::DrawCommandBuf > Sub
Definition draw_pass.hh:499
void DRW_shaders_free()
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
@ DRW_STATE_WRITE_STENCIL
Definition draw_state.hh:32
#define DRAW_TEST(test_name)
BLI_INLINE float fb(float length, float L)
static void test_draw_submit_only()
static void test_draw_pass_multi_draw()
detail::Pass< command::DrawCommandBuf > PassSimple
detail::Pass< command::DrawMultiBuf > PassMain
static void test_draw_pass_all_commands()
static void test_draw_pass_simple_draw()
static void test_draw_visibility()
static void test_draw_manager_sync()
static void test_draw_resource_id_gen()
static void test_draw_pass_sub_ordering()
static void test_draw_pass_sortable()
MatBase< T, 4, 4 > orthographic(T left, T right, T bottom, T top, T near_clip, T far_clip)
Create an orthographic projection matrix using OpenGL coordinate convention: Maps each axis range to ...
MatT from_scale(const VecBase< typename MatT::base_type, ScaleDim > &scale)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
const c_style_mat & ptr() const