[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