1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * Copyright 2016, Blender Foundation.
17 */
18
19 /** \file
20 * \ingroup draw
21 */
22
23 #include "draw_manager.h"
24
25 #include "BLI_alloca.h"
26 #include "BLI_math.h"
27 #include "BLI_math_bits.h"
28 #include "BLI_memblock.h"
29
30 #include "BKE_global.h"
31
32 #include "GPU_platform.h"
33 #include "GPU_shader.h"
34 #include "GPU_state.h"
35
36 #ifdef USE_GPU_SELECT
37 # include "GPU_select.h"
38 #endif
39
DRW_select_load_id(uint id)40 void DRW_select_load_id(uint id)
41 {
42 #ifdef USE_GPU_SELECT
43 BLI_assert(G.f & G_FLAG_PICKSEL);
44 DST.select_id = id;
45 #endif
46 }
47
48 #define DEBUG_UBO_BINDING
49
50 typedef struct DRWCommandsState {
51 GPUBatch *batch;
52 int resource_chunk;
53 int resource_id;
54 int base_inst;
55 int inst_count;
56 bool neg_scale;
57 /* Resource location. */
58 int obmats_loc;
59 int obinfos_loc;
60 int baseinst_loc;
61 int chunkid_loc;
62 int resourceid_loc;
63 /* Legacy matrix support. */
64 int obmat_loc;
65 int obinv_loc;
66 /* Selection ID state. */
67 GPUVertBuf *select_buf;
68 uint select_id;
69 /* Drawing State */
70 DRWState drw_state_enabled;
71 DRWState drw_state_disabled;
72 } DRWCommandsState;
73
74 /* -------------------------------------------------------------------- */
75 /** \name Draw State (DRW_state)
76 * \{ */
77
drw_state_set(DRWState state)78 void drw_state_set(DRWState state)
79 {
80 /* Mask locked state. */
81 state = (~DST.state_lock & state) | (DST.state_lock & DST.state);
82
83 if (DST.state == state) {
84 return;
85 }
86
87 eGPUWriteMask write_mask = 0;
88 eGPUBlend blend = 0;
89 eGPUFaceCullTest culling_test = 0;
90 eGPUDepthTest depth_test = 0;
91 eGPUStencilTest stencil_test = 0;
92 eGPUStencilOp stencil_op = 0;
93 eGPUProvokingVertex provoking_vert = 0;
94
95 if (state & DRW_STATE_WRITE_DEPTH) {
96 write_mask |= GPU_WRITE_DEPTH;
97 }
98 if (state & DRW_STATE_WRITE_COLOR) {
99 write_mask |= GPU_WRITE_COLOR;
100 }
101 if (state & DRW_STATE_WRITE_STENCIL_ENABLED) {
102 write_mask |= GPU_WRITE_STENCIL;
103 }
104
105 switch (state & (DRW_STATE_CULL_BACK | DRW_STATE_CULL_FRONT)) {
106 case DRW_STATE_CULL_BACK:
107 culling_test = GPU_CULL_BACK;
108 break;
109 case DRW_STATE_CULL_FRONT:
110 culling_test = GPU_CULL_FRONT;
111 break;
112 default:
113 culling_test = GPU_CULL_NONE;
114 break;
115 }
116
117 switch (state & DRW_STATE_DEPTH_TEST_ENABLED) {
118 case DRW_STATE_DEPTH_LESS:
119 depth_test = GPU_DEPTH_LESS;
120 break;
121 case DRW_STATE_DEPTH_LESS_EQUAL:
122 depth_test = GPU_DEPTH_LESS_EQUAL;
123 break;
124 case DRW_STATE_DEPTH_EQUAL:
125 depth_test = GPU_DEPTH_EQUAL;
126 break;
127 case DRW_STATE_DEPTH_GREATER:
128 depth_test = GPU_DEPTH_GREATER;
129 break;
130 case DRW_STATE_DEPTH_GREATER_EQUAL:
131 depth_test = GPU_DEPTH_GREATER_EQUAL;
132 break;
133 case DRW_STATE_DEPTH_ALWAYS:
134 depth_test = GPU_DEPTH_ALWAYS;
135 break;
136 default:
137 depth_test = GPU_DEPTH_NONE;
138 break;
139 }
140
141 switch (state & DRW_STATE_WRITE_STENCIL_ENABLED) {
142 case DRW_STATE_WRITE_STENCIL:
143 stencil_op = GPU_STENCIL_OP_REPLACE;
144 GPU_stencil_write_mask_set(0xFF);
145 break;
146 case DRW_STATE_WRITE_STENCIL_SHADOW_PASS:
147 stencil_op = GPU_STENCIL_OP_COUNT_DEPTH_PASS;
148 GPU_stencil_write_mask_set(0xFF);
149 break;
150 case DRW_STATE_WRITE_STENCIL_SHADOW_FAIL:
151 stencil_op = GPU_STENCIL_OP_COUNT_DEPTH_FAIL;
152 GPU_stencil_write_mask_set(0xFF);
153 break;
154 default:
155 stencil_op = GPU_STENCIL_OP_NONE;
156 GPU_stencil_write_mask_set(0x00);
157 break;
158 }
159
160 switch (state & DRW_STATE_STENCIL_TEST_ENABLED) {
161 case DRW_STATE_STENCIL_ALWAYS:
162 stencil_test = GPU_STENCIL_ALWAYS;
163 break;
164 case DRW_STATE_STENCIL_EQUAL:
165 stencil_test = GPU_STENCIL_EQUAL;
166 break;
167 case DRW_STATE_STENCIL_NEQUAL:
168 stencil_test = GPU_STENCIL_NEQUAL;
169 break;
170 default:
171 stencil_test = GPU_STENCIL_NONE;
172 break;
173 }
174
175 switch (state & DRW_STATE_BLEND_ENABLED) {
176 case DRW_STATE_BLEND_ADD:
177 blend = GPU_BLEND_ADDITIVE;
178 break;
179 case DRW_STATE_BLEND_ADD_FULL:
180 blend = GPU_BLEND_ADDITIVE_PREMULT;
181 break;
182 case DRW_STATE_BLEND_ALPHA:
183 blend = GPU_BLEND_ALPHA;
184 break;
185 case DRW_STATE_BLEND_ALPHA_PREMUL:
186 blend = GPU_BLEND_ALPHA_PREMULT;
187 break;
188 case DRW_STATE_BLEND_BACKGROUND:
189 blend = GPU_BLEND_BACKGROUND;
190 break;
191 case DRW_STATE_BLEND_OIT:
192 blend = GPU_BLEND_OIT;
193 break;
194 case DRW_STATE_BLEND_MUL:
195 blend = GPU_BLEND_MULTIPLY;
196 break;
197 case DRW_STATE_BLEND_SUB:
198 blend = GPU_BLEND_SUBTRACT;
199 break;
200 case DRW_STATE_BLEND_CUSTOM:
201 blend = GPU_BLEND_CUSTOM;
202 break;
203 case DRW_STATE_LOGIC_INVERT:
204 blend = GPU_BLEND_INVERT;
205 break;
206 case DRW_STATE_BLEND_ALPHA_UNDER_PREMUL:
207 blend = GPU_BLEND_ALPHA_UNDER_PREMUL;
208 break;
209 default:
210 blend = GPU_BLEND_NONE;
211 break;
212 }
213
214 GPU_state_set(
215 write_mask, blend, culling_test, depth_test, stencil_test, stencil_op, provoking_vert);
216
217 if (state & DRW_STATE_SHADOW_OFFSET) {
218 GPU_shadow_offset(true);
219 }
220 else {
221 GPU_shadow_offset(false);
222 }
223
224 /* TODO this should be part of shader state. */
225 if (state & DRW_STATE_CLIP_PLANES) {
226 GPU_clip_distances(DST.view_active->clip_planes_len);
227 }
228 else {
229 GPU_clip_distances(0);
230 }
231
232 if (state & DRW_STATE_IN_FRONT_SELECT) {
233 /* XXX `GPU_depth_range` is not a perfect solution
234 * since very distant geometries can still be occluded.
235 * Also the depth test precision of these geometries is impaired.
236 * However, it solves the selection for the vast majority of cases. */
237 GPU_depth_range(0.0f, 0.01f);
238 }
239 else {
240 GPU_depth_range(0.0f, 1.0f);
241 }
242
243 if (state & DRW_STATE_PROGRAM_POINT_SIZE) {
244 GPU_program_point_size(true);
245 }
246 else {
247 GPU_program_point_size(false);
248 }
249
250 if (state & DRW_STATE_FIRST_VERTEX_CONVENTION) {
251 GPU_provoking_vertex(GPU_VERTEX_FIRST);
252 }
253 else {
254 GPU_provoking_vertex(GPU_VERTEX_LAST);
255 }
256
257 DST.state = state;
258 }
259
drw_stencil_state_set(uint write_mask,uint reference,uint compare_mask)260 static void drw_stencil_state_set(uint write_mask, uint reference, uint compare_mask)
261 {
262 /* Reminders:
263 * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value)
264 * stencil_value being the value stored in the stencil buffer.
265 * - (write-mask & reference) is what gets written if the test condition is fulfilled.
266 **/
267 GPU_stencil_write_mask_set(write_mask);
268 GPU_stencil_reference_set(reference);
269 GPU_stencil_compare_mask_set(compare_mask);
270 }
271
272 /* Reset state to not interfer with other UI drawcall */
DRW_state_reset_ex(DRWState state)273 void DRW_state_reset_ex(DRWState state)
274 {
275 DST.state = ~state;
276 drw_state_set(state);
277 }
278
drw_state_validate(void)279 static void drw_state_validate(void)
280 {
281 /* Cannot write to stencil buffer without stencil test. */
282 if ((DST.state & DRW_STATE_WRITE_STENCIL_ENABLED)) {
283 BLI_assert(DST.state & DRW_STATE_STENCIL_TEST_ENABLED);
284 }
285 /* Cannot write to depth buffer without depth test. */
286 if ((DST.state & DRW_STATE_WRITE_DEPTH)) {
287 BLI_assert(DST.state & DRW_STATE_DEPTH_TEST_ENABLED);
288 }
289 }
290
291 /**
292 * Use with care, intended so selection code can override passes depth settings,
293 * which is important for selection to work properly.
294 *
295 * Should be set in main draw loop, cleared afterwards
296 */
DRW_state_lock(DRWState state)297 void DRW_state_lock(DRWState state)
298 {
299 DST.state_lock = state;
300
301 /* We must get the current state to avoid overriding it. */
302 /* Not complete, but that just what we need for now. */
303 if (state & DRW_STATE_WRITE_DEPTH) {
304 SET_FLAG_FROM_TEST(DST.state, GPU_depth_mask_get(), DRW_STATE_WRITE_DEPTH);
305 }
306 if (state & DRW_STATE_DEPTH_TEST_ENABLED) {
307 DST.state &= ~DRW_STATE_DEPTH_TEST_ENABLED;
308
309 switch (GPU_depth_test_get()) {
310 case GPU_DEPTH_ALWAYS:
311 DST.state |= DRW_STATE_DEPTH_ALWAYS;
312 break;
313 case GPU_DEPTH_LESS:
314 DST.state |= DRW_STATE_DEPTH_LESS;
315 break;
316 case GPU_DEPTH_LESS_EQUAL:
317 DST.state |= DRW_STATE_DEPTH_LESS_EQUAL;
318 break;
319 case GPU_DEPTH_EQUAL:
320 DST.state |= DRW_STATE_DEPTH_EQUAL;
321 break;
322 case GPU_DEPTH_GREATER:
323 DST.state |= DRW_STATE_DEPTH_GREATER;
324 break;
325 case GPU_DEPTH_GREATER_EQUAL:
326 DST.state |= DRW_STATE_DEPTH_GREATER_EQUAL;
327 break;
328 default:
329 break;
330 }
331 }
332 }
333
DRW_state_reset(void)334 void DRW_state_reset(void)
335 {
336 DRW_state_reset_ex(DRW_STATE_DEFAULT);
337
338 GPU_texture_unbind_all();
339 GPU_uniformbuf_unbind_all();
340
341 /* Should stay constant during the whole rendering. */
342 GPU_point_size(5);
343 GPU_line_smooth(false);
344 /* Bypass U.pixelsize factor by using a factor of 0.0f. Will be clamped to 1.0f. */
345 GPU_line_width(0.0f);
346 }
347
348 /** \} */
349
350 /* -------------------------------------------------------------------- */
351 /** \name Culling (DRW_culling)
352 * \{ */
353
draw_call_is_culled(const DRWResourceHandle * handle,DRWView * view)354 static bool draw_call_is_culled(const DRWResourceHandle *handle, DRWView *view)
355 {
356 DRWCullingState *culling = DRW_memblock_elem_from_handle(DST.vmempool->cullstates, handle);
357 return (culling->mask & view->culling_mask) != 0;
358 }
359
360 /* Set active view for rendering. */
DRW_view_set_active(DRWView * view)361 void DRW_view_set_active(DRWView *view)
362 {
363 DST.view_active = (view) ? view : DST.view_default;
364 }
365
366 /* Return True if the given BoundSphere intersect the current view frustum */
draw_culling_sphere_test(const BoundSphere * frustum_bsphere,const float (* frustum_planes)[4],const BoundSphere * bsphere)367 static bool draw_culling_sphere_test(const BoundSphere *frustum_bsphere,
368 const float (*frustum_planes)[4],
369 const BoundSphere *bsphere)
370 {
371 /* Bypass test if radius is negative. */
372 if (bsphere->radius < 0.0f) {
373 return true;
374 }
375
376 /* Do a rough test first: Sphere VS Sphere intersect. */
377 float center_dist_sq = len_squared_v3v3(bsphere->center, frustum_bsphere->center);
378 float radius_sum = bsphere->radius + frustum_bsphere->radius;
379 if (center_dist_sq > square_f(radius_sum)) {
380 return false;
381 }
382 /* TODO we could test against the inscribed sphere of the frustum to early out positively. */
383
384 /* Test against the 6 frustum planes. */
385 /* TODO order planes with sides first then far then near clip. Should be better culling
386 * heuristic when sculpting. */
387 for (int p = 0; p < 6; p++) {
388 float dist = plane_point_side_v3(frustum_planes[p], bsphere->center);
389 if (dist < -bsphere->radius) {
390 return false;
391 }
392 }
393 return true;
394 }
395
draw_culling_box_test(const float (* frustum_planes)[4],const BoundBox * bbox)396 static bool draw_culling_box_test(const float (*frustum_planes)[4], const BoundBox *bbox)
397 {
398 /* 6 view frustum planes */
399 for (int p = 0; p < 6; p++) {
400 /* 8 box vertices. */
401 for (int v = 0; v < 8; v++) {
402 float dist = plane_point_side_v3(frustum_planes[p], bbox->vec[v]);
403 if (dist > 0.0f) {
404 /* At least one point in front of this plane.
405 * Go to next plane. */
406 break;
407 }
408 if (v == 7) {
409 /* 8 points behind this plane. */
410 return false;
411 }
412 }
413 }
414 return true;
415 }
416
draw_culling_plane_test(const BoundBox * corners,const float plane[4])417 static bool draw_culling_plane_test(const BoundBox *corners, const float plane[4])
418 {
419 /* Test against the 8 frustum corners. */
420 for (int c = 0; c < 8; c++) {
421 float dist = plane_point_side_v3(plane, corners->vec[c]);
422 if (dist < 0.0f) {
423 return true;
424 }
425 }
426 return false;
427 }
428
429 /* Return True if the given BoundSphere intersect the current view frustum.
430 * bsphere must be in world space. */
DRW_culling_sphere_test(const DRWView * view,const BoundSphere * bsphere)431 bool DRW_culling_sphere_test(const DRWView *view, const BoundSphere *bsphere)
432 {
433 view = view ? view : DST.view_default;
434 return draw_culling_sphere_test(&view->frustum_bsphere, view->frustum_planes, bsphere);
435 }
436
437 /* Return True if the given BoundBox intersect the current view frustum.
438 * bbox must be in world space. */
DRW_culling_box_test(const DRWView * view,const BoundBox * bbox)439 bool DRW_culling_box_test(const DRWView *view, const BoundBox *bbox)
440 {
441 view = view ? view : DST.view_default;
442 return draw_culling_box_test(view->frustum_planes, bbox);
443 }
444
445 /* Return True if the view frustum is inside or intersect the given plane.
446 * plane must be in world space. */
DRW_culling_plane_test(const DRWView * view,const float plane[4])447 bool DRW_culling_plane_test(const DRWView *view, const float plane[4])
448 {
449 view = view ? view : DST.view_default;
450 return draw_culling_plane_test(&view->frustum_corners, plane);
451 }
452
453 /* Return True if the given box intersect the current view frustum.
454 * This function will have to be replaced when world space bb per objects is implemented. */
DRW_culling_min_max_test(const DRWView * view,float obmat[4][4],float min[3],float max[3])455 bool DRW_culling_min_max_test(const DRWView *view, float obmat[4][4], float min[3], float max[3])
456 {
457 view = view ? view : DST.view_default;
458 float tobmat[4][4];
459 transpose_m4_m4(tobmat, obmat);
460 for (int i = 6; i--;) {
461 float frustum_plane_local[4], bb_near[3], bb_far[3];
462 mul_v4_m4v4(frustum_plane_local, tobmat, view->frustum_planes[i]);
463 aabb_get_near_far_from_plane(frustum_plane_local, min, max, bb_near, bb_far);
464
465 if (plane_point_side_v3(frustum_plane_local, bb_far) < 0.0f) {
466 return false;
467 }
468 }
469
470 return true;
471 }
472
DRW_culling_frustum_corners_get(const DRWView * view,BoundBox * corners)473 void DRW_culling_frustum_corners_get(const DRWView *view, BoundBox *corners)
474 {
475 view = view ? view : DST.view_default;
476 *corners = view->frustum_corners;
477 }
478
DRW_culling_frustum_planes_get(const DRWView * view,float planes[6][4])479 void DRW_culling_frustum_planes_get(const DRWView *view, float planes[6][4])
480 {
481 view = view ? view : DST.view_default;
482 memcpy(planes, view->frustum_planes, sizeof(float[6][4]));
483 }
484
draw_compute_culling(DRWView * view)485 static void draw_compute_culling(DRWView *view)
486 {
487 view = view->parent ? view->parent : view;
488
489 /* TODO(fclem): multi-thread this. */
490 /* TODO(fclem): compute all dirty views at once. */
491 if (!view->is_dirty) {
492 return;
493 }
494
495 BLI_memblock_iter iter;
496 BLI_memblock_iternew(DST.vmempool->cullstates, &iter);
497 DRWCullingState *cull;
498 while ((cull = BLI_memblock_iterstep(&iter))) {
499 if (cull->bsphere.radius < 0.0) {
500 cull->mask = 0;
501 }
502 else {
503 bool culled = !draw_culling_sphere_test(
504 &view->frustum_bsphere, view->frustum_planes, &cull->bsphere);
505
506 #ifdef DRW_DEBUG_CULLING
507 if (G.debug_value != 0) {
508 if (culled) {
509 DRW_debug_sphere(
510 cull->bsphere.center, cull->bsphere.radius, (const float[4]){1, 0, 0, 1});
511 }
512 else {
513 DRW_debug_sphere(
514 cull->bsphere.center, cull->bsphere.radius, (const float[4]){0, 1, 0, 1});
515 }
516 }
517 #endif
518
519 if (view->visibility_fn) {
520 culled = !view->visibility_fn(!culled, cull->user_data);
521 }
522
523 SET_FLAG_FROM_TEST(cull->mask, culled, view->culling_mask);
524 }
525 }
526
527 view->is_dirty = false;
528 }
529
530 /** \} */
531
532 /* -------------------------------------------------------------------- */
533 /** \name Draw (DRW_draw)
534 * \{ */
535
draw_legacy_matrix_update(DRWShadingGroup * shgroup,DRWResourceHandle * handle,float obmat_loc,float obinv_loc)536 BLI_INLINE void draw_legacy_matrix_update(DRWShadingGroup *shgroup,
537 DRWResourceHandle *handle,
538 float obmat_loc,
539 float obinv_loc)
540 {
541 /* Still supported for compatibility with gpu_shader_* but should be forbidden. */
542 DRWObjectMatrix *ob_mats = DRW_memblock_elem_from_handle(DST.vmempool->obmats, handle);
543 if (obmat_loc != -1) {
544 GPU_shader_uniform_vector(shgroup->shader, obmat_loc, 16, 1, (float *)ob_mats->model);
545 }
546 if (obinv_loc != -1) {
547 GPU_shader_uniform_vector(shgroup->shader, obinv_loc, 16, 1, (float *)ob_mats->modelinverse);
548 }
549 }
550
draw_geometry_bind(DRWShadingGroup * shgroup,GPUBatch * geom)551 BLI_INLINE void draw_geometry_bind(DRWShadingGroup *shgroup, GPUBatch *geom)
552 {
553 DST.batch = geom;
554
555 GPU_batch_set_shader(geom, shgroup->shader);
556 }
557
draw_geometry_execute(DRWShadingGroup * shgroup,GPUBatch * geom,int vert_first,int vert_count,int inst_first,int inst_count,int baseinst_loc)558 BLI_INLINE void draw_geometry_execute(DRWShadingGroup *shgroup,
559 GPUBatch *geom,
560 int vert_first,
561 int vert_count,
562 int inst_first,
563 int inst_count,
564 int baseinst_loc)
565 {
566 /* inst_count can be -1. */
567 inst_count = max_ii(0, inst_count);
568
569 if (baseinst_loc != -1) {
570 /* Fallback when ARB_shader_draw_parameters is not supported. */
571 GPU_shader_uniform_vector_int(shgroup->shader, baseinst_loc, 1, 1, (int *)&inst_first);
572 /* Avoids VAO reconfiguration on older hardware. (see GPU_batch_draw_advanced) */
573 inst_first = 0;
574 }
575
576 /* bind vertex array */
577 if (DST.batch != geom) {
578 draw_geometry_bind(shgroup, geom);
579 }
580
581 GPU_batch_draw_advanced(geom, vert_first, vert_count, inst_first, inst_count);
582 }
583
draw_indirect_call(DRWShadingGroup * shgroup,DRWCommandsState * state)584 BLI_INLINE void draw_indirect_call(DRWShadingGroup *shgroup, DRWCommandsState *state)
585 {
586 if (state->inst_count == 0) {
587 return;
588 }
589 if (state->baseinst_loc == -1) {
590 /* bind vertex array */
591 if (DST.batch != state->batch) {
592 GPU_draw_list_submit(DST.draw_list);
593 draw_geometry_bind(shgroup, state->batch);
594 }
595 GPU_draw_list_append(DST.draw_list, state->batch, state->base_inst, state->inst_count);
596 }
597 /* Fallback when unsupported */
598 else {
599 draw_geometry_execute(
600 shgroup, state->batch, 0, 0, state->base_inst, state->inst_count, state->baseinst_loc);
601 }
602 }
603
draw_update_uniforms(DRWShadingGroup * shgroup,DRWCommandsState * state,bool * use_tfeedback)604 static void draw_update_uniforms(DRWShadingGroup *shgroup,
605 DRWCommandsState *state,
606 bool *use_tfeedback)
607 {
608 for (DRWUniformChunk *unichunk = shgroup->uniforms; unichunk; unichunk = unichunk->next) {
609 DRWUniform *uni = unichunk->uniforms;
610 for (int i = 0; i < unichunk->uniform_used; i++, uni++) {
611 switch (uni->type) {
612 case DRW_UNIFORM_INT_COPY:
613 GPU_shader_uniform_vector_int(
614 shgroup->shader, uni->location, uni->length, uni->arraysize, uni->ivalue);
615 break;
616 case DRW_UNIFORM_INT:
617 GPU_shader_uniform_vector_int(
618 shgroup->shader, uni->location, uni->length, uni->arraysize, uni->pvalue);
619 break;
620 case DRW_UNIFORM_FLOAT_COPY:
621 GPU_shader_uniform_vector(
622 shgroup->shader, uni->location, uni->length, uni->arraysize, uni->fvalue);
623 break;
624 case DRW_UNIFORM_FLOAT:
625 GPU_shader_uniform_vector(
626 shgroup->shader, uni->location, uni->length, uni->arraysize, uni->pvalue);
627 break;
628 case DRW_UNIFORM_TEXTURE:
629 GPU_texture_bind_ex(uni->texture, uni->sampler_state, uni->location, false);
630 break;
631 case DRW_UNIFORM_TEXTURE_REF:
632 GPU_texture_bind_ex(*uni->texture_ref, uni->sampler_state, uni->location, false);
633 break;
634 case DRW_UNIFORM_IMAGE:
635 GPU_texture_image_bind(uni->texture, uni->location);
636 break;
637 case DRW_UNIFORM_IMAGE_REF:
638 GPU_texture_image_bind(*uni->texture_ref, uni->location);
639 break;
640 case DRW_UNIFORM_BLOCK:
641 GPU_uniformbuf_bind(uni->block, uni->location);
642 break;
643 case DRW_UNIFORM_BLOCK_REF:
644 GPU_uniformbuf_bind(*uni->block_ref, uni->location);
645 break;
646 case DRW_UNIFORM_BLOCK_OBMATS:
647 state->obmats_loc = uni->location;
648 GPU_uniformbuf_bind(DST.vmempool->matrices_ubo[0], uni->location);
649 break;
650 case DRW_UNIFORM_BLOCK_OBINFOS:
651 state->obinfos_loc = uni->location;
652 GPU_uniformbuf_bind(DST.vmempool->obinfos_ubo[0], uni->location);
653 break;
654 case DRW_UNIFORM_RESOURCE_CHUNK:
655 state->chunkid_loc = uni->location;
656 GPU_shader_uniform_int(shgroup->shader, uni->location, 0);
657 break;
658 case DRW_UNIFORM_RESOURCE_ID:
659 state->resourceid_loc = uni->location;
660 break;
661 case DRW_UNIFORM_TFEEDBACK_TARGET:
662 BLI_assert(uni->pvalue && (*use_tfeedback == false));
663 *use_tfeedback = GPU_shader_transform_feedback_enable(shgroup->shader,
664 ((GPUVertBuf *)uni->pvalue));
665 break;
666 /* Legacy/Fallback support. */
667 case DRW_UNIFORM_BASE_INSTANCE:
668 state->baseinst_loc = uni->location;
669 break;
670 case DRW_UNIFORM_MODEL_MATRIX:
671 state->obmat_loc = uni->location;
672 break;
673 case DRW_UNIFORM_MODEL_MATRIX_INVERSE:
674 state->obinv_loc = uni->location;
675 break;
676 }
677 }
678 }
679 }
680
draw_select_buffer(DRWShadingGroup * shgroup,DRWCommandsState * state,GPUBatch * batch,const DRWResourceHandle * handle)681 BLI_INLINE void draw_select_buffer(DRWShadingGroup *shgroup,
682 DRWCommandsState *state,
683 GPUBatch *batch,
684 const DRWResourceHandle *handle)
685 {
686 const bool is_instancing = (batch->inst[0] != NULL);
687 int start = 0;
688 int count = 1;
689 int tot = is_instancing ? GPU_vertbuf_get_vertex_len(batch->inst[0]) :
690 GPU_vertbuf_get_vertex_len(batch->verts[0]);
691 /* Hack : get "vbo" data without actually drawing. */
692 int *select_id = (void *)GPU_vertbuf_get_data(state->select_buf);
693
694 /* Batching */
695 if (!is_instancing) {
696 /* FIXME: Meh a bit nasty. */
697 if (batch->prim_type == GPU_PRIM_TRIS) {
698 count = 3;
699 }
700 else if (batch->prim_type == GPU_PRIM_LINES) {
701 count = 2;
702 }
703 }
704
705 while (start < tot) {
706 GPU_select_load_id(select_id[start]);
707 if (is_instancing) {
708 draw_geometry_execute(shgroup, batch, 0, 0, start, count, state->baseinst_loc);
709 }
710 else {
711 draw_geometry_execute(
712 shgroup, batch, start, count, DRW_handle_id_get(handle), 0, state->baseinst_loc);
713 }
714 start += count;
715 }
716 }
717
718 typedef struct DRWCommandIterator {
719 int cmd_index;
720 DRWCommandChunk *curr_chunk;
721 } DRWCommandIterator;
722
draw_command_iter_begin(DRWCommandIterator * iter,DRWShadingGroup * shgroup)723 static void draw_command_iter_begin(DRWCommandIterator *iter, DRWShadingGroup *shgroup)
724 {
725 iter->curr_chunk = shgroup->cmd.first;
726 iter->cmd_index = 0;
727 }
728
draw_command_iter_step(DRWCommandIterator * iter,eDRWCommandType * cmd_type)729 static DRWCommand *draw_command_iter_step(DRWCommandIterator *iter, eDRWCommandType *cmd_type)
730 {
731 if (iter->curr_chunk) {
732 if (iter->cmd_index == iter->curr_chunk->command_len) {
733 iter->curr_chunk = iter->curr_chunk->next;
734 iter->cmd_index = 0;
735 }
736 if (iter->curr_chunk) {
737 *cmd_type = command_type_get(iter->curr_chunk->command_type, iter->cmd_index);
738 if (iter->cmd_index < iter->curr_chunk->command_used) {
739 return iter->curr_chunk->commands + iter->cmd_index++;
740 }
741 }
742 }
743 return NULL;
744 }
745
draw_call_resource_bind(DRWCommandsState * state,const DRWResourceHandle * handle)746 static void draw_call_resource_bind(DRWCommandsState *state, const DRWResourceHandle *handle)
747 {
748 /* Front face is not a resource but it is inside the resource handle. */
749 bool neg_scale = DRW_handle_negative_scale_get(handle);
750 if (neg_scale != state->neg_scale) {
751 state->neg_scale = neg_scale;
752 GPU_front_facing(neg_scale != DST.view_active->is_inverted);
753 }
754
755 int chunk = DRW_handle_chunk_get(handle);
756 if (state->resource_chunk != chunk) {
757 if (state->chunkid_loc != -1) {
758 GPU_shader_uniform_int(DST.shader, state->chunkid_loc, chunk);
759 }
760 if (state->obmats_loc != -1) {
761 GPU_uniformbuf_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]);
762 GPU_uniformbuf_bind(DST.vmempool->matrices_ubo[chunk], state->obmats_loc);
763 }
764 if (state->obinfos_loc != -1) {
765 GPU_uniformbuf_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]);
766 GPU_uniformbuf_bind(DST.vmempool->obinfos_ubo[chunk], state->obinfos_loc);
767 }
768 state->resource_chunk = chunk;
769 }
770
771 if (state->resourceid_loc != -1) {
772 int id = DRW_handle_id_get(handle);
773 if (state->resource_id != id) {
774 GPU_shader_uniform_int(DST.shader, state->resourceid_loc, id);
775 state->resource_id = id;
776 }
777 }
778 }
779
draw_call_batching_flush(DRWShadingGroup * shgroup,DRWCommandsState * state)780 static void draw_call_batching_flush(DRWShadingGroup *shgroup, DRWCommandsState *state)
781 {
782 draw_indirect_call(shgroup, state);
783 GPU_draw_list_submit(DST.draw_list);
784
785 state->batch = NULL;
786 state->inst_count = 0;
787 state->base_inst = -1;
788 }
789
draw_call_single_do(DRWShadingGroup * shgroup,DRWCommandsState * state,GPUBatch * batch,DRWResourceHandle handle,int vert_first,int vert_count,int inst_first,int inst_count,bool do_base_instance)790 static void draw_call_single_do(DRWShadingGroup *shgroup,
791 DRWCommandsState *state,
792 GPUBatch *batch,
793 DRWResourceHandle handle,
794 int vert_first,
795 int vert_count,
796 int inst_first,
797 int inst_count,
798 bool do_base_instance)
799 {
800 draw_call_batching_flush(shgroup, state);
801
802 draw_call_resource_bind(state, &handle);
803
804 /* TODO This is Legacy. Need to be removed. */
805 if (state->obmats_loc == -1 && (state->obmat_loc != -1 || state->obinv_loc != -1)) {
806 draw_legacy_matrix_update(shgroup, &handle, state->obmat_loc, state->obinv_loc);
807 }
808
809 if (G.f & G_FLAG_PICKSEL) {
810 if (state->select_buf != NULL) {
811 draw_select_buffer(shgroup, state, batch, &handle);
812 return;
813 }
814
815 GPU_select_load_id(state->select_id);
816 }
817
818 draw_geometry_execute(shgroup,
819 batch,
820 vert_first,
821 vert_count,
822 do_base_instance ? DRW_handle_id_get(&handle) : inst_first,
823 inst_count,
824 state->baseinst_loc);
825 }
826
draw_call_batching_start(DRWCommandsState * state)827 static void draw_call_batching_start(DRWCommandsState *state)
828 {
829 state->neg_scale = false;
830 state->resource_chunk = 0;
831 state->resource_id = -1;
832 state->base_inst = 0;
833 state->inst_count = 0;
834 state->batch = NULL;
835
836 state->select_id = -1;
837 state->select_buf = NULL;
838 }
839
840 /* NOTE: Does not support batches with instancing VBOs. */
draw_call_batching_do(DRWShadingGroup * shgroup,DRWCommandsState * state,DRWCommandDraw * call)841 static void draw_call_batching_do(DRWShadingGroup *shgroup,
842 DRWCommandsState *state,
843 DRWCommandDraw *call)
844 {
845 /* If any condition requires to interupt the merging. */
846 bool neg_scale = DRW_handle_negative_scale_get(&call->handle);
847 int chunk = DRW_handle_chunk_get(&call->handle);
848 int id = DRW_handle_id_get(&call->handle);
849 if ((state->neg_scale != neg_scale) || /* Need to change state. */
850 (state->resource_chunk != chunk) || /* Need to change UBOs. */
851 (state->batch != call->batch) /* Need to change VAO. */
852 ) {
853 draw_call_batching_flush(shgroup, state);
854
855 state->batch = call->batch;
856 state->inst_count = 1;
857 state->base_inst = id;
858
859 draw_call_resource_bind(state, &call->handle);
860 }
861 /* Is the id consecutive? */
862 else if (id != state->base_inst + state->inst_count) {
863 /* We need to add a draw command for the pending instances. */
864 draw_indirect_call(shgroup, state);
865 state->inst_count = 1;
866 state->base_inst = id;
867 }
868 /* We avoid a drawcall by merging with the precedent
869 * drawcall using instancing. */
870 else {
871 state->inst_count++;
872 }
873 }
874
875 /* Flush remaining pending drawcalls. */
draw_call_batching_finish(DRWShadingGroup * shgroup,DRWCommandsState * state)876 static void draw_call_batching_finish(DRWShadingGroup *shgroup, DRWCommandsState *state)
877 {
878 draw_call_batching_flush(shgroup, state);
879
880 /* Reset state */
881 if (state->neg_scale) {
882 GPU_front_facing(DST.view_active->is_inverted);
883 }
884 if (state->obmats_loc != -1) {
885 GPU_uniformbuf_unbind(DST.vmempool->matrices_ubo[state->resource_chunk]);
886 }
887 if (state->obinfos_loc != -1) {
888 GPU_uniformbuf_unbind(DST.vmempool->obinfos_ubo[state->resource_chunk]);
889 }
890 }
891
draw_shgroup(DRWShadingGroup * shgroup,DRWState pass_state)892 static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
893 {
894 BLI_assert(shgroup->shader);
895
896 DRWCommandsState state = {
897 .obmats_loc = -1,
898 .obinfos_loc = -1,
899 .baseinst_loc = -1,
900 .chunkid_loc = -1,
901 .resourceid_loc = -1,
902 .obmat_loc = -1,
903 .obinv_loc = -1,
904 .drw_state_enabled = 0,
905 .drw_state_disabled = 0,
906 };
907
908 const bool shader_changed = (DST.shader != shgroup->shader);
909 bool use_tfeedback = false;
910
911 if (shader_changed) {
912 if (DST.shader) {
913 GPU_shader_unbind();
914
915 /* Unbinding can be costly. Skip in normal condition. */
916 if (G.debug & G_DEBUG_GPU) {
917 GPU_texture_unbind_all();
918 GPU_uniformbuf_unbind_all();
919 }
920 }
921 GPU_shader_bind(shgroup->shader);
922 DST.shader = shgroup->shader;
923 DST.batch = NULL;
924 }
925
926 draw_update_uniforms(shgroup, &state, &use_tfeedback);
927
928 drw_state_set(pass_state);
929
930 /* Rendering Calls */
931 {
932 DRWCommandIterator iter;
933 DRWCommand *cmd;
934 eDRWCommandType cmd_type;
935
936 draw_command_iter_begin(&iter, shgroup);
937
938 draw_call_batching_start(&state);
939
940 while ((cmd = draw_command_iter_step(&iter, &cmd_type))) {
941
942 switch (cmd_type) {
943 case DRW_CMD_DRWSTATE:
944 case DRW_CMD_STENCIL:
945 draw_call_batching_flush(shgroup, &state);
946 break;
947 case DRW_CMD_DRAW:
948 case DRW_CMD_DRAW_PROCEDURAL:
949 case DRW_CMD_DRAW_INSTANCE:
950 if (draw_call_is_culled(&cmd->instance.handle, DST.view_active)) {
951 continue;
952 }
953 break;
954 default:
955 break;
956 }
957
958 switch (cmd_type) {
959 case DRW_CMD_CLEAR:
960 GPU_framebuffer_clear(GPU_framebuffer_active_get(),
961 cmd->clear.clear_channels,
962 (float[4]){cmd->clear.r / 255.0f,
963 cmd->clear.g / 255.0f,
964 cmd->clear.b / 255.0f,
965 cmd->clear.a / 255.0f},
966 cmd->clear.depth,
967 cmd->clear.stencil);
968 break;
969 case DRW_CMD_DRWSTATE:
970 state.drw_state_enabled |= cmd->state.enable;
971 state.drw_state_disabled |= cmd->state.disable;
972 drw_state_set((pass_state & ~state.drw_state_disabled) | state.drw_state_enabled);
973 break;
974 case DRW_CMD_STENCIL:
975 drw_stencil_state_set(cmd->stencil.write_mask, cmd->stencil.ref, cmd->stencil.comp_mask);
976 break;
977 case DRW_CMD_SELECTID:
978 state.select_id = cmd->select_id.select_id;
979 state.select_buf = cmd->select_id.select_buf;
980 break;
981 case DRW_CMD_DRAW:
982 if (!USE_BATCHING || state.obmats_loc == -1 || (G.f & G_FLAG_PICKSEL) ||
983 cmd->draw.batch->inst[0]) {
984 draw_call_single_do(
985 shgroup, &state, cmd->draw.batch, cmd->draw.handle, 0, 0, 0, 0, true);
986 }
987 else {
988 draw_call_batching_do(shgroup, &state, &cmd->draw);
989 }
990 break;
991 case DRW_CMD_DRAW_PROCEDURAL:
992 draw_call_single_do(shgroup,
993 &state,
994 cmd->procedural.batch,
995 cmd->procedural.handle,
996 0,
997 cmd->procedural.vert_count,
998 0,
999 1,
1000 true);
1001 break;
1002 case DRW_CMD_DRAW_INSTANCE:
1003 draw_call_single_do(shgroup,
1004 &state,
1005 cmd->instance.batch,
1006 cmd->instance.handle,
1007 0,
1008 0,
1009 0,
1010 cmd->instance.inst_count,
1011 cmd->instance.use_attrs == 0);
1012 break;
1013 case DRW_CMD_DRAW_RANGE:
1014 draw_call_single_do(shgroup,
1015 &state,
1016 cmd->range.batch,
1017 cmd->range.handle,
1018 cmd->range.vert_first,
1019 cmd->range.vert_count,
1020 0,
1021 1,
1022 true);
1023 break;
1024 case DRW_CMD_DRAW_INSTANCE_RANGE:
1025 draw_call_single_do(shgroup,
1026 &state,
1027 cmd->instance_range.batch,
1028 cmd->instance_range.handle,
1029 0,
1030 0,
1031 cmd->instance_range.inst_first,
1032 cmd->instance_range.inst_count,
1033 false);
1034 break;
1035 }
1036 }
1037
1038 draw_call_batching_finish(shgroup, &state);
1039 }
1040
1041 if (use_tfeedback) {
1042 GPU_shader_transform_feedback_disable(shgroup->shader);
1043 }
1044 }
1045
drw_update_view(void)1046 static void drw_update_view(void)
1047 {
1048 /* TODO(fclem): update a big UBO and only bind ranges here. */
1049 GPU_uniformbuf_update(G_draw.view_ubo, &DST.view_active->storage);
1050
1051 /* TODO get rid of this. */
1052 DST.view_storage_cpy = DST.view_active->storage;
1053
1054 draw_compute_culling(DST.view_active);
1055 }
1056
drw_draw_pass_ex(DRWPass * pass,DRWShadingGroup * start_group,DRWShadingGroup * end_group)1057 static void drw_draw_pass_ex(DRWPass *pass,
1058 DRWShadingGroup *start_group,
1059 DRWShadingGroup *end_group)
1060 {
1061 if (pass->original) {
1062 start_group = pass->original->shgroups.first;
1063 end_group = pass->original->shgroups.last;
1064 }
1065
1066 if (start_group == NULL) {
1067 return;
1068 }
1069
1070 DST.shader = NULL;
1071
1072 BLI_assert(DST.buffer_finish_called &&
1073 "DRW_render_instance_buffer_finish had not been called before drawing");
1074
1075 if (DST.view_previous != DST.view_active || DST.view_active->is_dirty) {
1076 drw_update_view();
1077 DST.view_active->is_dirty = false;
1078 DST.view_previous = DST.view_active;
1079 }
1080
1081 /* GPU_framebuffer_clear calls can change the state outside the DRW module.
1082 * Force reset the affected states to avoid problems later. */
1083 drw_state_set(DST.state | DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR);
1084
1085 drw_state_set(pass->state);
1086 drw_state_validate();
1087
1088 if (DST.view_active->is_inverted) {
1089 GPU_front_facing(true);
1090 }
1091
1092 DRW_stats_query_start(pass->name);
1093
1094 for (DRWShadingGroup *shgroup = start_group; shgroup; shgroup = shgroup->next) {
1095 draw_shgroup(shgroup, pass->state);
1096 /* break if upper limit */
1097 if (shgroup == end_group) {
1098 break;
1099 }
1100 }
1101
1102 if (DST.shader) {
1103 GPU_shader_unbind();
1104 DST.shader = NULL;
1105 }
1106
1107 if (DST.batch) {
1108 DST.batch = NULL;
1109 }
1110
1111 /* Fix T67342 for some reason. AMD Pro driver bug. */
1112 if ((DST.state & DRW_STATE_BLEND_CUSTOM) != 0 &&
1113 GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) {
1114 drw_state_set(DST.state & ~DRW_STATE_BLEND_CUSTOM);
1115 }
1116
1117 /* HACK: Rasterized discard can affect clear commands which are not
1118 * part of a DRWPass (as of now). So disable rasterized discard here
1119 * if it has been enabled. */
1120 if ((DST.state & DRW_STATE_RASTERIZER_ENABLED) == 0) {
1121 drw_state_set((DST.state & ~DRW_STATE_RASTERIZER_ENABLED) | DRW_STATE_DEFAULT);
1122 }
1123
1124 /* Reset default. */
1125 if (DST.view_active->is_inverted) {
1126 GPU_front_facing(false);
1127 }
1128
1129 DRW_stats_query_end();
1130 }
1131
DRW_draw_pass(DRWPass * pass)1132 void DRW_draw_pass(DRWPass *pass)
1133 {
1134 for (; pass; pass = pass->next) {
1135 drw_draw_pass_ex(pass, pass->shgroups.first, pass->shgroups.last);
1136 }
1137 }
1138
1139 /* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */
DRW_draw_pass_subset(DRWPass * pass,DRWShadingGroup * start_group,DRWShadingGroup * end_group)1140 void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group)
1141 {
1142 drw_draw_pass_ex(pass, start_group, end_group);
1143 }
1144
1145 /** \} */
1146