[Bf-blender-cvs] [502b8e0f08c] blender-v2.83-release: GPUViewport: Use GPUBatch for viewport drawing

Jeroen Bakker noreply at git.blender.org
Thu Apr 16 08:42:37 CEST 2020


Commit: 502b8e0f08cfddc1f1c1793f14584c02e7eea39d
Author: Jeroen Bakker
Date:   Thu Apr 16 08:40:22 2020 +0200
Branches: blender-v2.83-release
https://developer.blender.org/rB502b8e0f08cfddc1f1c1793f14584c02e7eea39d

GPUViewport: Use GPUBatch for viewport drawing

When drawing the viewport to the screen the draw calls were not batched.
This resulted in measurable slowdown on Windows Intel 10th gen
platforms.

This patch would cache the last draw calls per viewport. Our API does
support partial redrawing of the viewport, but that isn't used anywhere.

This patch does not include stereoscopy rendering. This still uses the
imm approach and would still be slow on certain hardware.

Reviewed By: Clément Foucault

Differential Revision: https://developer.blender.org/D7357

===================================================================

M	source/blender/gpu/intern/gpu_viewport.c

===================================================================

diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c
index 704d1c3155e..ad74ce02731 100644
--- a/source/blender/gpu/intern/gpu_viewport.c
+++ b/source/blender/gpu/intern/gpu_viewport.c
@@ -65,6 +65,24 @@ typedef struct ViewportTempTexture {
   GPUTexture *texture;
 } ViewportTempTexture;
 
+/* Struct storing a viewport specific GPUBatch.
+ * The end-goal is to have a single batch shared across viewport and use a model matrix to place
+ * the batch. Due to OCIO and Image/UV editor we are not able to use an model matrix yet. */
+struct GPUViewportBatch {
+  GPUBatch *batch;
+  struct {
+    rctf rect_pos;
+    rctf rect_uv;
+  } last_used_parameters;
+} GPUViewportBatch;
+
+static struct {
+  GPUVertFormat format;
+  struct {
+    uint pos, tex_coord;
+  } attr_id;
+} g_viewport = {{0}};
+
 struct GPUViewport {
   int size[2];
   int flag;
@@ -98,6 +116,7 @@ struct GPUViewport {
   /* TODO(fclem) the uvimage display use the viewport but do not set any view transform for the
    * moment. The end goal would be to let the GPUViewport do the color management. */
   bool do_color_management;
+  struct GPUViewportBatch batch;
 };
 
 enum {
@@ -661,6 +680,76 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo
 
   GPU_framebuffer_restore();
 }
+/* -------------------------------------------------------------------- */
+/** \name Viewport Batches
+ * \{ */
+
+static GPUVertFormat *gpu_viewport_batch_format(void)
+{
+  if (g_viewport.format.attr_len == 0) {
+    GPUVertFormat *format = &g_viewport.format;
+    g_viewport.attr_id.pos = GPU_vertformat_attr_add(
+        format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+    g_viewport.attr_id.tex_coord = GPU_vertformat_attr_add(
+        format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
+  }
+  return &g_viewport.format;
+}
+
+static GPUBatch *gpu_viewport_batch_create(const rctf *rect_pos, const rctf *rect_uv)
+{
+  GPUVertBuf *vbo = GPU_vertbuf_create_with_format(gpu_viewport_batch_format());
+  const uint vbo_len = 4;
+  GPU_vertbuf_data_alloc(vbo, vbo_len);
+
+  GPUVertBufRaw pos_step, tex_coord_step;
+  GPU_vertbuf_attr_get_raw_data(vbo, g_viewport.attr_id.pos, &pos_step);
+  GPU_vertbuf_attr_get_raw_data(vbo, g_viewport.attr_id.tex_coord, &tex_coord_step);
+
+  copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmin, rect_pos->ymin);
+  copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmin, rect_uv->ymin);
+  copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmax, rect_pos->ymin);
+  copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmax, rect_uv->ymin);
+  copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmin, rect_pos->ymax);
+  copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmin, rect_uv->ymax);
+  copy_v2_fl2(GPU_vertbuf_raw_step(&pos_step), rect_pos->xmax, rect_pos->ymax);
+  copy_v2_fl2(GPU_vertbuf_raw_step(&tex_coord_step), rect_uv->xmax, rect_uv->ymax);
+
+  return GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
+}
+
+static GPUBatch *gpu_viewport_batch_get(GPUViewport *viewport,
+                                        const rctf *rect_pos,
+                                        const rctf *rect_uv)
+{
+  const float compare_limit = 0.0001f;
+  const bool parameters_changed =
+      (!BLI_rctf_compare(
+           &viewport->batch.last_used_parameters.rect_pos, rect_pos, compare_limit) ||
+       !BLI_rctf_compare(&viewport->batch.last_used_parameters.rect_uv, rect_uv, compare_limit));
+
+  if (viewport->batch.batch && parameters_changed) {
+    GPU_batch_discard(viewport->batch.batch);
+    viewport->batch.batch = NULL;
+  }
+
+  if (!viewport->batch.batch) {
+    viewport->batch.batch = gpu_viewport_batch_create(rect_pos, rect_uv);
+    viewport->batch.last_used_parameters.rect_pos = *rect_pos;
+    viewport->batch.last_used_parameters.rect_uv = *rect_uv;
+  }
+  return viewport->batch.batch;
+}
+
+static void gpu_viewport_batch_free(GPUViewport *viewport)
+{
+  if (viewport->batch.batch) {
+    GPU_batch_discard(viewport->batch.batch);
+    viewport->batch.batch = NULL;
+  }
+}
+
+/** \} */
 
 static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
                                            const rctf *rect_pos,
@@ -671,13 +760,17 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
   GPUTexture *color = dtxl->color;
   GPUTexture *color_overlay = dtxl->color_overlay;
 
-  GPUVertFormat *vert_format = immVertexFormat();
-  uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-  uint texco = GPU_vertformat_attr_add(vert_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
-
   bool use_ocio = false;
 
   if (viewport->do_color_management && display_colorspace) {
+    /* During the binding process the last used VertexFormat is tested and can assert as it is not
+     * valid. By calling the `immVertexFormat` the last used VertexFormat is reset and the assert
+     * does not happen. This solves a chicken and egg problem when using GPUBatches. GPUBatches
+     * contain the correct vertex format, but can only bind after the shader is bound.
+     *
+     * Image/UV editor still uses imm, after that has been changed we could move this fix to the
+     * OCIO. */
+    immVertexFormat();
     use_ocio = IMB_colormanagement_setup_glsl_draw_from_space(&viewport->view_settings,
                                                               &viewport->display_settings,
                                                               NULL,
@@ -686,38 +779,26 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport,
                                                               true);
   }
 
-  if (!use_ocio) {
-    immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE);
-    immUniform1i("display_transform", display_colorspace);
-    immUniform1i("image_texture", 0);
-    immUniform1i("overlays_texture", 1);
+  GPUBatch *batch = gpu_viewport_batch_get(viewport, rect_pos, rect_uv);
+  if (use_ocio) {
+    GPU_batch_program_set_imm_shader(batch);
+  }
+  else {
+    GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE);
+    GPU_batch_uniform_1i(batch, "display_transform", display_colorspace);
+    GPU_batch_uniform_1i(batch, "image_texture", 0);
+    GPU_batch_uniform_1i(batch, "overlays_texture", 1);
   }
 
   GPU_texture_bind(color, 0);
   GPU_texture_bind(color_overlay, 1);
-
-  immBegin(GPU_PRIM_TRI_STRIP, 4);
-
-  immAttr2f(texco, rect_uv->xmin, rect_uv->ymin);
-  immVertex2f(pos, rect_pos->xmin, rect_pos->ymin);
-  immAttr2f(texco, rect_uv->xmax, rect_uv->ymin);
-  immVertex2f(pos, rect_pos->xmax, rect_pos->ymin);
-  immAttr2f(texco, rect_uv->xmin, rect_uv->ymax);
-  immVertex2f(pos, rect_pos->xmin, rect_pos->ymax);
-  immAttr2f(texco, rect_uv->xmax, rect_uv->ymax);
-  immVertex2f(pos, rect_pos->xmax, rect_pos->ymax);
-
-  immEnd();
-
+  GPU_batch_draw(batch);
   GPU_texture_unbind(color);
   GPU_texture_unbind(color_overlay);
 
   if (use_ocio) {
     IMB_colormanagement_finish_glsl_draw();
   }
-  else {
-    immUnbindProgram();
-  }
 }
 
 /**
@@ -781,8 +862,8 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport,
  * Merge and draw the buffers of \a viewport into the currently active framebuffer, performing
  * color transform to display space.
  *
- * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done with
- *              inversed axis coordinates (upside down or sideways).
+ * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done
+ * with inversed axis coordinates (upside down or sideways).
  */
 void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect)
 {
@@ -960,6 +1041,7 @@ void GPU_viewport_free(GPUViewport *viewport)
   MEM_freeN(viewport->idatalist);
 
   BKE_color_managed_view_settings_free(&viewport->view_settings);
+  gpu_viewport_batch_free(viewport);
 
   MEM_freeN(viewport);
 }



More information about the Bf-blender-cvs mailing list