Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2018-03-31 20:32:28 +0300
committerClément Foucault <foucault.clem@gmail.com>2018-03-31 20:43:22 +0300
commitc77870fc78f594411c9831ee77eba2167a702fd7 (patch)
tree8ca99ec3f8745f2b3c4cd1f8e85df8e550ae5534 /source/blender/editors
parent4dc0c923fb7f5c9c6f36ce0a63c1d19f241befa2 (diff)
UI: Perf: Batch icons drawcalls together.
For this we use a new shader that gets it's data from a uniform array. Vertex shader position the vertices using these data. Using glUniform is way faster than using imm for that matter. Like BLF rendering, UI icons are always (as far as I know) non occluded and displayed above everything else. They also does not overlap with texts so they can be batched at the same time.
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/include/UI_interface_icons.h3
-rw-r--r--source/blender/editors/interface/interface.c3
-rw-r--r--source/blender/editors/interface/interface_icons.c107
3 files changed, 112 insertions, 1 deletions
diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h
index cee68ed361c..8b436942fdd 100644
--- a/source/blender/editors/include/UI_interface_icons.h
+++ b/source/blender/editors/include/UI_interface_icons.h
@@ -77,6 +77,9 @@ void UI_icon_draw_size(float x, float y, int size, int icon_id, float alpha);
void UI_icons_free(void);
void UI_icons_free_drawinfo(void *drawinfo);
+void UI_icon_draw_cache_begin(void);
+void UI_icon_draw_cache_end(void);
+
struct ListBase *UI_iconfile_list(void);
int UI_iconfile_get_index(const char *filename);
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 0050340d842..0c786874180 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -64,6 +64,7 @@
#include "BLT_translation.h"
#include "UI_interface.h"
+#include "UI_interface_icons.h"
#include "IMB_imbuf.h"
@@ -1427,6 +1428,7 @@ void UI_block_draw(const bContext *C, uiBlock *block)
ui_draw_aligned_panel(&style, block, &rect, UI_panel_category_is_visible(ar));
BLF_batch_draw_begin();
+ UI_icon_draw_cache_begin();
/* widgets */
for (but = block->buttons.first; but; but = but->next) {
@@ -1440,6 +1442,7 @@ void UI_block_draw(const bContext *C, uiBlock *block)
}
}
+ UI_icon_draw_cache_end();
BLF_batch_draw_end();
/* restore matrix */
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index eca8273ee3a..bcc6c40a9e7 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -34,11 +34,13 @@
#include "MEM_guardedalloc.h"
#include "GPU_draw.h"
+#include "GPU_matrix.h"
#include "GPU_immediate.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_fileops_types.h"
+#include "BLI_math_vector.h"
#include "DNA_brush_types.h"
#include "DNA_curve_types.h"
@@ -1016,10 +1018,113 @@ static void icon_draw_rect(float x, float y, int w, int h, float UNUSED(aspect),
IMB_freeImBuf(ima);
}
-static void icon_draw_texture(
+/* High enough to make a difference, low enough so that
+ * small draws are still efficient with the use of glUniform.
+ * NOTE TODO: We could use UBO but we would need some triple
+ * buffer system + persistent mapping for this to be more
+ * efficient than simple glUniform calls. */
+#define ICON_DRAW_CACHE_SIZE 16
+
+typedef struct IconDrawCall{
+ rctf pos;
+ rctf tex;
+ float color[4];
+} IconDrawCall;
+
+static struct {
+ IconDrawCall drawcall_cache[ICON_DRAW_CACHE_SIZE];
+ int calls; /* Number of calls batched together */
+ bool enabled;
+ float mat[4][4];
+} g_icon_draw_cache = {0};
+
+void UI_icon_draw_cache_begin(void)
+{
+ BLI_assert(g_icon_draw_cache.enabled == false);
+ g_icon_draw_cache.enabled = true;
+}
+
+static void icon_draw_cache_flush_ex(void)
+{
+ if (g_icon_draw_cache.calls == 0)
+ return;
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, icongltex.id);
+
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR);
+ GPU_shader_bind(shader);
+
+ int img_loc = GPU_shader_get_uniform(shader, "image");
+ int data_loc = GPU_shader_get_uniform(shader, "calls_data[0]");
+
+ glUniform1i(img_loc, 0);
+ glUniform4fv(data_loc, ICON_DRAW_CACHE_SIZE * 3, (float *)g_icon_draw_cache.drawcall_cache);
+
+ GWN_draw_primitive(GWN_PRIM_TRIS, 6 * g_icon_draw_cache.calls);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ g_icon_draw_cache.calls = 0;
+}
+
+void UI_icon_draw_cache_end(void)
+{
+ BLI_assert(g_icon_draw_cache.enabled == true);
+ g_icon_draw_cache.enabled = false;
+
+ /* Don't change blend state if it's not needed. */
+ if (g_icon_draw_cache.calls == 0)
+ return;
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ icon_draw_cache_flush_ex();
+
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_BLEND);
+}
+
+static void icon_draw_texture_cached(
float x, float y, float w, float h, int ix, int iy,
int UNUSED(iw), int ih, float alpha, const float rgb[3])
{
+
+ float mvp[4][4];
+ gpuGetModelViewProjectionMatrix(mvp);
+
+ IconDrawCall *call = &g_icon_draw_cache.drawcall_cache[g_icon_draw_cache.calls];
+ g_icon_draw_cache.calls++;
+
+ /* Manual mat4*vec2 */
+ call->pos.xmin = x * mvp[0][0] + y * mvp[1][0] + mvp[3][0];
+ call->pos.ymin = x * mvp[0][1] + y * mvp[1][1] + mvp[3][1];
+ call->pos.xmax = call->pos.xmin + w * mvp[0][0] + h * mvp[1][0];
+ call->pos.ymax = call->pos.ymin + w * mvp[0][1] + h * mvp[1][1];
+
+ call->tex.xmin = ix * icongltex.invw;
+ call->tex.xmax = (ix + ih) * icongltex.invw;
+ call->tex.ymin = iy * icongltex.invh;
+ call->tex.ymax = (iy + ih) * icongltex.invh;
+
+ if (rgb) copy_v4_fl4(call->color, rgb[0], rgb[1], rgb[2], alpha);
+ else copy_v4_fl(call->color, alpha);
+
+ if (g_icon_draw_cache.calls == ICON_DRAW_CACHE_SIZE) {
+ icon_draw_cache_flush_ex();
+ }
+}
+
+static void icon_draw_texture(
+ float x, float y, float w, float h, int ix, int iy,
+ int iw, int ih, float alpha, const float rgb[3])
+{
+ if (g_icon_draw_cache.enabled) {
+ icon_draw_texture_cached(x, y, w, h, ix, iy, iw, ih, alpha, rgb);
+ return;
+ }
+
float x1, x2, y1, y2;
x1 = ix * icongltex.invw;