[Bf-blender-cvs] [c77870fc78f] blender2.8: UI: Perf: Batch icons drawcalls together.

Clément Foucault noreply at git.blender.org
Sat Mar 31 20:26:31 CEST 2018


Commit: c77870fc78f594411c9831ee77eba2167a702fd7
Author: Clément Foucault
Date:   Sat Mar 31 19:32:28 2018 +0200
Branches: blender2.8
https://developer.blender.org/rBc77870fc78f594411c9831ee77eba2167a702fd7

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.

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

M	source/blender/editors/include/UI_interface_icons.h
M	source/blender/editors/interface/interface.c
M	source/blender/editors/interface/interface_icons.c
M	source/blender/gpu/CMakeLists.txt
M	source/blender/gpu/GPU_shader.h
M	source/blender/gpu/intern/gpu_shader.c
A	source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
A	source/blender/gpu/shaders/gpu_shader_image_varying_color_frag.glsl

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

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;
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index f0e5b0842fc..b52817c68a8 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -141,6 +141,7 @@ data_to_c_simple(shaders/gpu_shader_2D_smooth_color_vert.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_2D_smooth_color_frag.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_2D_image_vert.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_2D_image_rect_vert.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_2D_image_multi_rect_vert.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_image_frag.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_image_linear_frag.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_image_shuffle_color_frag.glsl SRC)
@@ -148,6 +149,7 @@ data_to_c_simple(shaders/gpu_shader_image_mask_uniform_color_frag.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_image_modulate_alpha_frag.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_image_alpha_color_frag.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_image_color_frag.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_image_varying_color_frag.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_image_depth_linear_frag.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_image_depth_copy_frag.glsl SRC)
 data_to_c_simple(shaders/gpu_shader_image_interlace_frag.glsl SRC)
diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h
index 1a1ec120d28..5041d524f18 100644
--- a/source/blender/gpu/GPU_shader.h
+++ b/source/blender/gpu/GPU_shader.h
@@ -116,6 +116,7 @@ typedef enum GPUBuiltinShader {
 	GPU_SHADER_2D_IMAGE_ALPHA_COLOR,
 	GPU_SHADER_2D_IMAGE_ALPHA,
 	GPU_SHADER_2D_IMAGE_RECT_COLOR,
+	GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR,
 	GPU_SHADER_2D_CHECKER,
 	GPU_SHADER_2D_DIAG_STRIPES,
 	/* for simple 3D drawing */
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index ad6331befce..55184418284 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -66,12 +66,14 @@ extern char datatoc_gpu_shader_2D_smooth_color_vert_glsl[];
 extern char datatoc_gpu_shader_2D_smooth_color_frag_glsl[];
 extern char datatoc_gpu_shader_2D_image_vert_glsl[];
 extern char datatoc_gpu_shader_2D_image_rect_vert_glsl[];
+extern char datatoc_gpu_shader_2D_image_multi_rect_vert_glsl[];
 extern char datatoc_gpu_shader_2D_widget_base_vert_glsl[];
 
 extern char datatoc_gpu_shader_3D_image_vert_glsl[];
 extern char datatoc_gpu_shader_image_frag_glsl[];
 extern char datatoc_gpu_shader_image_linear_frag_glsl[];
 extern char datatoc_gpu_shader_image_color_frag_glsl[];
+extern char datatoc_gpu_shader_image_varying_color_frag_glsl[];
 extern char datatoc_gpu_shader_image_alpha_color_frag_glsl[];
 extern char datatoc_gpu_shader_image_shuffle_color_frag_glsl[];
 extern char datatoc_gpu_shader_image_interlace_frag_glsl[];
@@ -710,6 +712,8 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
 		                                        datatoc_gpu_shader_image_shuffle_color_frag_glsl },
 		[GPU_SHADER_2D_IMAGE_RECT_COLOR] = { datatoc_gpu_shader_2D_image_rect_vert_glsl,
 		                                     datatoc_gpu_shader_image_color_frag_glsl },
+		[GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR] = { datatoc_gpu_shader_2D_image_multi_rect_vert_glsl,
+		                                           datatoc_gpu_shader_image_varying_color_frag_glsl },
 
 		[GPU_SHADER_3D_UNIFORM_COLOR] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl },
 		[GPU_SHADER_3D_UNIFORM_COLOR_U32] = { datatoc_gpu_shader_3D_vert_glsl, datatoc_gpu_shader_uniform_color_frag_glsl },
diff --git a/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
new file mode 100644
index 00000000000..9fdf8ececc5
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_2D_image_multi_rect_vert.glsl
@@ -0,0 +1,48 @@
+/**
+ * Simple shader that just draw multiple icons at the specified locations
+ * does not need any vertex input (producing less call to immBegin/End)
+ **/
+
+/* Same as ICON_DRAW_CACHE_SIZE */
+#define MAX_CALLS 16
+
+uniform vec4 calls_data[MAX_CALLS * 3];
+
+out vec2 texCoord_interp;
+flat out vec4 finalColor;
+
+void main()
+{
+	/* Rendering 2 triangle per icon. */
+	int i = gl_VertexID / 6;
+	int v = gl_VertexID % 6;
+
+	vec4 pos = calls_data[i*3];
+	vec4 tex = calls_data[i*3+1];
+	finalColor = calls_data[i*3+2];
+
+	/* TODO Remove this */
+	if (v == 2) v = 4;
+	else if (v == 3) v = 0;
+	else if (v == 5) v = 2;
+
+	if (v == 0) {
+		pos.xy = pos.xw;
+		tex.xy = tex.xw;
+	}
+	else if (v == 1) {
+		pos.xy = pos.xz;
+		tex.xy = tex.xz;
+	}
+	else if (v == 2) {
+		pos.xy = pos.yw;
+		tex.xy = tex.yw;
+	}
+	else {
+		pos.xy = pos.yz;
+		tex.xy 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list