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.
This commit is contained in:
parent
ba9c2746b6
commit
f6ad538040
|
@ -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__ */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue