GPU: Refactor GPU_batch_draw_range_ex
authorClément Foucault <foucault.clem@gmail.com>
Wed, 22 May 2019 09:31:49 +0000 (11:31 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Wed, 22 May 2019 11:29:05 +0000 (13:29 +0200)
Rename it to GPU_batch_draw_advanced and use base instance when possible.

Also add GPU_batch_bind to bind the vao independantly of drawing commands.

source/blender/draw/intern/draw_manager.c
source/blender/draw/intern/draw_manager_exec.c
source/blender/editors/interface/interface_widgets.c
source/blender/editors/mesh/editmesh_knife.c
source/blender/editors/uvedit/uvedit_draw.c
source/blender/gpu/GPU_batch.h
source/blender/gpu/intern/gpu_batch.c

index 54d6752..cabf684 100644 (file)
@@ -365,7 +365,8 @@ void DRW_transform_none(GPUTexture *tex)
   GPU_batch_uniform_mat4(geom, "ModelViewProjectionMatrix", mat);
 
   GPU_batch_program_use_begin(geom);
-  GPU_batch_draw_range_ex(geom, 0, 0, false);
+  GPU_batch_bind(geom);
+  GPU_batch_draw_advanced(geom, 0, 0, 0, 0);
   GPU_batch_program_use_end(geom);
 
   GPU_texture_unbind(tex);
@@ -456,7 +457,8 @@ void DRW_multisamples_resolve(GPUTexture *src_depth, GPUTexture *src_color, bool
 
   /* avoid gpuMatrix calls */
   GPU_batch_program_use_begin(geom);
-  GPU_batch_draw_range_ex(geom, 0, 0, false);
+  GPU_batch_bind(geom);
+  GPU_batch_draw_advanced(geom, 0, 0, 0, 0);
   GPU_batch_program_use_end(geom);
 }
 
index dfffc62..0535674 100644 (file)
@@ -587,16 +587,23 @@ static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCall *call)
   }
 }
 
-static void draw_geometry_execute(
-    DRWShadingGroup *shgroup, GPUBatch *geom, uint start, uint count, bool draw_instance)
+static void draw_geometry_execute(DRWShadingGroup *shgroup,
+                                  GPUBatch *geom,
+                                  uint vert_first,
+                                  uint vert_count,
+                                  uint inst_first,
+                                  uint inst_count)
 {
-  /* step 2 : bind vertex array & draw */
+  /* bind vertex array */
   GPU_batch_program_set_no_use(
       geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader));
+
+  GPU_batch_bind(geom);
+
   /* XXX hacking gawain. we don't want to call glUseProgram! (huge performance loss) */
   geom->program_in_use = true;
 
-  GPU_batch_draw_range_ex(geom, start, count, draw_instance);
+  GPU_batch_draw_advanced(geom, vert_first, vert_count, inst_first, inst_count);
 
   geom->program_in_use = false; /* XXX hacking gawain */
 }
@@ -859,7 +866,12 @@ BLI_INLINE bool draw_select_do_call(DRWShadingGroup *shgroup, DRWCall *call)
 
     while (start < tot) {
       GPU_select_load_id(select_id[start]);
-      draw_geometry_execute(shgroup, call->batch, start, count, is_instancing);
+      if (is_instancing) {
+        draw_geometry_execute(shgroup, call->batch, 0, 0, start, count);
+      }
+      else {
+        draw_geometry_execute(shgroup, call->batch, start, count, 0, 0);
+      }
       start += count;
     }
     return true;
@@ -930,13 +942,8 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
         continue;
       }
 
-      /* TODO revisit when DRW_SHG_INSTANCE and the like is gone. */
-      if (call->inst_count == 0) {
-        draw_geometry_execute(shgroup, call->batch, call->vert_first, call->vert_count, false);
-      }
-      else {
-        draw_geometry_execute(shgroup, call->batch, 0, call->inst_count, true);
-      }
+      draw_geometry_execute(
+          shgroup, call->batch, call->vert_first, call->vert_count, 0, call->inst_count);
     }
     /* Reset state */
     glFrontFace(GL_CCW);
index 5947933..e31646f 100644 (file)
@@ -1261,7 +1261,9 @@ void UI_widgetbase_draw_cache_flush(void)
                                 (float *)g_widget_base_batch.params);
     GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
     GPU_matrix_bind(batch->interface);
-    GPU_batch_draw_range_ex(batch, 0, g_widget_base_batch.count, true);
+    GPU_batch_bind(batch);
+    GPU_batch_draw_advanced(batch, 0, 0, 0, g_widget_base_batch.count);
+
     GPU_batch_program_use_end(batch);
   }
   g_widget_base_batch.count = 0;
index e45c15b..976dbe0 100644 (file)
@@ -1156,19 +1156,20 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(ar), void
 
     GPUBatch *batch = GPU_batch_create_ex(GPU_PRIM_POINTS, vert, NULL, GPU_BATCH_OWNS_VBO);
     GPU_batch_program_set_builtin(batch, GPU_SHADER_3D_UNIFORM_COLOR);
+    GPU_batch_bind(batch);
 
     /* draw any snapped verts first */
     rgba_uchar_to_float(fcol, kcd->colors.point_a);
     GPU_batch_uniform_4fv(batch, "color", fcol);
     GPU_matrix_bind(batch->interface);
     GPU_point_size(11);
-    GPU_batch_draw_range_ex(batch, 0, v - 1, false);
+    GPU_batch_draw_advanced(batch, 0, v - 1, 0, 0);
 
     /* now draw the rest */
     rgba_uchar_to_float(fcol, kcd->colors.curpoint_a);
     GPU_batch_uniform_4fv(batch, "color", fcol);
     GPU_point_size(7);
-    GPU_batch_draw_range_ex(batch, vs + 1, kcd->totlinehit - (vs + 1), false);
+    GPU_batch_draw_advanced(batch, vs + 1, kcd->totlinehit - (vs + 1), 0, 0);
 
     GPU_batch_program_use_end(batch);
     GPU_batch_discard(batch);
index 3a5aead..7f9b90f 100644 (file)
@@ -246,6 +246,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
     bool prev_ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1));
 
     GPU_matrix_bind(geom->interface);
+    GPU_batch_bind(geom);
 
     /* TODO(fclem): If drawcall count becomes a problem in the future
      * we can use multi draw indirect drawcalls for this.
@@ -254,7 +255,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
       bool ma_match = (mpoly->mat_nr == (eval_ob->actcol - 1));
       if (ma_match != prev_ma_match) {
         if (ma_match == false) {
-          GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false);
+          GPU_batch_draw_advanced(geom, draw_start, idx - draw_start, 0, 0);
         }
         else {
           draw_start = idx;
@@ -264,7 +265,7 @@ static void draw_uvs_texpaint(Scene *scene, Object *ob, Depsgraph *depsgraph)
       prev_ma_match = ma_match;
     }
     if (prev_ma_match == true) {
-      GPU_batch_draw_range_ex(geom, draw_start, idx - draw_start, false);
+      GPU_batch_draw_advanced(geom, draw_start, idx - draw_start, 0, 0);
     }
 
     GPU_batch_program_use_end(geom);
index c48d49b..3b0d728 100644 (file)
@@ -148,8 +148,10 @@ void GPU_batch_uniform_mat4(GPUBatch *, const char *name, const float data[4][4]
 
 void GPU_batch_draw(GPUBatch *);
 
+/* Needs to be called before GPU_batch_draw_advanced. */
+void GPU_batch_bind(GPUBatch *);
 /* This does not bind/unbind shader and does not call GPU_matrix_bind() */
-void GPU_batch_draw_range_ex(GPUBatch *, int v_first, int v_count, bool force_instance);
+void GPU_batch_draw_advanced(GPUBatch *, int v_first, int v_count, int i_first, int i_count);
 
 /* Does not even need batch */
 void GPU_draw_primitive(GPUPrimType, int v_count);
index 76a250a..933bcb2 100644 (file)
@@ -577,10 +577,14 @@ static void *elem_offset(const GPUIndexBuf *el, int v_first)
   else if (el->index_type == GPU_INDEX_U16) {
     return (GLushort *)0 + v_first;
   }
-  else {
 #endif
-    return (GLuint *)0 + v_first;
-  }
+  return (GLuint *)0 + v_first;
+}
+
+/* Use when drawing with GPU_batch_draw_advanced */
+void GPU_batch_bind(GPUBatch *batch)
+{
+  glBindVertexArray(batch->vao_id);
 }
 
 void GPU_batch_draw(GPUBatch *batch)
@@ -592,103 +596,76 @@ void GPU_batch_draw(GPUBatch *batch)
   GPU_batch_program_use_begin(batch);
   GPU_matrix_bind(batch->interface);  // external call.
 
-  GPU_batch_draw_range_ex(batch, 0, 0, false);
+  GPU_batch_bind(batch);
+  GPU_batch_draw_advanced(batch, 0, 0, 0, 0);
 
   GPU_batch_program_use_end(batch);
 }
 
-void GPU_batch_draw_range_ex(GPUBatch *batch, int v_first, int v_count, bool force_instance)
+void GPU_batch_draw_advanced(GPUBatch *batch, int v_first, int v_count, int i_first, int i_count)
 {
 #if TRUST_NO_ONE
-  assert(!(force_instance && (batch->inst == NULL)) ||
-         v_count > 0);  // we cannot infer length if force_instance
+  BLI_assert(batch->program_in_use);
+  /* TODO could assert that VAO is bound. */
 #endif
 
-  const bool do_instance = (force_instance || batch->inst);
-
-  // If using offset drawing, use the default VAO and redo bindings.
-  if (v_first != 0 && do_instance) {
-    glBindVertexArray(GPU_vao_default());
-    batch_update_program_bindings(batch, v_first);
+  if (v_count == 0) {
+    v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len;
   }
-  else {
-    glBindVertexArray(batch->vao_id);
+  if (i_count == 0) {
+    i_count = (batch->inst) ? batch->inst->vertex_len : 1;
   }
 
-  if (do_instance) {
-    /* Infer length if vertex count is not given */
-    if (v_count == 0) {
-      v_count = batch->inst->vertex_len;
+  if (!GLEW_ARB_base_instance) {
+    if (i_first > 0 && i_count > 0) {
+      /* If using offset drawing with instancing, we must
+       * use the default VAO and redo bindings. */
+      glBindVertexArray(GPU_vao_default());
+      batch_update_program_bindings(batch, v_first);
     }
+    else {
+      /* Previous call could have bind the default vao
+       * see above. */
+      glBindVertexArray(batch->vao_id);
+    }
+  }
 
-    if (batch->elem) {
-      const GPUIndexBuf *el = batch->elem;
-
-      if (el->use_prim_restart) {
-        primitive_restart_enable(el);
-      }
+  if (batch->elem) {
+    const GPUIndexBuf *el = batch->elem;
 #if GPU_TRACK_INDEX_RANGE
-      glDrawElementsInstancedBaseVertex(
-          batch->gl_prim_type, el->index_len, el->gl_index_type, 0, v_count, el->base_index);
+    GLenum index_type = el->gl_index_type;
+    GLint base_index = el->base_index;
 #else
-      glDrawElementsInstanced(batch->gl_prim_type, el->index_len, GL_UNSIGNED_INT, 0, v_count);
+    GLenum index_type = GL_UNSIGNED_INT;
+    GLint base_index = 0;
 #endif
-      if (el->use_prim_restart) {
-        primitive_restart_disable();
-      }
+    void *v_first_ofs = elem_offset(el, v_first);
+
+    if (el->use_prim_restart) {
+      primitive_restart_enable(el);
+    }
+
+    if (GLEW_ARB_base_instance) {
+      glDrawElementsInstancedBaseVertexBaseInstance(
+          batch->gl_prim_type, v_count, index_type, v_first_ofs, i_count, base_index, i_first);
     }
     else {
-      glDrawArraysInstanced(batch->gl_prim_type, 0, batch->verts[0]->vertex_len, v_count);
+      glDrawElementsInstancedBaseVertex(
+          batch->gl_prim_type, v_count, index_type, v_first_ofs, i_count, base_index);
+    }
+
+    if (el->use_prim_restart) {
+      primitive_restart_disable();
     }
   }
   else {
-    /* Infer length if vertex count is not given */
-    if (v_count == 0) {
-      v_count = (batch->elem) ? batch->elem->index_len : batch->verts[0]->vertex_len;
-    }
-
-    if (batch->elem) {
-      const GPUIndexBuf *el = batch->elem;
-
-      if (el->use_prim_restart) {
-        primitive_restart_enable(el);
-      }
-
-      void *v_first_ofs = elem_offset(el, v_first);
-
-#if GPU_TRACK_INDEX_RANGE
-      if (el->base_index) {
-        glDrawRangeElementsBaseVertex(batch->gl_prim_type,
-                                      el->min_index,
-                                      el->max_index,
-                                      v_count,
-                                      el->gl_index_type,
-                                      v_first_ofs,
-                                      el->base_index);
-      }
-      else {
-        glDrawRangeElements(batch->gl_prim_type,
-                            el->min_index,
-                            el->max_index,
-                            v_count,
-                            el->gl_index_type,
-                            v_first_ofs);
-      }
-#else
-      glDrawElements(batch->gl_prim_type, v_count, GL_UNSIGNED_INT, v_first_ofs);
-#endif
-      if (el->use_prim_restart) {
-        primitive_restart_disable();
-      }
+    if (GLEW_ARB_base_instance) {
+      glDrawArraysInstancedBaseInstance(batch->gl_prim_type, v_first, v_count, i_count, i_first);
     }
     else {
-      glDrawArrays(batch->gl_prim_type, v_first, v_count);
+      glDrawArraysInstanced(batch->gl_prim_type, v_first, v_count, i_count);
     }
   }
-
-  /* Performance hog if you are drawing with the same vao multiple time.
-   * Only activate for debugging. */
-  // glBindVertexArray(0);
 }
 
 /* just draw some vertices and let shader place them where we want. */