[Bf-blender-cvs] [8b607d77e5c] strand_editmode: New gtests for the mesh sampling system.

Lukas Tönne noreply at git.blender.org
Tue Aug 22 19:51:48 CEST 2017


Commit: 8b607d77e5cb0a47788793303f668767ed9005b7
Author: Lukas Tönne
Date:   Tue Aug 22 18:49:01 2017 +0100
Branches: strand_editmode
https://developer.blender.org/rB8b607d77e5cb0a47788793303f668767ed9005b7

New gtests for the mesh sampling system.

This should test general functionality and consistency of different methods
for generating samples. In particular it shoud ensure that threaded variants
produce the same samples as unthreaded variants when using the same generator
and seeds.

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

M	source/blender/blenkernel/intern/mesh_sample.c
M	tests/gtests/CMakeLists.txt
A	tests/gtests/blenkernel/BKE_mesh_sample_test.cc
A	tests/gtests/blenkernel/BKE_mesh_test_util.cc
A	tests/gtests/blenkernel/BKE_mesh_test_util.h
A	tests/gtests/blenkernel/CMakeLists.txt

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

diff --git a/source/blender/blenkernel/intern/mesh_sample.c b/source/blender/blenkernel/intern/mesh_sample.c
index f3224d7467e..09b3adcbc84 100644
--- a/source/blender/blenkernel/intern/mesh_sample.c
+++ b/source/blender/blenkernel/intern/mesh_sample.c
@@ -955,6 +955,14 @@ int BKE_mesh_sample_generate_batch_ex(MeshSampleGenerator *gen,
 			}
 		}
 		
+		if (gen->thread_context_free) {
+			MeshSampleTaskData *td = task_data;
+			for (int i = 0; i < num_tasks; ++i, ++td) {
+				if (td->thread_ctx) {
+					gen->thread_context_free(gen, td->thread_ctx);
+				}
+			}
+		}
 		MEM_freeN(task_data);
 		
 		return totresult;
diff --git a/tests/gtests/CMakeLists.txt b/tests/gtests/CMakeLists.txt
index 781da7bf452..09b18beffa2 100644
--- a/tests/gtests/CMakeLists.txt
+++ b/tests/gtests/CMakeLists.txt
@@ -13,6 +13,7 @@ if(WITH_GTESTS)
 
 	add_subdirectory(testing)
 	add_subdirectory(blenlib)
+	add_subdirectory(blenkernel)
 	add_subdirectory(guardedalloc)
 	add_subdirectory(bmesh)
 	if(WITH_ALEMBIC)
diff --git a/tests/gtests/blenkernel/BKE_mesh_sample_test.cc b/tests/gtests/blenkernel/BKE_mesh_sample_test.cc
new file mode 100644
index 00000000000..786e1badde3
--- /dev/null
+++ b/tests/gtests/blenkernel/BKE_mesh_sample_test.cc
@@ -0,0 +1,143 @@
+/* Apache License, Version 2.0 */
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+#include "testing/testing.h"
+
+#include "BKE_mesh_test_util.h"
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_mesh.h"
+#include "BKE_mesh_sample.h"
+}
+
+//#define TEST_MESH_OUTPUT_FILE "mesh_dump_"
+
+static const float verts[][3] = { {-1, -1, -1}, {1, -1, -1}, {-1, 1, -1}, {1, 1, -1},
+                                  {-1, -1, 1},  {1, -1, 1},  {-1, 1, 1},  {1, 1, 1} };
+static const int faces[] = { 0, 1, 3, 2,
+                             4, 5, 7, 6,
+                             0, 1, 5, 4,
+                             2, 3, 7, 6,
+                             0, 2, 6, 4,
+                             1, 3, 7, 5,
+                           };
+static const int face_sizes[] = { 4, 4, 4, 4, 4, 4 };
+
+static void dump_samples(const char *testname, const Mesh *mesh, const MeshSample *samples, int numsamples)
+{
+#ifdef TEST_MESH_OUTPUT_FILE
+	int numverts = mesh->totvert;
+	
+	int dbg_numverts = numverts + numsamples;
+	float (*dbg_verts)[3] = (float (*)[3])MEM_mallocN(sizeof(float[3]) * dbg_numverts, "vertices");
+	for (int i = 0; i < numverts; ++i) {
+		copy_v3_v3(dbg_verts[i], mesh->mvert[i].co);
+	}
+	for (int i = 0; i < numsamples; ++i) {
+		float nor[3], tang[3];
+		BKE_mesh_sample_eval(dm, &samples[i], dbg_verts[numverts + i], nor, tang);
+	}
+	Mesh *dbg_mesh = BKE_mesh_test_from_data(dbg_verts, dbg_numverts, NULL, 0, faces, face_sizes, numfaces);
+	MEM_freeN(dbg_verts);
+	
+	std::stringstream filename;
+	filename << TEST_MESH_OUTPUT_FILE << testname << ".py";
+	std::fstream s(filename.str(), s.trunc | s.out);
+	
+	BKE_mesh_test_dump_mesh(dbg_mesh, testname, s);
+	
+	BKE_mesh_free(dbg_mesh);
+	MEM_freeN(dbg_mesh);
+#else
+	UNUSED_VARS(testname, mesh, samples, numsamples);
+#endif
+}
+
+static void compare_samples(const MeshSample *ground_truth, const MeshSample *samples, int count)
+{
+	for (int i = 0; i < count; ++i) {
+		EXPECT_EQ(ground_truth[i].orig_verts[0], samples[i].orig_verts[0]);
+		EXPECT_EQ(ground_truth[i].orig_verts[1], samples[i].orig_verts[1]);
+		EXPECT_EQ(ground_truth[i].orig_verts[2], samples[i].orig_verts[2]);
+		
+		EXPECT_EQ(ground_truth[i].orig_weights[0], samples[i].orig_weights[0]);
+		EXPECT_EQ(ground_truth[i].orig_weights[1], samples[i].orig_weights[1]);
+		EXPECT_EQ(ground_truth[i].orig_weights[2], samples[i].orig_weights[2]);
+	}
+}
+
+static void generate_samples_simple(MeshSampleGenerator *gen, MeshSample *samples, int count)
+{
+	for (int i = 0; i < count; ++i) {
+		BKE_mesh_sample_generate(gen, &samples[i]);
+	}
+}
+
+static void generate_samples_batch(MeshSampleGenerator *gen, MeshSample *samples, int count)
+{
+	BKE_mesh_sample_generate_batch_ex(gen, samples, sizeof(MeshSample), count, false);
+}
+
+static void generate_samples_batch_threaded(MeshSampleGenerator *gen, MeshSample *samples, int count)
+{
+	BKE_mesh_sample_generate_batch_ex(gen, samples, sizeof(MeshSample), count, true);
+}
+
+static void test_samples(MeshSampleGenerator *gen, const MeshSample *ground_truth, MeshSample *samples, int count)
+{
+	generate_samples_simple(gen, samples, count);
+	if (ground_truth) {
+		compare_samples(ground_truth, samples, count);
+	}
+	else {
+		// Use simple sample generation as ground truth if not provided explicitly
+		ground_truth = samples;
+	}
+	
+	generate_samples_batch(gen, samples, count);
+	compare_samples(ground_truth, samples, count);
+	
+	generate_samples_batch_threaded(gen, samples, count);
+	compare_samples(ground_truth, samples, count);
+}
+
+TEST(mesh_sample, SurfaceRandom)
+{
+	int numverts = ARRAY_SIZE(verts);
+	int numfaces = ARRAY_SIZE(face_sizes);
+	Mesh *mesh = BKE_mesh_test_from_data(verts, numverts, NULL, 0, faces, face_sizes, numfaces);
+	DerivedMesh *dm = CDDM_from_mesh(mesh);
+	
+	const unsigned int seed = 8343;
+	const int numsamples = 100000;
+	MeshSample *samples = (MeshSample *)MEM_mallocN(sizeof(MeshSample) * numsamples, "mesh samples");
+	
+	std::stringstream testname;
+	testname << ::testing::UnitTest::GetInstance()->current_test_info()->name() << "_" << seed;
+	
+	{
+		MeshSampleGenerator *gen = BKE_mesh_sample_gen_surface_random(dm, seed);
+		ASSERT_TRUE(gen != NULL) << "No generator created";
+		
+		test_samples(gen, NULL, samples, numsamples);
+		dump_samples(testname.str().c_str(), mesh, samples, numsamples);
+		
+		BKE_mesh_sample_free_generator(gen);
+	}
+	
+	MEM_freeN(samples);
+	
+	dm->release(dm);
+	BKE_mesh_free(mesh);
+	MEM_freeN(mesh);
+}
diff --git a/tests/gtests/blenkernel/BKE_mesh_test_util.cc b/tests/gtests/blenkernel/BKE_mesh_test_util.cc
new file mode 100644
index 00000000000..f72ee7c74d0
--- /dev/null
+++ b/tests/gtests/blenkernel/BKE_mesh_test_util.cc
@@ -0,0 +1,276 @@
+/* Apache License, Version 2.0 */
+
+#include <iostream>
+#include <iomanip>
+
+#include "BKE_mesh_test_util.h"
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+}
+
+static void mesh_update(Mesh *mesh, int calc_edges, int calc_tessface)
+{
+	bool tessface_input = false;
+
+	if (mesh->totface > 0 && mesh->totpoly == 0) {
+		BKE_mesh_convert_mfaces_to_mpolys(mesh);
+
+		/* would only be converting back again, don't bother */
+		tessface_input = true;
+	}
+
+	if (calc_edges || ((mesh->totpoly || mesh->totface) && mesh->totedge == 0))
+		BKE_mesh_calc_edges(mesh, calc_edges, true);
+
+	if (calc_tessface) {
+		if (tessface_input == false) {
+			BKE_mesh_tessface_calc(mesh);
+		}
+	}
+	else {
+		/* default state is not to have tessface's so make sure this is the case */
+		BKE_mesh_tessface_clear(mesh);
+	}
+
+	BKE_mesh_calc_normals(mesh);
+}
+
+static void mesh_add_verts(Mesh *mesh, int len)
+{
+	CustomData vdata;
+
+	if (len == 0)
+		return;
+
+	int totvert = mesh->totvert + len;
+	CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert);
+	CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert);
+
+	if (!CustomData_has_layer(&vdata, CD_MVERT))
+		CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert);
+
+	CustomData_free(&mesh->vdata, mesh->totvert);
+	mesh->vdata = vdata;
+	BKE_mesh_update_customdata_pointers(mesh, false);
+
+	/* scan the input list and insert the new vertices */
+
+	/* set final vertex list size */
+	mesh->totvert = totvert;
+}
+
+static void mesh_add_edges(Mesh *mesh, int len)
+{
+	CustomData edata;
+	MEdge *medge;
+	int i, totedge;
+
+	if (len == 0)
+		return;
+
+	totedge = mesh->totedge + len;
+
+	/* update customdata  */
+	CustomData_copy(&mesh->edata, &edata, CD_MASK_MESH, CD_DEFAULT, totedge);
+	CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge);
+
+	if (!CustomData_has_layer(&edata, CD_MEDGE))
+		CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, NULL, totedge);
+
+	CustomData_free(&mesh->edata, mesh->totedge);
+	mesh->edata = edata;
+	BKE_mesh_update_customdata_pointers(mesh, false); /* new edges don't change tessellation */
+
+	/* set default flags */
+	medge = &mesh->medge[mesh->totedge];
+	for (i = 0; i < len; i++, medge++)
+		medge->flag = ME_EDGEDRAW | ME_EDGERENDER;
+
+	mesh->totedge = totedge;
+}
+
+static void mesh_add_loops(Mesh *mesh, int len)
+{
+	CustomData ldata;
+	int totloop;
+
+	if (len == 0)
+		return;
+
+	totloop = mesh->totloop + len;   /* new face count */
+
+	/* update customdata */
+	CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloop);
+	CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop);
+
+	if (!CustomData_has_layer(&ldata, CD_MLOOP))
+		CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloop);
+
+	CustomData_free(&mesh->ldata, mesh->totloop);
+	mesh->ldata = ldata;
+	BKE_mesh_update_customdata_pointers(mesh, true);
+
+	mesh->totloop = totloop;
+}
+
+static void mesh_add_polys(Mesh *mesh, int len)
+{
+	CustomData pdata;
+	MPoly *mpoly;
+	int i, totpoly;
+
+	if (len == 0)
+		return;
+
+	totpoly = mesh->totpoly + len;   /* new face count */
+
+	/* update customdata */
+	CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpoly);
+	CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly);
+
+	if (!CustomData_has_layer(&pdata, CD_MPOLY))
+		CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpoly);
+
+	CustomData_free(&mesh->pdata, mesh->totpoly);
+	mesh->pdata = pdata;
+	BKE_mesh_update_customdata_pointers(mesh, true);
+
+	/* set default flags */
+	mpoly = &mesh->mpoly[mesh->totpoly];
+	for (i = 0; i < len; i++, mpoly++)
+		mpoly->flag = ME_FACE_SEL;
+
+	mesh->totpoly = totpoly;
+}
+
+Mesh* BKE_mesh_test_from_data(
+        const float (*verts)[3], int numverts,
+        const int (*edges)[2], int numedges,
+        const int *loops, const int *face_lengths, int numfaces)
+{
+	Mesh *me = (Mesh *)MEM_callocN(sizeof(Mesh),

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list