[Bf-blender-cvs] [8991e0f] opensubdiv-modifier: OpenSubdiv: Reduce number of glDrawEleemnts calls when in solid view

Sergey Sharybin noreply at git.blender.org
Thu Jul 17 20:11:34 CEST 2014


Commit: 8991e0f3a36a631203af7f0d760faede9ea5a7c0
Author: Sergey Sharybin
Date:   Thu Jul 17 14:48:12 2014 +0600
https://developer.blender.org/rB8991e0f3a36a631203af7f0d760faede9ea5a7c0

OpenSubdiv: Reduce number of glDrawEleemnts calls when in solid view

Made it so OsdGLMesh partitions are drawn in batches, so if mesh does have
a continuous set of faces with the same material they all will be displayed
with a single glDrawEelemnts call.

Not sure how this affects on performance on the better quality cards, but
on laptop it brings FPS back to the same value as it was before implementing
multiple textures in solid view (it's around 25% speed gain on Intel card).

That's a good practice anyway to reduce number of glDrawElements anyway, so
even if we wouldn't support low-end GPU with old driver (because of geometry
shader) it's still good to have.

Improvements to textured and GLSL display will be done later,

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

M	intern/opensubdiv/opensubdiv_capi.h
M	intern/opensubdiv/opensubdiv_gpu_capi.cc
M	source/blender/blenkernel/intern/CCGSubSurf.c
M	source/blender/blenkernel/intern/CCGSubSurf.h
M	source/blender/blenkernel/intern/subsurf_ccg.c

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

diff --git a/intern/opensubdiv/opensubdiv_capi.h b/intern/opensubdiv/opensubdiv_capi.h
index c596dd1..bee636f 100644
--- a/intern/opensubdiv/opensubdiv_capi.h
+++ b/intern/opensubdiv/opensubdiv_capi.h
@@ -99,7 +99,8 @@ void openSubdiv_osdGLMeshDisplayPrepare(void);
 /* Draw patches which corresponds to a given partition. */
 void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
                                  int fill_quads,
-                                 int partition);
+                                 int start_partition,
+                                 int num_partitions);
 
 /* ** Utility functions ** */
 int openSubdiv_getAvailableControllers(void);
diff --git a/intern/opensubdiv/opensubdiv_gpu_capi.cc b/intern/opensubdiv/opensubdiv_gpu_capi.cc
index b3d9733..d350f54 100644
--- a/intern/opensubdiv/opensubdiv_gpu_capi.cc
+++ b/intern/opensubdiv/opensubdiv_gpu_capi.cc
@@ -49,6 +49,8 @@
 
 #include "opensubdiv_partitioned.h"
 
+using OpenSubdiv::FarPatchTables;
+using OpenSubdiv::OsdDrawContext;
 using OpenSubdiv::OsdGLMeshInterface;
 using OpenSubdiv::PartitionedGLMeshInterface;
 
@@ -390,25 +392,13 @@ void openSubdiv_osdGLMeshDisplayPrepare(void)
 #endif
 }
 
-void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
-                                 int fill_quads,
-                                 int partition)
+static GLuint preapre_patchDraw(PartitionedGLMeshInterface *mesh,
+                                bool fill_quads)
 {
-	openSubdiv_osdGLDisplayInit();
-
-	using OpenSubdiv::OsdDrawContext;
-	using OpenSubdiv::FarPatchTables;
-
-	PartitionedGLMeshInterface *mesh =
-		(PartitionedGLMeshInterface *)(gl_mesh->descriptor);
-
-	OsdDrawContext::PatchArrayVector const &patches =
-	        partition >= 0
-	            ? mesh->GetPatchArrays(partition)
-	            : mesh->GetDrawContext()->patchArrays;
+	GLuint program = 0;
 
 #ifndef OPENSUBDIV_LEGACY_DRAW
-	GLuint program = g_smooth_fill_program;
+	program = g_smooth_fill_program;
 	if (fill_quads) {
 		int model;
 		glGetIntegerv(GL_SHADE_MODEL, &model);
@@ -423,39 +413,137 @@ void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
 
 	bindProgram(mesh, program);
 #else
+	(void) mesh;
 	if (!fill_quads) {
 		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 	}
 #endif
 
-	for (int i = 0; i < (int)patches.size(); ++i) {
-		OpenSubdiv::OsdDrawContext::PatchArray const &patch = patches[i];
-		OpenSubdiv::OsdDrawContext::PatchDescriptor desc = patch.GetDescriptor();
-		OpenSubdiv::FarPatchTables::Type patchType = desc.GetType();
+	return program;
+}
 
-		if (patchType == OpenSubdiv::FarPatchTables::QUADS) {
-			int mode = GL_QUADS;
+static void perform_drawElements(GLuint program,
+                                 int patch_index,
+                                 int num_elements,
+                                 int start_element)
+{
+	int mode = GL_QUADS;
 #ifndef OPENSUBDIV_LEGACY_DRAW
-			glUniform1i(glGetUniformLocation(program, "PrimitiveIdBase"),
-			            patch.GetPatchIndex());
-			mode = GL_LINES_ADJACENCY;
+	glUniform1i(glGetUniformLocation(program, "PrimitiveIdBase"),
+	            patch_index);
+	mode = GL_LINES_ADJACENCY;
+#else
+	(void) patch_index;
 #endif
-			glDrawElements(mode,
-			               patch.GetNumIndices(),
-			               GL_UNSIGNED_INT,
-			               (void *)(patch.GetVertIndex() *
-			                        sizeof(unsigned int)));
-		}
-	}
+	glDrawElements(mode,
+	               num_elements,
+	               GL_UNSIGNED_INT,
+	               (void *)(start_element * sizeof(unsigned int)));
+}
+
+static void finish_patchDraw(bool fill_quads)
+{
+	/* TODO(sergey): Some of the stuff could be done once after the whole
+	 * mesh is displayed.
+	 */
 
 	/* Restore state. */
 	if (!fill_quads) {
 		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 	}
 	glBindVertexArray(0);
+
 #ifndef OPENSUBDIV_LEGACY_DRAW
 	glActiveTexture(GL_TEXTURE0);
 	/* TODO(sergey): Store previously used program and roll back to it? */
 	glUseProgram(0);
 #endif
 }
+
+static void draw_partition_patches_range(PartitionedGLMeshInterface *mesh,
+                                         GLuint program,
+                                         int start_partition,
+                                         int num_partitions)
+{
+	/* Glue patches from all partitions in the range together. */
+	int patch_index = -1, start_element = -1, num_elements = 0;
+	for (int partition = start_partition;
+	     partition < start_partition + num_partitions;
+	     ++partition)
+	{
+		OsdDrawContext::PatchArrayVector const &patches =
+		        mesh->GetPatchArrays(partition);
+		for (int i = 0; i < (int)patches.size(); ++i) {
+			OsdDrawContext::PatchArray const &patch = patches[i];
+			OsdDrawContext::PatchDescriptor desc = patch.GetDescriptor();
+			OpenSubdiv::FarPatchTables::Type patchType = desc.GetType();
+			if (patchType == OpenSubdiv::FarPatchTables::QUADS) {
+				if (start_element == -1) {
+					patch_index = patch.GetPatchIndex();
+					start_element = patch.GetVertIndex();
+				}
+
+				assert(patch.GetVertIndex() == start_element + num_elements);
+				num_elements += patch.GetNumIndices();
+			}
+			else {
+				assert(!"Discontinuitied are not supported yet.");
+			}
+		}
+	}
+
+	/* Perform actual draw. */
+	perform_drawElements(program,
+	                     patch_index,
+	                     num_elements,
+	                     start_element);
+}
+
+static void draw_all_patches(PartitionedGLMeshInterface *mesh,
+                             GLuint program)
+{
+	OsdDrawContext::PatchArrayVector const &patches =
+	        mesh->GetDrawContext()->patchArrays;
+
+	for (int i = 0; i < (int)patches.size(); ++i) {
+		OsdDrawContext::PatchArray const &patch = patches[i];
+		OsdDrawContext::PatchDescriptor desc = patch.GetDescriptor();
+		OpenSubdiv::FarPatchTables::Type patchType = desc.GetType();
+
+		if (patchType == OpenSubdiv::FarPatchTables::QUADS) {
+			perform_drawElements(program,
+			                     patch.GetPatchIndex(),
+			                     patch.GetNumIndices(),
+			                     patch.GetVertIndex());
+		}
+	}
+
+}
+
+void openSubdiv_osdGLMeshDisplay(OpenSubdiv_GLMesh *gl_mesh,
+                                 int fill_quads,
+                                 int start_partition,
+                                 int num_partitions)
+{
+	PartitionedGLMeshInterface *mesh =
+		(PartitionedGLMeshInterface *)(gl_mesh->descriptor);
+
+	/* Make sure all global invariants are initialized. */
+	openSubdiv_osdGLDisplayInit();
+
+	/* Setup GLSL/OpenGL to draw patches in current context. */
+	GLuint program = preapre_patchDraw(mesh, fill_quads != 0);
+
+	if (start_partition != -1) {
+		draw_partition_patches_range(mesh,
+		                             program,
+		                             start_partition,
+		                             num_partitions);
+	}
+	else {
+		draw_all_patches(mesh, program);
+	}
+
+	/* Finish patch drawing by restoring all changes to the OpenGL context. */
+	finish_patchDraw(fill_quads != 0);
+}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index c37ab44..32df69d 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -2397,12 +2397,14 @@ void ccgSubSurf_prepareGLMesh(CCGSubSurf *ss)
 	openSubdiv_osdGLMeshDisplayPrepare();
 }
 
-void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads, int material)
+void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
+                           int start_partition, int num_partitions)
 {
 	if (LIKELY(ss->osd_mesh != NULL)) {
 		openSubdiv_osdGLMeshBindVertexBuffer(ss->osd_mesh);
 		glBindVertexArray(ss->osd_vao);
-		openSubdiv_osdGLMeshDisplay(ss->osd_mesh, fill_quads, material);
+		openSubdiv_osdGLMeshDisplay(ss->osd_mesh, fill_quads,
+		                            start_partition, num_partitions);
 		glBindVertexArray(0);
 		glBindBuffer(GL_ARRAY_BUFFER, 0);
 	}
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h
index 99c99e3..28062ff 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.h
+++ b/source/blender/blenkernel/intern/CCGSubSurf.h
@@ -188,7 +188,8 @@ void				ccgFaceIterator_free		(CCGFaceIterator *fi);
 
 #ifdef WITH_OPENSUBDIV
 void ccgSubSurf_prepareGLMesh(CCGSubSurf *ss);
-void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads, int material);
+void ccgSubSurf_drawGLMesh(CCGSubSurf *ss, bool fill_quads,
+                           int start_partition, int num_partitions);
 void ccgSubSurf_setSkipGrids(CCGSubSurf *ss, bool skip_grids);
 #endif
 
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index e829223..32ec038 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -1666,7 +1666,7 @@ static void ccgDM_drawEdges(DerivedMesh *dm, bool drawLooseEdges, bool drawAllEd
 	if (ccgdm->useGpuBackend) {
 		/* TODO(sergey): We currently only support all edges drawing. */
 		ccgSubSurf_prepareGLMesh(ss);
-		ccgSubSurf_drawGLMesh(ss, false, -1);
+		ccgSubSurf_drawGLMesh(ss, false, -1, -1);
 		return;
 	}
 #endif
@@ -1791,6 +1791,7 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
 	if (ccgdm->useGpuBackend) {
 		int i, matnr = -1, shademodel = -1;
 		CCGFaceIterator *fi;
+		int start_partition = 0, num_partitions = 0;
 		ccgSubSurf_prepareGLMesh(ss);
 
 		for (fi = ccgSubSurf_getFaceIterator(ss), i = 0;
@@ -1812,20 +1813,35 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
 				new_matnr = 0;
 			}
 
-			if (new_shademodel != shademodel) {
+			if (new_shademodel != shademodel || new_matnr != matnr) {
+				if (num_partitions) {
+					ccgSubSurf_drawGLMesh(ss, true,
+					                      start_partition, num_partitions);
+				}
+
+				start_partition = i;
+				num_partitions = 0;
+
+				/* Update material settings for the next partitions batch. */
 				glShadeModel(new_shademodel);
-				shademodel = new_shademodel;
-			}
+				if (new_matnr != matnr) {
+					setMaterial(new_matnr + 1, NULL);
+				}
 
-		

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list