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