[Bf-blender-cvs] [aa0ecd17918] master: UI: Speed up icon scaling

Julian Eisel noreply at git.blender.org
Mon Jan 17 18:26:54 CET 2022


Commit: aa0ecd17918d5f1c3ce684f8f14b6aa7080ea9e1
Author: Julian Eisel
Date:   Mon Jan 17 18:02:29 2022 +0100
Branches: master
https://developer.blender.org/rBaa0ecd17918d5f1c3ce684f8f14b6aa7080ea9e1

UI: Speed up icon scaling

Use GPU-side scaling to speed up the scaling itself, and to avoid having
to copy the image buffer using the CPU. Mipmapping is used to get decent
filtering when downscaling without ugly artifacts.
In my comparisons, there was barely any difference between the methods
for DPIs >= 1. Below that, the result looks a bit different due to the
different filtering method.

See D13144 for screen-recordings showing the difference.

Part of T92922.

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

Reviewed by: Jeroen Bakker

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

M	source/blender/editors/include/BIF_glutil.h
M	source/blender/editors/interface/interface_icons.c
M	source/blender/editors/screen/glutil.c

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

diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 8f2a189e35e..8546c3eae89 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -54,6 +54,36 @@ typedef struct IMMDrawPixelsTexState {
  */
 IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin);
 
+/**
+ * Unlike the other `immDrawPixelsTex` functions, this doesn't do tiled drawing, but draws into a
+ * full texture.
+ *
+ * Use the currently bound shader.
+ *
+ * Use #immDrawPixelsTexSetup to bind the shader you want before calling #immDrawPixelsTex.
+ *
+ * If using a special shader double check it uses the same attributes "pos" "texCoord" and uniform
+ * "image".
+ *
+ * If color is NULL then use white by default
+ *
+ * Unless <em>state->do_shader_unbind<em> is explicitly set to `false`, the shader is unbound when
+ * finished.
+ */
+void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state,
+                                    const float x,
+                                    const float y,
+                                    const int img_w,
+                                    const int img_h,
+                                    const eGPUTextureFormat gpu_format,
+                                    const bool use_filter,
+                                    const void *rect,
+                                    const float scaleX,
+                                    const float scaleY,
+                                    const float xzoom,
+                                    const float yzoom,
+                                    const float color[4]);
+
 /**
  * #immDrawPixelsTex - Functions like a limited #glDrawPixels, but actually draws the
  * image using textures, which can be tremendously faster on low-end
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index ca5d08ba40e..085b7d04be9 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -1546,7 +1546,7 @@ static void icon_draw_rect_fast(float x,
     immUniform1f("factor", desaturate);
   }
 
-  immDrawPixelsTexScaled(
+  immDrawPixelsTexScaledFullSize(
       &state, draw_x, draw_y, rw, rh, GPU_RGBA8, true, rect, scale_x, scale_y, 1.0f, 1.0f, col);
 }
 
@@ -1561,7 +1561,6 @@ static void icon_draw_rect(float x,
                            float alpha,
                            const float desaturate)
 {
-  ImBuf *ima = NULL;
   int draw_w = w;
   int draw_h = h;
   int draw_x = x;
@@ -1577,6 +1576,8 @@ static void icon_draw_rect(float x,
   /* modulate color */
   const float col[4] = {alpha, alpha, alpha, alpha};
 
+  float scale_x = 1.0f;
+  float scale_y = 1.0f;
   /* rect contains image in 'rendersize', we only scale if needed */
   if (rw != w || rh != h) {
     /* preserve aspect ratio and center */
@@ -1590,13 +1591,9 @@ static void icon_draw_rect(float x,
       draw_h = h;
       draw_x += (w - draw_w) / 2;
     }
+    scale_x = draw_w / (float)rw;
+    scale_y = draw_h / (float)rh;
     /* If the image is squared, the `draw_*` initialization values are good. */
-
-    /* first allocate imbuf for scaling and copy preview into it */
-    ima = IMB_allocImBuf(rw, rh, 32, IB_rect);
-    memcpy(ima->rect, rect, rw * rh * sizeof(uint));
-    IMB_scaleImBuf(ima, draw_w, draw_h); /* scale it */
-    rect = ima->rect;
   }
 
   /* draw */
@@ -1613,12 +1610,8 @@ static void icon_draw_rect(float x,
     immUniform1f("factor", desaturate);
   }
 
-  immDrawPixelsTex(
-      &state, draw_x, draw_y, draw_w, draw_h, GPU_RGBA8, false, rect, 1.0f, 1.0f, col);
-
-  if (ima) {
-    IMB_freeImBuf(ima);
-  }
+  immDrawPixelsTexScaledFullSize(
+      &state, draw_x, draw_y, rw, rh, GPU_RGBA8, true, rect, scale_x, scale_y, 1.0f, 1.0f, col);
 }
 
 /* High enough to make a difference, low enough so that
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 5f523df18d1..cb5c5df20ec 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -72,6 +72,75 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
   return state;
 }
 
+void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state,
+                                    const float x,
+                                    const float y,
+                                    const int img_w,
+                                    const int img_h,
+                                    const eGPUTextureFormat gpu_format,
+                                    const bool use_filter,
+                                    const void *rect,
+                                    const float scaleX,
+                                    const float scaleY,
+                                    const float xzoom,
+                                    const float yzoom,
+                                    const float color[4])
+{
+  const static float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+  const float draw_width = img_w * scaleX * xzoom;
+  const float draw_height = img_h * scaleY * yzoom;
+  /* Downscaling with regular bilinear interpolation (i.e. #GL_LINEAR) doesn't give good filtering
+   * results. Mipmaps can be used to get better results (i.e. #GL_LINEAR_MIPMAP_LINEAR), so always
+   * use mipmaps when filtering. */
+  const bool use_mipmap = use_filter && ((draw_width < img_w) || (draw_height < img_h));
+
+  GPUTexture *tex = GPU_texture_create_2d("immDrawPixels", img_w, img_h, 1, gpu_format, NULL);
+
+  const bool use_float_data = ELEM(gpu_format, GPU_RGBA16F, GPU_RGB16F, GPU_R16F);
+  eGPUDataFormat gpu_data_format = (use_float_data) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE;
+  GPU_texture_update(tex, gpu_data_format, rect);
+
+  GPU_texture_filter_mode(tex, use_filter);
+  if (use_mipmap) {
+    GPU_texture_generate_mipmap(tex);
+    GPU_texture_mipmap_mode(tex, true, true);
+  }
+  GPU_texture_wrap_mode(tex, false, true);
+
+  GPU_texture_bind(tex, 0);
+
+  /* optional */
+  /* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since
+   * it does not need color.
+   */
+  if (state->shader != NULL && GPU_shader_get_uniform(state->shader, "color") != -1) {
+    immUniformColor4fv((color) ? color : white);
+  }
+
+  uint pos = state->pos, texco = state->texco;
+
+  immBegin(GPU_PRIM_TRI_FAN, 4);
+  immAttr2f(texco, 0.0f, 0.0f);
+  immVertex2f(pos, x, y);
+
+  immAttr2f(texco, 1.0f, 0.0f);
+  immVertex2f(pos, x + draw_width, y);
+
+  immAttr2f(texco, 1.0f, 1.0f);
+  immVertex2f(pos, x + draw_width, y + draw_height);
+
+  immAttr2f(texco, 0.0f, 1.0f);
+  immVertex2f(pos, x, y + draw_height);
+  immEnd();
+
+  if (state->do_shader_unbind) {
+    immUnbindProgram();
+  }
+
+  GPU_texture_unbind(tex);
+  GPU_texture_free(tex);
+}
+
 void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
                                      float x,
                                      float y,



More information about the Bf-blender-cvs mailing list