[Bf-blender-cvs] [33f85d0] GPU_data_request: cache GPUx batches for performance++

Mike Erwin noreply at git.blender.org
Thu Apr 16 19:57:45 CEST 2015


Commit: 33f85d0fe2a52e94722f00e46472156e15451570
Author: Mike Erwin
Date:   Thu Apr 16 13:56:34 2015 -0400
Branches: GPU_data_request
https://developer.blender.org/rB33f85d0fe2a52e94722f00e46472156e15451570

cache GPUx batches for performance++

WIP — developed on Mac, want to test on Linux & Windows so pushing
unfinished.

Everything needed for drawing is collected into a GPUxBatch. These are
generated per-object the first time drawn, then reused for subsequent
draws. Regenerated when DerivedMesh or draw mode changes.

TODO:
- actively reclaim memory (like gpu_buffers.c’s pool)
- store a list of batches per DM, for complex drawing
- find cause of low perf on high poly OB_SOLID rendering

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

M	source/blender/blenkernel/BKE_DerivedMesh.h
M	source/blender/blenkernel/intern/DerivedMesh.c
M	source/blender/editors/space_view3d/drawobject.c
M	source/blender/gpu/GPUx_draw.h
M	source/blender/gpu/intern/gpux_draw.c

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

diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 2da23d6..5626ba8 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -96,6 +96,7 @@ struct MCol;
 struct ColorBand;
 struct GPUVertexAttribs;
 struct GPUDrawObject;
+struct GPUxBatch;
 struct BMEditMesh;
 struct PBVH;
 
@@ -184,6 +185,7 @@ struct DerivedMesh {
 	int deformedOnly; /* set by modifier stack if only deformed from original */
 	BVHCache bvhCache;
 	struct GPUDrawObject *drawObject;
+	struct GPUxBatch *gpux_batch; /* TODO: replace with list of batches */
 	DerivedMeshType type;
 	float auto_bump_scale;
 	DMDirtyFlag dirty;
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 87a00c2..4da345d 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -75,6 +75,7 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
 #include "GPU_buffers.h"
 #include "GPU_extensions.h"
 #include "GPU_glew.h"
+#include "GPUx_draw.h"
 
 /* very slow! enable for testing only! */
 //#define USE_MODIFIER_VALIDATE
@@ -337,6 +338,12 @@ int DM_release(DerivedMesh *dm)
 	if (dm->needsFree) {
 		bvhcache_free(&dm->bvhCache);
 		GPU_drawobject_free(dm);
+
+		if (dm->gpux_batch) {
+			GPUx_batch_discard(dm->gpux_batch);
+			dm->gpux_batch = NULL;
+		}
+
 		CustomData_free(&dm->vertData, dm->numVertData);
 		CustomData_free(&dm->edgeData, dm->numEdgeData);
 		CustomData_free(&dm->faceData, dm->numTessFaceData);
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 7155ac5..ea45d08 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -4443,77 +4443,106 @@ static bool draw_mesh_object_new_new(Scene *scene, ARegion *ar, View3D *v3d, Reg
 	}
 	else {
 		DerivedMesh *dm = mesh_get_derived_final(scene, ob, scene->customdata_mask);
-		const int vert_ct = dm->getNumVerts(dm);
-		const int edge_ct = dm->getNumEdges(dm);
-		const int face_ct = dm->getNumTessFaces(dm);
-		const int attrib_ct = (dt > OB_WIRE) ? 2 : 1;
-	
-		VertexBuffer *verts = GPUx_vertex_buffer_create(attrib_ct, vert_ct);
-		ElementList *elem = NULL;
-		MVert *mverts = dm->getVertArray(dm);
+		bool batch_needs_setup = false;
+
+		if (dm->gpux_batch == 0) {
+			dm->gpux_batch = GPUx_batch_create();
+			batch_needs_setup = true;
+		}
+		else if (dm->gpux_batch->draw_type != dt) {
+			GPUx_batch_discard(dm->gpux_batch);
+			dm->gpux_batch = GPUx_batch_create();
+			batch_needs_setup = true;
+		}
+
+		if (batch_needs_setup) {
+			const int vert_ct = dm->getNumVerts(dm);
+			const int edge_ct = dm->getNumEdges(dm);
+			const int face_ct = dm->getNumTessFaces(dm);
+			const int attrib_ct = (dt > OB_WIRE) ? 2 : 1;
+
+			dm->gpux_batch->draw_type = dt;
+
+			VertexBuffer *verts = GPUx_vertex_buffer_create(attrib_ct, vert_ct);
+			ElementList *elem = NULL;
+			MVert *mverts = dm->getVertArray(dm);
 
 #if MCE_TRACE
-		printf("%d verts, %d edges, %d faces\n", vert_ct, edge_ct, face_ct);
+			printf("%d verts, %d edges, %d faces\n", vert_ct, edge_ct, face_ct);
 #endif /* MCE_TRACE */
 
-		GPUx_specify_attrib(verts, 0, GL_VERTEX_ARRAY, GL_FLOAT, 3, KEEP_FLOAT);
-		GPUx_fill_attrib_stride(verts, 0, mverts, sizeof(MVert));
+			GPUx_specify_attrib(verts, 0, GL_VERTEX_ARRAY, GL_FLOAT, 3, KEEP_FLOAT);
+			GPUx_fill_attrib_stride(verts, 0, mverts, sizeof(MVert));
 
-		if (dt > OB_WIRE) {
-			/* draw smooth surface */
-			/* TODO: handle flat faces */
-			/* TODO: handle loop normals */
-			int i, t, tri_ct = 0;
-			MFace *faces = dm->getTessFaceArray(dm);
-			CommonDrawState common_state = default_state.common;
-			PolygonDrawState polygon_state = default_state.polygon;
-			common_state.lighting = true;
-			polygon_state.draw_back = false;
-
-			GPUx_specify_attrib(verts, 1, GL_NORMAL_ARRAY, GL_SHORT, 3, NORMALIZE_INT_TO_FLOAT);
-			GPUx_fill_attrib_stride(verts, 1, &mverts[0].no, sizeof(MVert));
-
-			/* some tess faces are quads, some triangles
-			 * we draw just triangles, so count quads twice */
-			for (i = 0; i < face_ct; ++i)
-				tri_ct += faces[i].v4 ? 2 : 1;
-
-			elem = GPUx_element_list_create(GL_TRIANGLES, tri_ct, vert_ct - 1);
-
-			for (i = 0, t = 0; i < face_ct; ++i) {
-				const MFace *face = faces + i;
-				GPUx_set_triangle_vertices(elem, t++, face->v1, face->v2, face->v3);
-				if (face->v4)
-					GPUx_set_triangle_vertices(elem, t++, face->v4, face->v1, face->v3);
-			}
-
-			/* TODO: update state tracking to handle all these */
-			glShadeModel(GL_SMOOTH);
+			if (dt > OB_WIRE) {
+				/* draw smooth surface */
+				/* TODO: handle flat faces */
+				/* TODO: handle loop normals */
+				int i, t, tri_ct = 0;
+				MFace *faces = dm->getTessFaceArray(dm);
+				dm->gpux_batch->state.common.lighting = true;
+				dm->gpux_batch->state.polygon.draw_back = false;
+#if 1
+				GPUx_specify_attrib(verts, 1, GL_NORMAL_ARRAY, GL_SHORT, 3, NORMALIZE_INT_TO_FLOAT);
+				GPUx_fill_attrib_stride(verts, 1, &mverts[0].no, sizeof(MVert));
+#else
+				/* float normals (NOT our performance culprit) */
+				GPUx_specify_attrib(verts, 1, GL_NORMAL_ARRAY, GL_FLOAT, 3, KEEP_FLOAT);
+				for (i = 0; i < vert_ct; ++i) {
+					const float scale = 1.0f / 32768.0f;
+					GPUx_set_attrib_3f(verts, 1, i,
+						scale * mverts[i].no[0],
+						scale * mverts[i].no[1],
+						scale * mverts[i].no[2]
+						);
+				}
+#endif
+				/* some tess faces are quads, some triangles
+				 * we draw just triangles, so count quads twice */
+				for (i = 0; i < face_ct; ++i)
+					tri_ct += faces[i].v4 ? 2 : 1;
+
+				elem = GPUx_element_list_create(GL_TRIANGLES, tri_ct, vert_ct - 1);
+
+				for (i = 0, t = 0; i < face_ct; ++i) {
+					const MFace *face = faces + i;
+					GPUx_set_triangle_vertices(elem, t++, face->v1, face->v2, face->v3);
+					if (face->v4)
+						GPUx_set_triangle_vertices(elem, t++, face->v4, face->v1, face->v3);
+				}
 
-			GPUx_vertex_buffer_prime(verts);
-			GPUx_draw_triangles(verts, elem, &polygon_state, &common_state);
+				/* TODO: update state tracking to handle all these */
+//				glShadeModel(GL_SMOOTH);
 
-			glShadeModel(GL_FLAT); /* restore default */
-		}
-		else if (dt == OB_WIRE) {
-			/* draw wireframe */
-			int i;
-			MEdge *edges = dm->getEdgeArray(dm);
+				GPUx_vertex_buffer_prime(verts);
 
-			elem = GPUx_element_list_create(GL_LINES, edge_ct, vert_ct - 1);
+				dm->gpux_batch->prim_type = GL_TRIANGLES;
+				dm->gpux_batch->buff = verts;
+				dm->gpux_batch->elem = elem;
 
-			for (i = 0; i < edge_ct; ++i) {
-				const MEdge *edge = edges + i;
-				GPUx_set_line_vertices(elem, i, edge->v1, edge->v2);
+//				glShadeModel(GL_FLAT); /* restore default */
 			}
+			else if (dt == OB_WIRE) {
+				/* draw wireframe */
+				int i;
+				MEdge *edges = dm->getEdgeArray(dm);
+
+				elem = GPUx_element_list_create(GL_LINES, edge_ct, vert_ct - 1);
 
-			GPUx_vertex_buffer_prime(verts);
-			GPUx_draw_lines(verts, elem, NULL, NULL);
+				for (i = 0; i < edge_ct; ++i) {
+					const MEdge *edge = edges + i;
+					GPUx_set_line_vertices(elem, i, edge->v1, edge->v2);
+				}
+
+				GPUx_vertex_buffer_prime(verts);
+
+				dm->gpux_batch->prim_type = GL_LINES;
+				dm->gpux_batch->buff = verts;
+				dm->gpux_batch->elem = elem;
+			}
 		}
 
-		if (elem)
-			GPUx_element_list_discard(elem);
-		GPUx_vertex_buffer_discard(verts);
+		GPUx_draw_batch(dm->gpux_batch);
 	}
 
 #if MCE_TRACE
diff --git a/source/blender/gpu/GPUx_draw.h b/source/blender/gpu/GPUx_draw.h
index 4941b42..e3ccc03 100644
--- a/source/blender/gpu/GPUx_draw.h
+++ b/source/blender/gpu/GPUx_draw.h
@@ -17,4 +17,17 @@ void GPUx_draw_triangles(const VertexBuffer*, const ElementList*, const PolygonD
 /* generic version uses ElementList's primitive type */
 void GPUx_draw_primitives(const VertexBuffer*, const ElementList*, const void *primitive_state, const CommonDrawState*);
 
+typedef struct GPUxBatch {
+	GLenum prim_type; /* GL_POINTS, GL_LINES, GL_TRIANGLES (must match elem->prim_type) */
+	int draw_type; /* OB_WIRE, OB_SOLID, OB_MATERIAL */
+	DrawState state;
+	VertexBuffer *buff; /* TODO: rename "verts" */
+	ElementList *elem;
+} GPUxBatch;
+
+GPUxBatch *GPUx_batch_create();
+void GPUx_batch_discard(GPUxBatch*);
+
+void GPUx_draw_batch(const GPUxBatch*);
+
 #endif /* BLENDER_GL_DRAW_PRIMITIVES */
diff --git a/source/blender/gpu/intern/gpux_draw.c b/source/blender/gpu/intern/gpux_draw.c
index 8c6af77..7d4549d 100644
--- a/source/blender/gpu/intern/gpux_draw.c
+++ b/source/blender/gpu/intern/gpux_draw.c
@@ -2,6 +2,9 @@
 #include "GPUx_draw.h"
 #include "gpux_element_private.h"
 
+#include <stdlib.h>
+//#include <stdio.h> /* TODO: remove */
+
 #ifdef TRUST_NO_ONE
   #include <assert.h>
 #endif /* TRUST_NO_ONE */
@@ -125,3 +128,72 @@ void GPUx_draw_primitives(const VertexBuffer *vbo, const ElementList *el, const
 	GPUx_vertex_buffer_done_using(vbo);
 #endif /* REALLY_DRAW */
 }
+
+GPUxBatch *GPUx_batch_create()
+{
+//	puts(__FUNCTION__);
+	GPUxBatch *batch = calloc(1, sizeof(GPUxBatch));
+	batch->prim_type = GL_NONE;
+	batch->state = default_state;
+	return batch;
+}
+
+void GPUx_batch_discard(GPUxBatch *batch)
+{
+//	puts(__FUNCTION__);
+	GPUx_vertex_buffer_discard(batch->buff);
+	if (batch->elem)
+		GPUx_element_list_discard(batch->elem);
+	free(batch);
+}
+
+void GPUx_draw_batch(const GPUxBatch *batch)
+{
+	int vert_per_prim = 0;
+
+#ifdef TRUST_NO_ONE
+	if (batch->elem) {
+		assert(batch->elem->prim_type == batch->prim_type);
+		assert(max_index(batch->elem) < GPUx_vertex_ct(batch->buff));
+	}
+#endif /* TRUST_NO_ONE */
+
+	switch (batch->prim_type) {
+		case GL_POINTS:
+			GPUx_set_point_state(&batch->state.point);
+			vert_per_prim = 1;
+			break;
+		case GL_LINES:
+			GPUx_set_line_state(&batch->state.line);
+			vert_per_prim = 2;
+			break;
+		case GL_TRIANGLES:
+			GPUx_set_polygon_state(&batch->state.polygon);
+			vert_per_prim = 3;
+			glShadeModel(GL_SMOOTH);
+			break;
+		default:
+#ifdef TRUST_NO_ONE
+			assert(false);
+#else
+			return;
+#endif /* TRUST_NO_ONE */
+	}
+
+	GPUx_set_common_state(&batch->state.common);

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list