[Bf-blender-cvs] [f6ad5380409] blender2.8: UI: Perf: widgetbase: Replace imm usage by a batch cache.

Clément Foucault noreply at git.blender.org
Thu Mar 29 14:22:57 CEST 2018


Commit: f6ad53804099802ab3f5eafa830f95f8545eb888
Author: Clément Foucault
Date:   Thu Mar 29 03:21:03 2018 +0200
Branches: blender2.8
https://developer.blender.org/rBf6ad53804099802ab3f5eafa830f95f8545eb888

UI: Perf: widgetbase: Replace imm usage by a batch cache.

Introduce a UI batch cache. For the moment it's only used by widgetbase so
leaving it interface_widgets.c. If it grows, it can have its own file.

Like all preset batches (batches used by UI context), vaos must be refreshed
each time a new window context is binded.

This still does 3 GWN_batch_draw in the worst cases but at least it does
not use the IMM api.

I will continue and batch the 3 calls together since we are really CPU
bound, so shader complexity does not really matters.

I cannot spot any difference on all the widgets I could test. I did not use
any unit tests so I cannot tell if there is really any defects.

This is not a complete rewrite but it adresses the top bottleneck found
after a profilling session.

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

M	source/blender/editors/include/UI_interface.h
M	source/blender/editors/interface/interface_widgets.c
M	source/blender/gpu/intern/gpu_batch_presets.c

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

diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 6e09318314d..2a0181876c7 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -1168,4 +1168,8 @@ void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *ar)
 
 int UI_calc_float_precision(int prec, double value);
 
+/* UI Batches managment */
+void ui_widget_batch_preset_reset(void);
+void ui_widget_batch_preset_exit(void);
+
 #endif  /* __UI_INTERFACE_H__ */
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 6459c164075..183ab6cfbac 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -55,6 +55,7 @@
 #include "interface_intern.h"
 
 #include "GPU_basic_shader.h"
+#include "GPU_batch.h"
 #include "GPU_immediate.h"
 #include "GPU_immediate_util.h"
 #include "GPU_matrix.h"
@@ -79,6 +80,7 @@ enum {
 #define UI_BUT_UPDATE_DELAY ((void)0)
 #define UI_BUT_UNDO ((void)0)
 
+
 /* ************** widget base functions ************** */
 /**
  * - in: roundbox codes for corner types and radius
@@ -105,21 +107,31 @@ typedef struct uiWidgetTrias {
 } uiWidgetTrias;
 
 /* max as used by round_box__edges */
+/* Make sure to change widget_base_vert.glsl accordingly. */
 #define WIDGET_CURVE_RESOLU 9
 #define WIDGET_SIZE_MAX (WIDGET_CURVE_RESOLU * 4)
 
 typedef struct uiWidgetBase {
-	
+	/* TODO remove these completely */
 	int totvert, halfwayvert;
 	float outer_v[WIDGET_SIZE_MAX][2];
 	float inner_v[WIDGET_SIZE_MAX][2];
 	float inner_uv[WIDGET_SIZE_MAX][2];
 	
-	bool draw_inner, draw_outline, draw_emboss, draw_shadedir;
+	bool draw_inner, draw_outline, draw_emboss;
 	
 	uiWidgetTrias tria1;
 	uiWidgetTrias tria2;
-	
+
+	/* Widget shader parameters, must match the shader layout. */
+	struct {
+		rctf recti, rect;
+		float radi, rad;
+		float facxi, facyi;
+		float round_corners[4];
+		float color1[4], color2[4];
+		float shade_dir, clamp, pad[2];
+	} uniform_params;
 } uiWidgetBase;
 
 /** uiWidgetType: for time being only for visual appearance,
@@ -206,6 +218,126 @@ static const uint g_shape_preset_hold_action_face[2][3] = {{2, 0, 1}, {3, 5, 4}}
 
 /** \} */
 
+/* **************** Batch creations ****************** */
+/**
+ * In order to speed up UI drawing we create some batches that are then
+ * modified by specialized shaders to draw certain elements really fast.
+ * TODO: find a better place. Maybe it's own file?
+ **/
+static struct {
+	Gwn_Batch *roundbox_inner;
+	Gwn_Batch *roundbox_edges;
+	Gwn_Batch *roundbox_emboss;
+	Gwn_Batch *anti_tria;
+
+	Gwn_VertFormat format;
+	uint vflag_id;
+} g_ui_batch_cache = {0};
+
+static Gwn_VertFormat *vflag_format(void)
+{
+	if (g_ui_batch_cache.format.attrib_ct == 0) {
+		Gwn_VertFormat *format = &g_ui_batch_cache.format;
+		g_ui_batch_cache.vflag_id = GWN_vertformat_attr_add(format, "vflag", GWN_COMP_U32, 1, GWN_FETCH_INT);
+	}
+	return &g_ui_batch_cache.format;
+}
+
+static void set_roundbox_vertex(
+        Gwn_VertBufRaw *vflag_step,
+        int corner_id, int corner_v, int jit_v, bool inner, bool emboss)
+{
+	uint32_t *data = GWN_vertbuf_raw_step(vflag_step);
+	*data  = corner_id;
+	*data |= corner_v << 2;
+	*data |= jit_v << 6;
+	*data |= (inner) ? (1 << 10) : 0; /* is inner vert */
+	*data |= (emboss) ? (1 << 11) : 0; /* is emboss vert */
+}
+
+static Gwn_Batch *ui_batch_roundbox_inner_get(void)
+{
+	if (g_ui_batch_cache.roundbox_inner == NULL) {
+		Gwn_VertBufRaw vflag_step;
+		Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(vflag_format());
+		GWN_vertbuf_data_alloc(vbo, WIDGET_SIZE_MAX);
+		GWN_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step);
+		for (int c = 0; c < 4; c++) {
+			for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
+				set_roundbox_vertex(&vflag_step, c, a, WIDGET_AA_JITTER, true, false);
+			}
+		}
+		g_ui_batch_cache.roundbox_inner = GWN_batch_create_ex(GWN_PRIM_TRI_FAN, vbo, NULL, GWN_BATCH_OWNS_VBO);
+	}
+	return g_ui_batch_cache.roundbox_inner;
+}
+
+static Gwn_Batch *ui_batch_roundbox_edges_get(void)
+{
+	if (g_ui_batch_cache.roundbox_edges == NULL) {
+		Gwn_VertBufRaw vflag_step;
+		Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(vflag_format());
+		GWN_vertbuf_data_alloc(vbo, ((WIDGET_SIZE_MAX + 1) * 2) * WIDGET_AA_JITTER);
+		GWN_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step);
+		for (int j = 0; j < WIDGET_AA_JITTER; j++) {
+			for (int c = 0; c < 4; c++) {
+				for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
+					set_roundbox_vertex(&vflag_step, c, a, j, true, false);
+					set_roundbox_vertex(&vflag_step, c, a, j, false, false);
+				}
+			}
+			/* Close the loop. */
+			set_roundbox_vertex(&vflag_step, 0, 0, j, true, false);
+			set_roundbox_vertex(&vflag_step, 0, 0, j, false, false);
+		}
+		g_ui_batch_cache.roundbox_edges = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
+	}
+	return g_ui_batch_cache.roundbox_edges;
+}
+
+static Gwn_Batch *ui_batch_roundbox_emboss_get(void)
+{
+	if (g_ui_batch_cache.roundbox_emboss == NULL) {
+		Gwn_VertBufRaw vflag_step;
+		Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(vflag_format());
+		GWN_vertbuf_data_alloc(vbo, ((WIDGET_CURVE_RESOLU * 2) * 2) * WIDGET_AA_JITTER);
+		GWN_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step);
+		bool rev = false; /* go back and forth : avoid degenerate triangle (beware of backface cull) */
+		for (int j = 0; j < WIDGET_AA_JITTER; j++, rev = !rev) {
+			for (int c = (rev) ? 1 : 0; (rev) ? c >= 0 : c < 2; (rev) ? c-- : c++) {
+				int sta = (rev) ? WIDGET_CURVE_RESOLU - 1 : 0;
+				int end = WIDGET_CURVE_RESOLU;
+				for (int a = sta; (rev) ? a >= 0 : a < end; (rev) ? a-- : a++) {
+					set_roundbox_vertex(&vflag_step, c, a, j, false, false);
+					set_roundbox_vertex(&vflag_step, c, a, j, false, true);
+				}
+			}
+		}
+		g_ui_batch_cache.roundbox_emboss = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
+	}
+	return g_ui_batch_cache.roundbox_emboss;
+}
+
+void ui_widget_batch_preset_reset(void)
+{
+	if (g_ui_batch_cache.roundbox_inner) {
+		gwn_batch_vao_cache_clear(g_ui_batch_cache.roundbox_inner);
+	}
+	if (g_ui_batch_cache.roundbox_edges) {
+		gwn_batch_vao_cache_clear(g_ui_batch_cache.roundbox_edges);
+	}
+	if (g_ui_batch_cache.roundbox_emboss) {
+		gwn_batch_vao_cache_clear(g_ui_batch_cache.roundbox_emboss);
+	}
+}
+
+void ui_widget_batch_preset_exit(void)
+{
+	GWN_BATCH_DISCARD_SAFE(g_ui_batch_cache.roundbox_inner);
+	GWN_BATCH_DISCARD_SAFE(g_ui_batch_cache.roundbox_edges);
+	GWN_BATCH_DISCARD_SAFE(g_ui_batch_cache.roundbox_emboss);
+}
+
 /* ************************************************* */
 
 void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3,
@@ -274,7 +406,8 @@ static void widget_init(uiWidgetBase *wtb)
 	wtb->draw_inner = true;
 	wtb->draw_outline = true;
 	wtb->draw_emboss = true;
-	wtb->draw_shadedir = true;
+
+	wtb->uniform_params.shade_dir = 1.0f;
 }
 
 /* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
@@ -381,7 +514,18 @@ static void round_box__edges(uiWidgetBase *wt, int roundboxalign, const rcti *re
 
 	if (2.0f * (radi + 1.0f) > minsize)
 		radi = 0.5f * minsize - U.pixelsize;
-	
+
+	wt->uniform_params.rad = rad;
+	wt->uniform_params.radi = radi;
+	wt->uniform_params.facxi = facxi;
+	wt->uniform_params.facyi = facyi;
+	wt->uniform_params.round_corners[0] = (roundboxalign & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f;
+	wt->uniform_params.round_corners[1] = (roundboxalign & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f;
+	wt->uniform_params.round_corners[2] = (roundboxalign & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f;
+	wt->uniform_params.round_corners[3] = (roundboxalign & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f;
+	BLI_rctf_rcti_copy(&wt->uniform_params.rect, rect);
+	BLI_rctf_init(&wt->uniform_params.recti, minxi, maxxi, minyi, maxyi);
+
 	/* mult */
 	for (a = 0; a < WIDGET_CURVE_RESOLU; a++) {
 		veci[a][0] = radi * cornervec[a][0];
@@ -605,40 +749,6 @@ static void widget_draw_vertex_buffer(unsigned int pos, unsigned int col, int mo
 	immEnd();
 }
 
-static void widget_draw_vertex_buffer_aa(unsigned int pos, unsigned int col, int mode,
-                                         const float quads_pos[WIDGET_SIZE_MAX][2],
-                                         const unsigned char quads_col[WIDGET_SIZE_MAX][4],
-                                         unsigned int totvert)
-{
-	immBegin(mode, (totvert+3) * WIDGET_AA_JITTER);
-	for (int j = 0; j < WIDGET_AA_JITTER; j++) {
-		/* Duplicate First vertex. */
-		if (quads_col)
-			immAttrib4ubv(col, quads_col[0]);
-		immVertex2f(pos,
-		            quads_pos[0][0] + jit[j][0],
-		            quads_pos[0][1] + jit[j][1]);
-
-		for (int i = 0; i < totvert; ++i) {
-			if (quads_col)
-				immAttrib4ubv(col, quads_col[i]);
-			immVertex2f(pos,
-			            quads_pos[i][0] + jit[j][0],
-			            quads_pos[i][1] + jit[j][1]);
-		}
-
-		/* Degenerate triangle to simulate primitive restart. */
-		for (int i = 0; i < 2; ++i) {
-			if (quads_col)
-				immAttrib4ubv(col, quads_col[totvert-1]);
-			immVertex2f(pos,
-			            quads_pos[totvert-1][0] + jit[j][0],
-			            quads_pos[totvert-1][1] + jit[j][1]);
-		}
-	}
-	immEnd();
-}
-
 static void shape_preset_trias_from_rect_menu(uiWidgetTrias *tria, const rcti *rect)
 {
 	float centx, centy, size;
@@ -716,17 +826,6 @@ static void widget_verts_to_triangle_strip(uiWidgetBase *wtb, const int totvert,
 	copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[0]);
 }
 
-static void widget_verts_to_triangle_strip_open(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2][2])
-{
-	int a;
-	for (a = 0; a < totvert; a++) {
-		triangle_strip[a * 2][0] = wtb->outer_v[a][0];
-		triangle_strip[a * 2][1] = wtb->outer_v[a][1];
-		triangle_strip[a * 2 + 1][0] = wtb->outer_v[a][0];
-		triangle_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f;
-	}
-}
-
 static void widgetbase_outline(uiWidgetBase *wtb, unsigned int pos)
 {
 	float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 be

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list