diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-03-29 17:35:45 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-03-29 17:36:01 +0300 |
commit | d93e7e643031448dad7f407ccb285c3b9cf91034 (patch) | |
tree | 1f0e484a380459cf2ac0cc001fff962243109be5 | |
parent | 26b9c502edced5142e4c2e0151566b31b524bbab (diff) |
UI: Perf: Group fill/border/emboss batches together.
This roughly halves the number of drawcalls from widgetbase_draw.
-rw-r--r-- | source/blender/editors/interface/interface_widgets.c | 181 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl | 62 |
2 files changed, 132 insertions, 111 deletions
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 183ab6cfbac..3e74f881cfd 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -129,7 +129,8 @@ typedef struct uiWidgetBase { float radi, rad; float facxi, facyi; float round_corners[4]; - float color1[4], color2[4]; + float color_inner1[4], color_inner2[4]; + float color_outline[4], color_emboss[4]; float shade_dir, clamp, pad[2]; } uniform_params; } uiWidgetBase; @@ -225,10 +226,7 @@ static const uint g_shape_preset_hold_action_face[2][3] = {{2, 0, 1}, {3, 5, 4}} * 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_Batch *roundbox; Gwn_VertFormat format; uint vflag_id; @@ -243,99 +241,102 @@ static Gwn_VertFormat *vflag_format(void) return &g_ui_batch_cache.format; } -static void set_roundbox_vertex( +#define INNER 0 +#define OUTLINE 1 +#define EMBOSS 2 +#define NO_AA WIDGET_AA_JITTER + +static void set_roundbox_vertex_data( + Gwn_VertBufRaw *vflag_step, uint32_t d) +{ + uint32_t *data = GWN_vertbuf_raw_step(vflag_step); + *data = d; +} + +static uint32_t set_roundbox_vertex( Gwn_VertBufRaw *vflag_step, - int corner_id, int corner_v, int jit_v, bool inner, bool emboss) + int corner_id, int corner_v, int jit_v, bool inner, bool emboss, int color) { uint32_t *data = GWN_vertbuf_raw_step(vflag_step); *data = corner_id; *data |= corner_v << 2; *data |= jit_v << 6; + *data |= color << 12; *data |= (inner) ? (1 << 10) : 0; /* is inner vert */ *data |= (emboss) ? (1 << 11) : 0; /* is emboss vert */ + return *data; } -static Gwn_Batch *ui_batch_roundbox_inner_get(void) +static Gwn_Batch *ui_batch_roundbox_get(void) { - if (g_ui_batch_cache.roundbox_inner == NULL) { + if (g_ui_batch_cache.roundbox == NULL) { + uint32_t last_data; Gwn_VertBufRaw vflag_step; Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(vflag_format()); - GWN_vertbuf_data_alloc(vbo, WIDGET_SIZE_MAX); + int vcount = WIDGET_SIZE_MAX; /* inner */ + vcount += 2; /* restart */ + vcount += ((WIDGET_SIZE_MAX + 1) * 2) * WIDGET_AA_JITTER; /* outline (edges) */ + vcount += 2; /* restart */ + vcount += ((WIDGET_CURVE_RESOLU * 2) * 2) * WIDGET_AA_JITTER; /* emboss */ + GWN_vertbuf_data_alloc(vbo, vcount); 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); + /* Inner */ + for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) { + for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU -1; a2 >= 0; a1++, a2--) { + last_data = set_roundbox_vertex(&vflag_step, c1, a1, NO_AA, true, false, INNER); + last_data = set_roundbox_vertex(&vflag_step, c2, a2, NO_AA, true, false, INNER); } } - 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); + /* restart */ + set_roundbox_vertex_data(&vflag_step, last_data); + set_roundbox_vertex(&vflag_step, 0, 0, 0, true, false, OUTLINE); + /* Outlines */ 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); + set_roundbox_vertex(&vflag_step, c, a, j, true, false, OUTLINE); + set_roundbox_vertex(&vflag_step, c, a, j, false, false, OUTLINE); } } /* Close the loop. */ - set_roundbox_vertex(&vflag_step, 0, 0, j, true, false); - set_roundbox_vertex(&vflag_step, 0, 0, j, false, false); + set_roundbox_vertex(&vflag_step, 0, 0, j, true, false, OUTLINE); + last_data = set_roundbox_vertex(&vflag_step, 0, 0, j, false, false, OUTLINE); } - 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); + /* restart */ + set_roundbox_vertex_data(&vflag_step, last_data); + set_roundbox_vertex(&vflag_step, 0, 0, 0, false, false, EMBOSS); + /* Emboss */ 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); + set_roundbox_vertex(&vflag_step, c, a, j, false, false, EMBOSS); + set_roundbox_vertex(&vflag_step, c, a, j, false, true, EMBOSS); } } } - g_ui_batch_cache.roundbox_emboss = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO); + g_ui_batch_cache.roundbox = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO); } - return g_ui_batch_cache.roundbox_emboss; + return g_ui_batch_cache.roundbox; } +#undef INNER +#undef OUTLINE +#undef EMBOSS +#undef NO_AA + 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); + if (g_ui_batch_cache.roundbox) { + gwn_batch_vao_cache_clear(g_ui_batch_cache.roundbox); } } 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); + GWN_BATCH_DISCARD_SAFE(g_ui_batch_cache.roundbox); } /* ************************************************* */ @@ -834,22 +835,32 @@ static void widgetbase_outline(uiWidgetBase *wtb, unsigned int pos) widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, wtb->totvert * 2 + 2); } -static void widgetbase_set_uniform_colors_ubv(uiWidgetBase *wtb, const unsigned char *col1, const unsigned char *col2) +static void widgetbase_set_uniform_colors_ubv( + uiWidgetBase *wtb, + const unsigned char *col1, const unsigned char *col2, + const unsigned char *outline, + const unsigned char *emboss) { - rgba_float_args_set_ch(wtb->uniform_params.color1, col1[0], col1[1], col1[2], col1[3]); - rgba_float_args_set_ch(wtb->uniform_params.color2, col2[0], col2[1], col2[2], col2[3]); + rgba_float_args_set_ch(wtb->uniform_params.color_inner1, col1[0], col1[1], col1[2], col1[3]); + rgba_float_args_set_ch(wtb->uniform_params.color_inner2, col2[0], col2[1], col2[2], col2[3]); + rgba_float_args_set_ch(wtb->uniform_params.color_outline, outline[0], outline[1], outline[2], outline[3]); + rgba_float_args_set_ch(wtb->uniform_params.color_emboss, emboss[0], emboss[1], emboss[2], emboss[3]); } static void draw_widgetbase_batch(Gwn_Batch *batch, uiWidgetBase *wtb) { GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE); - GWN_batch_uniform_4fv_array(batch, "parameters", 7, (float *)&wtb->uniform_params); + GWN_batch_uniform_4fv_array(batch, "parameters", 9, (float *)&wtb->uniform_params); GWN_batch_draw(batch); } static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) { int a; + unsigned char inner_col1[4] = {0}; + unsigned char inner_col2[4] = {0}; + unsigned char emboss_col[4] = {0}; + unsigned char outline_col[4] = {0}; glEnable(GL_BLEND); /* backdrop non AA */ @@ -899,49 +910,39 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) } else { /* simple fill */ - widgetbase_set_uniform_colors_ubv(wtb, (unsigned char *)wcol->inner, (unsigned char *)wcol->inner); - - Gwn_Batch *inner_batch = ui_batch_roundbox_inner_get(); - draw_widgetbase_batch(inner_batch, wtb); + inner_col1[0] = inner_col2[0] = (unsigned char)wcol->inner[0]; + inner_col1[1] = inner_col2[1] = (unsigned char)wcol->inner[1]; + inner_col1[2] = inner_col2[2] = (unsigned char)wcol->inner[2]; + inner_col1[3] = inner_col2[3] = (unsigned char)wcol->inner[3]; } } else { - char col1[4], col2[4]; - shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown); - widgetbase_set_uniform_colors_ubv(wtb, (unsigned char *)col1, (unsigned char *)col2); - - Gwn_Batch *inner_batch = ui_batch_roundbox_inner_get(); - draw_widgetbase_batch(inner_batch, wtb); + /* gradient fill */ + shadecolors4((char *)inner_col1, (char *)inner_col2, wcol->inner, wcol->shadetop, wcol->shadedown); } } - /* for each AA step */ if (wtb->draw_outline) { - BLI_assert(wtb->totvert != 0); - const unsigned char tcol[4] = {wcol->outline[0], - wcol->outline[1], - wcol->outline[2], - wcol->outline[3] / WIDGET_AA_JITTER}; - - /* outline */ - widgetbase_set_uniform_colors_ubv(wtb, tcol, tcol); - - Gwn_Batch *edges_batch = ui_batch_roundbox_edges_get(); - draw_widgetbase_batch(edges_batch, wtb); + outline_col[0] = wcol->outline[0]; + outline_col[1] = wcol->outline[1]; + outline_col[2] = wcol->outline[2]; + outline_col[3] = wcol->outline[3] / WIDGET_AA_JITTER; /* emboss bottom shadow */ if (wtb->draw_emboss) { - unsigned char emboss[4]; - UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss); - if (emboss[3]) { - widgetbase_set_uniform_colors_ubv(wtb, emboss, emboss); - - Gwn_Batch *emboss_batch = ui_batch_roundbox_emboss_get(); - draw_widgetbase_batch(emboss_batch, wtb); - } + UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col); } } + /* Draw everything in one drawcall */ + if (inner_col1[3] || inner_col2[3] || outline_col[3] || emboss_col[4]) { + widgetbase_set_uniform_colors_ubv(wtb, inner_col1, inner_col2, outline_col, emboss_col); + + Gwn_Batch *roundbox_batch = ui_batch_roundbox_get(); + draw_widgetbase_batch(roundbox_batch, wtb); + } + + /* TODO OPTI: Put this inside a batch too. */ /* decoration */ if (wtb->tria1.tot || wtb->tria2.tot) { const unsigned char tcol[4] = {wcol->item[0], diff --git a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl index 78fbc4b132b..1920184aefe 100644 --- a/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_2D_widget_base_vert.glsl @@ -1,3 +1,5 @@ +#define BIT_RANGE(x) ((1u << x) - 1u) + /* 2 bits for corner */ /* Attention! Not the same order as in UI_interface.h! * Ordered by drawing order. */ @@ -5,11 +7,11 @@ #define BOTTOM_RIGHT 1u #define TOP_RIGHT 2u #define TOP_LEFT 3u -#define CNR_FLAG_RANGE ((1u << 2u) - 1u) +#define CNR_FLAG_RANGE BIT_RANGE(2u) /* 4bits for corner id */ #define CORNER_VEC_OFS 2u -#define CORNER_VEC_RANGE ((1u << 4u) - 1u) +#define CORNER_VEC_RANGE BIT_RANGE(4u) const vec2 cornervec[36] = vec2[36]( vec2(0.0, 1.0), vec2(0.02, 0.805), vec2(0.067, 0.617), vec2(0.169, 0.45), vec2(0.293, 0.293), vec2(0.45, 0.169), vec2(0.617, 0.076), vec2(0.805, 0.02), vec2(1.0, 0.0), vec2(-1.0, 0.0), vec2(-0.805, 0.02), vec2(-0.617, 0.067), vec2(-0.45, 0.169), vec2(-0.293, 0.293), vec2(-0.169, 0.45), vec2(-0.076, 0.617), vec2(-0.02, 0.805), vec2(0.0, 1.0), @@ -19,7 +21,7 @@ const vec2 cornervec[36] = vec2[36]( /* 4bits for jitter id */ #define JIT_OFS 6u -#define JIT_RANGE ((1u << 4u) - 1u) +#define JIT_RANGE BIT_RANGE(4u) const vec2 jit[9] = vec2[9]( vec2( 0.468813, -0.481430), vec2(-0.155755, -0.352820), vec2( 0.219306, -0.238501), vec2(-0.393286, -0.110949), @@ -28,23 +30,32 @@ const vec2 jit[9] = vec2[9]( vec2( 0.0, 0.0) ); -/* 2bits for other flag */ -#define INNER_FLAG (1u << 10u) /* is inner vert */ -#define EMBOSS_FLAG (1u << 11u) /* is emboss vert */ +/* 2bits for other flags */ +#define INNER_FLAG (1u << 10u) /* is inner vert */ +#define EMBOSS_FLAG (1u << 11u) /* is emboss vert */ + +/* 2bits for color */ +#define COLOR_OFS 12u +#define COLOR_RANGE BIT_RANGE(2u) +#define COLOR_INNER 0u +#define COLOR_EDGE 1u +#define COLOR_EMBOSS 2u uniform mat4 ModelViewProjectionMatrix; -uniform vec4 parameters[7]; +uniform vec4 parameters[9]; /* radi and rad per corner */ -#define recti parameters[0] -#define rect parameters[1] -#define radsi parameters[2].x -#define rads parameters[2].y -#define faci parameters[2].zw +#define recti parameters[0] +#define rect parameters[1] +#define radsi parameters[2].x +#define rads parameters[2].y +#define faci parameters[2].zw #define roundCorners parameters[3] -#define color1 parameters[4] -#define color2 parameters[5] -#define shadeDir parameters[6].x +#define colorInner1 parameters[4] +#define colorInner2 parameters[5] +#define colorEdge parameters[6] +#define colorEmboss parameters[7] +#define shadeDir parameters[8].x in uint vflag; @@ -57,7 +68,7 @@ void main() vec2 v = cornervec[cflag * 9u + vofs]; - bool is_inner = (vflag & INNER_FLAG) != 0.0; + bool is_inner = (vflag & INNER_FLAG) != 0u; /* Scale by corner radius */ v *= roundCorners[cflag] * ((is_inner) ? radsi : rads); @@ -74,11 +85,20 @@ void main() v += rct.xw; /* compute uv and color gradient */ - vec2 uv = faci * (v - recti.xz); - float fac = clamp((shadeDir > 0.0) ? uv.y : uv.x, 0.0, 1.0); - finalColor = mix(color2, color1, fac); - - bool is_emboss = (vflag & EMBOSS_FLAG) != 0.0; + uint color_id = (vflag >> COLOR_OFS) & COLOR_RANGE; + if (color_id == COLOR_INNER) { + vec2 uv = faci * (v - recti.xz); + float fac = clamp((shadeDir > 0.0) ? uv.y : uv.x, 0.0, 1.0); + finalColor = mix(colorInner2, colorInner1, fac); + } + else if (color_id == COLOR_EDGE) { + finalColor = colorEdge; + } + else /* (color_id == COLOR_EMBOSS) */ { + finalColor = colorEmboss; + } + + bool is_emboss = (vflag & EMBOSS_FLAG) != 0u; v.y -= (is_emboss) ? 1.0f : 0.0; /* Antialiasing offset */ |