[Bf-blender-cvs] [4ecc8b67861] blender2.8: GWN: Add primitive restart in element/index buffers.

Clément Foucault noreply at git.blender.org
Wed Mar 14 22:44:30 CET 2018


Commit: 4ecc8b67861a4869cd6b1231c1f8a1082e031ff5
Author: Clément Foucault
Date:   Wed Mar 14 22:06:20 2018 +0100
Branches: blender2.8
https://developer.blender.org/rB4ecc8b67861a4869cd6b1231c1f8a1082e031ff5

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...

===================================================================

M	intern/gawain/gawain/gwn_element.h
M	intern/gawain/src/gwn_batch.c
M	intern/gawain/src/gwn_element.c

===================================================================

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)
 		{



More information about the Bf-blender-cvs mailing list