GWN: Element Buffer: Refactor / Optimisation.

- Upload the data to the GPU directly when creating the element buffer in
   GWN_indexbuf_build_in_place().

 - Convert data in place when squeezing the indices and removing the need
   for another allocation.

 - GWN_indexbuf_build_in_place() can be used with already used element
   buffers and reupload their data without changing vbo id (keeping vaos
   up to date).
This commit is contained in:
Clément Foucault 2018-03-17 18:23:04 +01:00
parent 87d88581aa
commit c2f36c3558
Notes: blender-bot 2023-02-14 10:37:50 +01:00
Referenced by issue #54327, Gawain: Perf: Add update routines for Gwn_VertBuf
2 changed files with 25 additions and 60 deletions

View File

@ -32,7 +32,6 @@ typedef struct Gwn_IndexBuf {
unsigned max_index;
unsigned base_index;
#endif
void* data; // NULL indicates data in VRAM (unmapped) or not yet allocated
GLuint vbo_id; // 0 indicates not yet sent to VRAM
bool use_prim_restart;
} Gwn_IndexBuf;

View File

@ -39,28 +39,6 @@ unsigned GWN_indexbuf_size_get(const Gwn_IndexBuf* elem)
#endif
}
static void ElementList_prime(Gwn_IndexBuf* elem)
{
elem->vbo_id = GWN_buf_id_alloc();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
// fill with delicious data & send to GPU the first time only
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GWN_indexbuf_size_get(elem), elem->data, GL_STATIC_DRAW);
#if KEEP_SINGLE_COPY
// now that GL has a copy, discard original
free(elem->data);
elem->data = NULL;
#endif
}
void GWN_indexbuf_use(Gwn_IndexBuf* elem)
{
if (elem->vbo_id)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
else
ElementList_prime(elem);
}
void GWN_indexbuf_init_ex(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, unsigned index_ct, unsigned vertex_ct, bool use_prim_restart)
{
builder->use_prim_restart = use_prim_restart;
@ -178,10 +156,14 @@ static unsigned index_range(const unsigned values[], unsigned value_ct, unsigned
return max_value - min_value;
}
static void squeeze_indices_byte(const unsigned values[], Gwn_IndexBuf* elem)
static void squeeze_indices_byte(Gwn_IndexBufBuilder *builder, Gwn_IndexBuf* elem)
{
const unsigned *values = builder->data;
const unsigned index_ct = elem->index_ct;
GLubyte* data = malloc(index_ct * sizeof(GLubyte));
// data will never be *larger* than builder->data...
// converting in place to avoid extra allocation
GLubyte *data = (GLubyte *)builder->data;
if (elem->max_index > 0xFF)
{
@ -201,14 +183,16 @@ static void squeeze_indices_byte(const unsigned values[], Gwn_IndexBuf* elem)
for (unsigned i = 0; i < index_ct; ++i)
data[i] = (GLubyte)(values[i]);
}
elem->data = data;
}
static void squeeze_indices_short(const unsigned values[], Gwn_IndexBuf* elem)
static void squeeze_indices_short(Gwn_IndexBufBuilder *builder, Gwn_IndexBuf* elem)
{
const unsigned *values = builder->data;
const unsigned index_ct = elem->index_ct;
GLushort* data = malloc(index_ct * sizeof(GLushort));
// data will never be *larger* than builder->data...
// converting in place to avoid extra allocation
GLushort *data = (GLushort *)builder->data;
if (elem->max_index > 0xFFFF)
{
@ -228,8 +212,6 @@ static void squeeze_indices_short(const unsigned values[], Gwn_IndexBuf* elem)
for (unsigned i = 0; i < index_ct; ++i)
data[i] = (GLushort)(values[i]);
}
elem->data = data;
}
#endif // GWN_TRACK_INDEX_RANGE
@ -260,60 +242,44 @@ void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder* builder, Gwn_IndexBuf* ele
if (range <= 0xFF)
{
elem->index_type = GWN_INDEX_U8;
squeeze_indices_byte(builder->data, elem);
squeeze_indices_byte(builder, elem);
}
else if (range <= 0xFFFF)
{
elem->index_type = GWN_INDEX_U16;
squeeze_indices_short(builder->data, elem);
squeeze_indices_short(builder, elem);
}
else
{
elem->index_type = GWN_INDEX_U32;
elem->base_index = 0;
if (builder->index_ct < builder->max_index_ct)
{
builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned));
// TODO: realloc only if index_ct is much smaller than max_index_ct
}
elem->data = builder->data;
}
elem->gl_index_type = convert_index_type_to_gl(elem->index_type);
#else
if (builder->index_ct < builder->max_index_ct)
{
builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned));
// TODO: realloc only if index_ct is much smaller than max_index_ct
}
elem->data = builder->data;
#endif
// elem->data will never be *larger* than builder->data... how about converting
// in place to avoid extra allocation?
if (elem->vbo_id == 0)
elem->vbo_id = GWN_buf_id_alloc();
elem->vbo_id = 0;
// TODO: create GL buffer object directly, based on an input flag
// send data to GPU
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, GWN_indexbuf_size_get(elem), builder->data, GL_STATIC_DRAW);
// discard builder (one-time use)
if (builder->data != elem->data)
free(builder->data);
free(builder->data);
builder->data = NULL;
// other fields are safe to leave
}
void GWN_indexbuf_use(Gwn_IndexBuf* elem)
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id);
}
void GWN_indexbuf_discard(Gwn_IndexBuf* elem)
{
if (elem->vbo_id)
GWN_buf_id_free(elem->vbo_id);
#if KEEP_SINGLE_COPY
else
#endif
if (elem->data)
free(elem->data);
free(elem);
}