diff options
-rw-r--r-- | source/blender/editors/include/UI_interface.h | 4 | ||||
-rw-r--r-- | source/blender/editors/interface/interface_widgets.c | 272 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_batch_presets.c | 6 |
3 files changed, 188 insertions, 94 deletions
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 because the last pair is wrapped */ @@ -735,10 +834,22 @@ 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) +{ + 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]); +} + +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_draw(batch); +} + static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) { int a; - glEnable(GL_BLEND); /* backdrop non AA */ @@ -788,74 +899,47 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol) } else { /* simple fill */ - unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4ubv((unsigned char *)wcol->inner); + widgetbase_set_uniform_colors_ubv(wtb, (unsigned char *)wcol->inner, (unsigned char *)wcol->inner); - widget_draw_vertex_buffer(pos, 0, GL_TRIANGLE_FAN, wtb->inner_v, NULL, wtb->totvert); - - immUnbindProgram(); + Gwn_Batch *inner_batch = ui_batch_roundbox_inner_get(); + draw_widgetbase_batch(inner_batch, wtb); } } else { char col1[4], col2[4]; - unsigned char col_array[WIDGET_SIZE_MAX][4]; - unsigned char *col_pt = &col_array[0][0]; - - Gwn_VertFormat *format = immVertexFormat(); - unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int col = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); - - immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); - shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown); + widgetbase_set_uniform_colors_ubv(wtb, (unsigned char *)col1, (unsigned char *)col2); - for (a = 0; a < wtb->totvert; a++, col_pt += 4) { - round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]); - } - - widget_draw_vertex_buffer(pos, col, GL_TRIANGLE_FAN, wtb->inner_v, col_array, wtb->totvert); - immUnbindProgram(); + Gwn_Batch *inner_batch = ui_batch_roundbox_inner_get(); + draw_widgetbase_batch(inner_batch, wtb); } } /* for each AA step */ if (wtb->draw_outline) { BLI_assert(wtb->totvert != 0); - float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */ - float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */ - const unsigned char tcol[4] = {wcol->outline[0], wcol->outline[1], wcol->outline[2], wcol->outline[3] / WIDGET_AA_JITTER}; - unsigned char emboss[4]; - - widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip); - - if (wtb->draw_emboss) { - widget_verts_to_triangle_strip_open(wtb, wtb->halfwayvert, triangle_strip_emboss); - UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss); - } - - unsigned int pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); /* outline */ - immUniformColor4ubv(tcol); + widgetbase_set_uniform_colors_ubv(wtb, tcol, tcol); - widget_draw_vertex_buffer_aa(pos, 0, GL_TRIANGLE_STRIP, triangle_strip, NULL, wtb->totvert * 2 + 2); + Gwn_Batch *edges_batch = ui_batch_roundbox_edges_get(); + draw_widgetbase_batch(edges_batch, wtb); /* emboss bottom shadow */ if (wtb->draw_emboss) { + unsigned char emboss[4]; + UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss); if (emboss[3]) { - immUniformColor4ubv(emboss); - widget_draw_vertex_buffer_aa(pos, 0, GL_TRIANGLE_STRIP, triangle_strip_emboss, NULL, wtb->halfwayvert * 2); + widgetbase_set_uniform_colors_ubv(wtb, emboss, emboss); + + Gwn_Batch *emboss_batch = ui_batch_roundbox_emboss_get(); + draw_widgetbase_batch(emboss_batch, wtb); } } - - immUnbindProgram(); } /* decoration */ @@ -2921,7 +3005,7 @@ void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *s else rad = 0.5f * BLI_rcti_size_x(rect); - wtb.draw_shadedir = (horizontal) ? true : false; + wtb.uniform_params.shade_dir = (horizontal) ? 1.0f : 0.0; /* draw back part, colors swapped and shading inverted */ if (horizontal) diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c index 696143a3857..1eb1b737bee 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -33,6 +33,8 @@ #include "BLI_math.h" #include "BLI_threads.h" +#include "UI_interface.h" + #include "GPU_batch.h" #include "gpu_shader_private.h" @@ -202,6 +204,8 @@ void gpu_batch_presets_reset(void) gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_high); gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_wire_low); gwn_batch_vao_cache_clear(g_presets_3d.batch.sphere_wire_med); + + ui_widget_batch_preset_reset(); } void gpu_batch_presets_exit(void) @@ -211,4 +215,6 @@ void gpu_batch_presets_exit(void) GWN_batch_discard(g_presets_3d.batch.sphere_high); GWN_batch_discard(g_presets_3d.batch.sphere_wire_low); GWN_batch_discard(g_presets_3d.batch.sphere_wire_med); + + ui_widget_batch_preset_exit(); } |