GWN: Add primitive restart in element/index buffers.

This allows to draw multiple primitive of the type
GWN_PRIM_LINE_STRIP
GWN_PRIM_LINE_LOOP
GWN_PRIM_TRI_STRIP
GWN_PRIM_TRI_FAN
GWN_PRIM_LINE_STRIP_ADJ
with only one drawcall. This should speed up some areas that are really
sensitive to drawcall counts : UV drawing, Hair drawing...
This commit is contained in:
Clément Foucault 2018-03-14 22:06:20 +01:00
parent 2c80a4d4aa
commit 4ecc8b6786
3 changed files with 73 additions and 14 deletions

View File

@ -15,6 +15,8 @@
#define GWN_TRACK_INDEX_RANGE 1
#define GWN_PRIM_RESTART 0xFFFFFFFF
typedef enum {
GWN_INDEX_U8, // GL has this, Vulkan does not
GWN_INDEX_U16,
@ -32,6 +34,7 @@ typedef struct Gwn_IndexBuf {
#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;
void GWN_indexbuf_use(Gwn_IndexBuf*);
@ -43,17 +46,18 @@ typedef struct Gwn_IndexBufBuilder {
unsigned index_ct;
Gwn_PrimType prim_type;
unsigned* data;
bool use_prim_restart;
} Gwn_IndexBufBuilder;
// supported primitives:
// GWN_PRIM_POINTS
// GWN_PRIM_LINES
// GWN_PRIM_TRIS
// supports all primitive types.
void GWN_indexbuf_init_ex(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned index_ct, unsigned vertex_ct, bool use_prim_restart);
// supports only GWN_PRIM_POINTS, GWN_PRIM_LINES and GWN_PRIM_TRIS.
void GWN_indexbuf_init(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned prim_ct, unsigned vertex_ct);
//void GWN_indexbuf_init_custom(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned index_ct, unsigned vertex_ct);
void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder*, unsigned v);
void GWN_indexbuf_add_primitive_restart(Gwn_IndexBufBuilder*);
void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder*, unsigned v);
void GWN_indexbuf_add_line_verts(Gwn_IndexBufBuilder*, unsigned v1, unsigned v2);

View File

@ -489,6 +489,27 @@ void GWN_batch_uniform_4fv(Gwn_Batch* batch, const char* name, const float data[
glUniform4fv(uniform->location, 1, data);
}
static void primitive_restart_enable(const Gwn_IndexBuf *el)
{
// TODO(fclem) Replace by GL_PRIMITIVE_RESTART_FIXED_INDEX when we have ogl 4.3
glEnable(GL_PRIMITIVE_RESTART);
GLuint restart_index = (GLuint)0xFFFFFFFF;
#if GWN_TRACK_INDEX_RANGE
if (el->index_type == GWN_INDEX_U8)
restart_index = (GLuint)0xFF;
else if (el->index_type == GWN_INDEX_U16)
restart_index = (GLuint)0xFFFF;
#endif
glPrimitiveRestartIndex(restart_index);
}
static void primitive_restart_disable(void)
{
glDisable(GL_PRIMITIVE_RESTART);
}
void GWN_batch_draw(Gwn_Batch* batch)
{
#if TRUST_NO_ONE
@ -528,11 +549,16 @@ void GWN_batch_draw_range_ex(Gwn_Batch* batch, int v_first, int v_count, bool fo
{
const Gwn_IndexBuf* el = batch->elem;
if (el->use_prim_restart)
primitive_restart_enable(el);
#if GWN_TRACK_INDEX_RANGE
glDrawElementsInstancedBaseVertex(batch->gl_prim_type, el->index_ct, el->gl_index_type, 0, v_count, el->base_index);
#else
glDrawElementsInstanced(batch->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0, v_count);
#endif
if (el->use_prim_restart)
primitive_restart_disable();
}
else
glDrawArraysInstanced(batch->gl_prim_type, 0, batch->verts[0]->vertex_ct, v_count);
@ -547,6 +573,9 @@ void GWN_batch_draw_range_ex(Gwn_Batch* batch, int v_first, int v_count, bool fo
{
const Gwn_IndexBuf* el = batch->elem;
if (el->use_prim_restart)
primitive_restart_enable(el);
#if GWN_TRACK_INDEX_RANGE
if (el->base_index)
glDrawRangeElementsBaseVertex(batch->gl_prim_type, el->min_index, el->max_index, v_count, el->gl_index_type, 0, el->base_index);
@ -555,6 +584,8 @@ void GWN_batch_draw_range_ex(Gwn_Batch* batch, int v_first, int v_count, bool fo
#else
glDrawElements(batch->gl_prim_type, v_count, GL_UNSIGNED_INT, 0);
#endif
if (el->use_prim_restart)
primitive_restart_disable();
}
else
glDrawArrays(batch->gl_prim_type, 0, v_count);

View File

@ -61,6 +61,16 @@ void GWN_indexbuf_use(Gwn_IndexBuf* elem)
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;
builder->max_allowed_index = vertex_ct - 1;
builder->max_index_ct = index_ct;
builder->index_ct = 0; // start empty
builder->prim_type = prim_type;
builder->data = calloc(builder->max_index_ct, sizeof(unsigned));
}
void GWN_indexbuf_init(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, unsigned prim_ct, unsigned vertex_ct)
{
unsigned verts_per_prim = 0;
@ -82,11 +92,7 @@ void GWN_indexbuf_init(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, uns
return;
}
builder->max_allowed_index = vertex_ct - 1;
builder->max_index_ct = prim_ct * verts_per_prim;
builder->index_ct = 0; // start empty
builder->prim_type = prim_type;
builder->data = calloc(builder->max_index_ct, sizeof(unsigned));
GWN_indexbuf_init_ex(builder, prim_type, prim_ct * verts_per_prim, vertex_ct, false);
}
void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder* builder, unsigned v)
@ -100,6 +106,17 @@ void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder* builder, unsigned v)
builder->data[builder->index_ct++] = v;
}
void GWN_indexbuf_add_primitive_restart(Gwn_IndexBufBuilder* builder)
{
#if TRUST_NO_ONE
assert(builder->data != NULL);
assert(builder->index_ct < builder->max_index_ct);
assert(builder->use_prim_restart);
#endif
builder->data[builder->index_ct++] = GWN_PRIM_RESTART;
}
void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder* builder, unsigned v)
{
#if TRUST_NO_ONE
@ -149,7 +166,9 @@ static unsigned index_range(const unsigned values[], unsigned value_ct, unsigned
for (unsigned i = 1; i < value_ct; ++i)
{
const unsigned value = values[i];
if (value < min_value)
if (value == GWN_PRIM_RESTART)
continue;
else if (value < min_value)
min_value = value;
else if (value > max_value)
max_value = value;
@ -173,7 +192,7 @@ static void squeeze_indices_byte(const unsigned values[], Gwn_IndexBuf* elem)
elem->max_index -= base;
for (unsigned i = 0; i < index_ct; ++i)
data[i] = (GLubyte)(values[i] - base);
data[i] = (values[i] == GWN_PRIM_RESTART) ? 0xFF : (GLubyte)(values[i] - base);
}
else
{
@ -200,7 +219,7 @@ static void squeeze_indices_short(const unsigned values[], Gwn_IndexBuf* elem)
elem->max_index -= base;
for (unsigned i = 0; i < index_ct; ++i)
data[i] = (GLushort)(values[i] - base);
data[i] = (values[i] == GWN_PRIM_RESTART) ? 0xFFFF : (GLushort)(values[i] - base);
}
else
{
@ -229,9 +248,14 @@ void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder* builder, Gwn_IndexBuf* ele
#endif
elem->index_ct = builder->index_ct;
elem->use_prim_restart = builder->use_prim_restart;
#if GWN_TRACK_INDEX_RANGE
const unsigned range = index_range(builder->data, builder->index_ct, &elem->min_index, &elem->max_index);
unsigned range = index_range(builder->data, builder->index_ct, &elem->min_index, &elem->max_index);
// count the primitive restart index.
if (elem->use_prim_restart)
range += 1;
if (range <= 0xFF)
{