UI: Perf: Improve ui_draw_dropshadow.
Replace the 12 iterations of UI_draw_roundbox_4fv with only one batch. This mean less overdraw and less drawcalls. I had to hack the opacity falloff curve manually to get approximatly the same result as previous technique. I'm sure with a bit more brain power somebody could find the perfect function.
This commit is contained in:
parent
80d4d71360
commit
4a73127a2b
|
@ -2125,16 +2125,40 @@ void ui_draw_dropshadow(const rctf *rct, float radius, float aspect, float alpha
|
|||
}
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
const float dalpha = alpha * 2.0f / 255.0f;
|
||||
float calpha = dalpha;
|
||||
for (; i--; a -= aspect) {
|
||||
float visibility = 1.0f;
|
||||
for (; i--;) {
|
||||
/* alpha ranges from 2 to 20 or so */
|
||||
#if 0 /* Old Method (pre 2.8) */
|
||||
float color[4] = {0.0f, 0.0f, 0.0f, calpha};
|
||||
UI_draw_roundbox_4fv(true, rct->xmin - a, rct->ymin - a, rct->xmax + a, rct->ymax - 10.0f + a, rad + a, color);
|
||||
#endif
|
||||
/* Compute final visibility to match old method result. */
|
||||
/* TODO we could just find a better fit function inside the shader instead of this. */
|
||||
visibility = visibility * (1.0f - calpha);
|
||||
calpha += dalpha;
|
||||
}
|
||||
|
||||
uiWidgetBaseParameters widget_params = {
|
||||
.recti.xmin = rct->xmin, .recti.ymin = rct->ymin,
|
||||
.recti.xmax = rct->xmax, .recti.ymax = rct->ymax - 10.0f,
|
||||
.rect.xmin = rct->xmin - a, .rect.ymin = rct->ymin - a,
|
||||
.rect.xmax = rct->xmax + a, .rect.ymax = rct->ymax - 10.0f + a,
|
||||
.radi = rad,
|
||||
.rad = rad + a,
|
||||
.round_corners[0] = (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f,
|
||||
.round_corners[1] = (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f,
|
||||
.round_corners[2] = (roundboxtype & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f,
|
||||
.round_corners[3] = (roundboxtype & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f,
|
||||
};
|
||||
|
||||
Gwn_Batch *batch = ui_batch_roundbox_shadow_get();
|
||||
GWN_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_SHADOW);
|
||||
GWN_batch_uniform_4fv_array(batch, "parameters", 4, (float *)&widget_params);
|
||||
GWN_batch_uniform_1f(batch, "alpha", 1.0f - visibility);
|
||||
GWN_batch_draw(batch);
|
||||
|
||||
/* outline emphasis */
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
float color[4] = {0.0f, 0.0f, 0.0f, 0.4f};
|
||||
|
|
|
@ -727,6 +727,7 @@ enum {
|
|||
|
||||
struct Gwn_Batch *ui_batch_roundbox_get(bool filled, bool antialiased);
|
||||
struct Gwn_Batch *ui_batch_roundbox_widget_get(int tria);
|
||||
struct Gwn_Batch *ui_batch_roundbox_shadow_get(void);
|
||||
|
||||
void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3, const float color[4]);
|
||||
void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy,
|
||||
|
|
|
@ -230,6 +230,7 @@ static struct {
|
|||
Gwn_Batch *roundbox_simple;
|
||||
Gwn_Batch *roundbox_simple_aa;
|
||||
Gwn_Batch *roundbox_simple_outline;
|
||||
Gwn_Batch *roundbox_shadow;
|
||||
|
||||
Gwn_VertFormat format;
|
||||
uint vflag_id;
|
||||
|
@ -436,6 +437,41 @@ Gwn_Batch *ui_batch_roundbox_get(bool filled, bool antialiased)
|
|||
return *batch;
|
||||
}
|
||||
|
||||
Gwn_Batch *ui_batch_roundbox_shadow_get(void)
|
||||
{
|
||||
if (g_ui_batch_cache.roundbox_shadow == NULL) {
|
||||
uint32_t last_data;
|
||||
Gwn_VertBufRaw vflag_step;
|
||||
Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(vflag_format());
|
||||
int vcount = (WIDGET_SIZE_MAX + 1) * 2 + 2 + WIDGET_SIZE_MAX;
|
||||
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, NO_AA, true, false, INNER);
|
||||
set_roundbox_vertex(&vflag_step, c, a, NO_AA, false, false, INNER);
|
||||
}
|
||||
}
|
||||
/* close loop */
|
||||
last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER);
|
||||
last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, false, false, INNER);
|
||||
/* restart */
|
||||
set_roundbox_vertex_data(&vflag_step, last_data);
|
||||
set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER);
|
||||
/* filled */
|
||||
for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) {
|
||||
for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU -1; a2 >= 0; a1++, a2--) {
|
||||
set_roundbox_vertex(&vflag_step, c1, a1, NO_AA, true, false, INNER);
|
||||
set_roundbox_vertex(&vflag_step, c2, a2, NO_AA, true, false, INNER);
|
||||
}
|
||||
}
|
||||
g_ui_batch_cache.roundbox_shadow = GWN_batch_create_ex(GWN_PRIM_TRI_STRIP, vbo, NULL, GWN_BATCH_OWNS_VBO);
|
||||
gpu_batch_presets_register(g_ui_batch_cache.roundbox_shadow);
|
||||
}
|
||||
return g_ui_batch_cache.roundbox_shadow;
|
||||
}
|
||||
|
||||
#undef INNER
|
||||
#undef OUTLINE
|
||||
#undef EMBOSS
|
||||
|
|
|
@ -133,6 +133,8 @@ data_to_c_simple(shaders/gpu_shader_flat_color_frag.glsl SRC)
|
|||
data_to_c_simple(shaders/gpu_shader_flat_color_alpha_test_0_frag.glsl SRC)
|
||||
data_to_c_simple(shaders/gpu_shader_2D_vert.glsl SRC)
|
||||
data_to_c_simple(shaders/gpu_shader_2D_widget_base_vert.glsl SRC)
|
||||
data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_vert.glsl SRC)
|
||||
data_to_c_simple(shaders/gpu_shader_2D_widget_shadow_frag.glsl SRC)
|
||||
data_to_c_simple(shaders/gpu_shader_2D_nodelink_frag.glsl SRC)
|
||||
data_to_c_simple(shaders/gpu_shader_2D_nodelink_vert.glsl SRC)
|
||||
data_to_c_simple(shaders/gpu_shader_2D_flat_color_vert.glsl SRC)
|
||||
|
|
|
@ -173,6 +173,7 @@ typedef enum GPUBuiltinShader {
|
|||
GPU_SHADER_INSTANCE_EDGES_VARIYING_COLOR,
|
||||
/* specialized for UI drawing */
|
||||
GPU_SHADER_2D_WIDGET_BASE,
|
||||
GPU_SHADER_2D_WIDGET_SHADOW,
|
||||
GPU_SHADER_2D_NODELINK,
|
||||
GPU_SHADER_2D_NODELINK_INST,
|
||||
|
||||
|
|
|
@ -68,6 +68,8 @@ 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_2D_widget_shadow_vert_glsl[];
|
||||
extern char datatoc_gpu_shader_2D_widget_shadow_frag_glsl[];
|
||||
extern char datatoc_gpu_shader_2D_nodelink_frag_glsl[];
|
||||
extern char datatoc_gpu_shader_2D_nodelink_vert_glsl[];
|
||||
|
||||
|
@ -801,6 +803,8 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
|
|||
|
||||
[GPU_SHADER_2D_WIDGET_BASE] = { datatoc_gpu_shader_2D_widget_base_vert_glsl,
|
||||
datatoc_gpu_shader_2D_smooth_color_frag_glsl},
|
||||
[GPU_SHADER_2D_WIDGET_SHADOW] = { datatoc_gpu_shader_2D_widget_shadow_vert_glsl,
|
||||
datatoc_gpu_shader_2D_widget_shadow_frag_glsl },
|
||||
[GPU_SHADER_2D_NODELINK] = { datatoc_gpu_shader_2D_nodelink_vert_glsl,
|
||||
datatoc_gpu_shader_2D_nodelink_frag_glsl },
|
||||
[GPU_SHADER_2D_NODELINK_INST] = { datatoc_gpu_shader_2D_nodelink_vert_glsl,
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
in float shadowFalloff;
|
||||
|
||||
out vec4 fragColor;
|
||||
|
||||
uniform float alpha;
|
||||
|
||||
void main()
|
||||
{
|
||||
fragColor = vec4(0.0);
|
||||
/* Manual curve fit of the falloff curve of previous drawing method. */
|
||||
fragColor.a = alpha * (shadowFalloff * shadowFalloff * 0.722 + shadowFalloff * 0.277);
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
#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. */
|
||||
#define BOTTOM_LEFT 0u
|
||||
#define BOTTOM_RIGHT 1u
|
||||
#define TOP_RIGHT 2u
|
||||
#define TOP_LEFT 3u
|
||||
#define CNR_FLAG_RANGE BIT_RANGE(2u)
|
||||
|
||||
/* 4bits for corner id */
|
||||
#define CORNER_VEC_OFS 2u
|
||||
#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),
|
||||
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)
|
||||
);
|
||||
|
||||
#define INNER_FLAG (1u << 10u) /* is inner vert */
|
||||
|
||||
uniform mat4 ModelViewProjectionMatrix;
|
||||
|
||||
uniform vec4 parameters[4];
|
||||
/* radi and rad per corner */
|
||||
#define recti parameters[0]
|
||||
#define rect parameters[1]
|
||||
#define radsi parameters[2].x
|
||||
#define rads parameters[2].y
|
||||
#define roundCorners parameters[3]
|
||||
|
||||
in uint vflag;
|
||||
|
||||
out float shadowFalloff;
|
||||
|
||||
void main()
|
||||
{
|
||||
uint cflag = vflag & CNR_FLAG_RANGE;
|
||||
uint vofs = (vflag >> CORNER_VEC_OFS) & CORNER_VEC_RANGE;
|
||||
|
||||
vec2 v = cornervec[cflag * 9u + vofs];
|
||||
|
||||
bool is_inner = (vflag & INNER_FLAG) != 0u;
|
||||
|
||||
shadowFalloff = (is_inner) ? 1.0 : 0.0;
|
||||
|
||||
/* Scale by corner radius */
|
||||
v *= roundCorners[cflag] * ((is_inner) ? radsi : rads);
|
||||
|
||||
/* Position to corner */
|
||||
vec4 rct = (is_inner) ? recti : rect;
|
||||
if (cflag == BOTTOM_LEFT)
|
||||
v += rct.xz;
|
||||
else if (cflag == BOTTOM_RIGHT)
|
||||
v += rct.yz;
|
||||
else if (cflag == TOP_RIGHT)
|
||||
v += rct.yw;
|
||||
else /* (cflag == TOP_LEFT) */
|
||||
v += rct.xw;
|
||||
|
||||
gl_Position = ModelViewProjectionMatrix * vec4(v, 0.0, 1.0);
|
||||
}
|
Loading…
Reference in New Issue