From 4ecc8b67861a4869cd6b1231c1f8a1082e031ff5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 14 Mar 2018 22:06:20 +0100 Subject: 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... --- intern/gawain/gawain/gwn_element.h | 14 ++++++++----- intern/gawain/src/gwn_batch.c | 31 ++++++++++++++++++++++++++++ intern/gawain/src/gwn_element.c | 42 ++++++++++++++++++++++++++++++-------- 3 files changed, 73 insertions(+), 14 deletions(-) (limited to 'intern/gawain') diff --git a/intern/gawain/gawain/gwn_element.h b/intern/gawain/gawain/gwn_element.h index 3081305769f..3015dc00e47 100644 --- a/intern/gawain/gawain/gwn_element.h +++ b/intern/gawain/gawain/gwn_element.h @@ -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); diff --git a/intern/gawain/src/gwn_batch.c b/intern/gawain/src/gwn_batch.c index 9dab2a4d7d9..b7f47b316ed 100644 --- a/intern/gawain/src/gwn_batch.c +++ b/intern/gawain/src/gwn_batch.c @@ -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); diff --git a/intern/gawain/src/gwn_element.c b/intern/gawain/src/gwn_element.c index f31b64fa232..a65ec9a18b3 100644 --- a/intern/gawain/src/gwn_element.c +++ b/intern/gawain/src/gwn_element.c @@ -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) { -- cgit v1.2.3