BVHCache: Performance

This patch changes the BVHCache implementation. It will use
a primitive array in stead of the ListBase. The locking is also
changed from a global lock to a per cache instance lock.

The performance of `gabby.blend` available on the cloud increased from 9.7
fps to 10.5 fps.

Reviewed By: Brecht van Lommel

Differential Revision: https://developer.blender.org/D7817
This commit is contained in:
Jeroen Bakker
2020-06-02 15:59:30 +02:00
committed by Jeroen Bakker
parent bf34b0c8f4
commit 752139556f
7 changed files with 300 additions and 242 deletions

View File

@@ -25,6 +25,7 @@
#include "BLI_bitmap.h"
#include "BLI_kdopbvh.h"
#include "BLI_threads.h"
#ifdef __cplusplus
extern "C" {
@@ -39,7 +40,7 @@ struct MFace;
struct MVert;
struct Mesh;
typedef struct LinkNode BVHCache;
struct BVHCache;
/**
* Struct that stores basic information about a BVHTree built from a edit-mesh.
@@ -98,6 +99,9 @@ typedef enum BVHCacheType {
BVHTREE_FROM_EM_VERTS,
BVHTREE_FROM_EM_EDGES,
BVHTREE_FROM_EM_LOOPTRI,
/* Keep `BVHTREE_MAX_ITEM` as last item. */
BVHTREE_MAX_ITEM,
} BVHCacheType;
/**
@@ -122,7 +126,8 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache);
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -134,7 +139,8 @@ BVHTree *bvhtree_from_mesh_verts_ex(struct BVHTreeFromMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache);
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
@@ -147,7 +153,8 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache);
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -161,7 +168,8 @@ BVHTree *bvhtree_from_mesh_edges_ex(struct BVHTreeFromMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache);
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -175,7 +183,8 @@ BVHTree *bvhtree_from_mesh_faces_ex(struct BVHTreeFromMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache);
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, int tree_type, int axis);
@@ -188,7 +197,8 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache);
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
const struct MVert *vert,
@@ -204,7 +214,8 @@ BVHTree *bvhtree_from_mesh_looptri_ex(struct BVHTreeFromMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache);
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
struct Mesh *mesh,
@@ -215,7 +226,8 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const int tree_type,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache);
struct BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex);
/**
* Frees data allocated by a call to bvhtree_from_mesh_*.
@@ -244,10 +256,9 @@ float bvhtree_sphereray_tri_intersection(const BVHTreeRay *ray,
/* Using local coordinates */
bool bvhcache_find(const BVHCache *cache, BVHCacheType type, BVHTree **r_tree);
bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree);
void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, BVHCacheType type);
void bvhcache_free(BVHCache **cache_p);
bool bvhcache_has_tree(const struct BVHCache *bvh_cache, const BVHTree *tree);
struct BVHCache *bvhcache_init(void);
void bvhcache_free(struct BVHCache *bvh_cache);
#ifdef __cplusplus
}

View File

@@ -41,8 +41,126 @@
#include "MEM_guardedalloc.h"
static ThreadRWMutex cache_rwlock = BLI_RWLOCK_INITIALIZER;
/* -------------------------------------------------------------------- */
/** \name BVHCache
* \{ */
typedef struct BVHCacheItem {
bool is_filled;
BVHTree *tree;
} BVHCacheItem;
typedef struct BVHCache {
BVHCacheItem items[BVHTREE_MAX_ITEM];
ThreadMutex mutex;
} BVHCache;
/**
* Queries a bvhcache for the cache bvhtree of the request type
*
* When the `r_locked` is filled and the tree could not be found the caches mutex will be
* locked. This mutex can be unlocked by calling `bvhcache_unlock`.
*
* When `r_locked` is used the `mesh_eval_mutex` must contain the `Mesh_Runtime.eval_mutex`.
*/
static bool bvhcache_find(BVHCache **bvh_cache_p,
BVHCacheType type,
BVHTree **r_tree,
bool *r_locked,
ThreadMutex *mesh_eval_mutex)
{
bool do_lock = r_locked;
if (r_locked) {
*r_locked = false;
}
if (*bvh_cache_p == NULL) {
if (!do_lock) {
/* Cache does not exist and no lock is requested. */
return false;
}
/* Lazy initialization of the bvh_cache using the `mesh_eval_mutex`. */
BLI_mutex_lock(mesh_eval_mutex);
if (*bvh_cache_p == NULL) {
*bvh_cache_p = bvhcache_init();
}
BLI_mutex_unlock(mesh_eval_mutex);
}
BVHCache *bvh_cache = *bvh_cache_p;
if (bvh_cache->items[type].is_filled) {
*r_tree = bvh_cache->items[type].tree;
return true;
}
if (do_lock) {
BLI_mutex_lock(&bvh_cache->mutex);
bool in_cache = bvhcache_find(bvh_cache_p, type, r_tree, NULL, NULL);
if (in_cache) {
BLI_mutex_unlock(&bvh_cache->mutex);
return in_cache;
}
*r_locked = true;
}
return false;
}
static void bvhcache_unlock(BVHCache *bvh_cache, bool lock_started)
{
if (lock_started) {
BLI_mutex_unlock(&bvh_cache->mutex);
}
}
bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree)
{
if (bvh_cache == NULL) {
return false;
}
for (BVHCacheType i = 0; i < BVHTREE_MAX_ITEM; i++) {
if (bvh_cache->items[i].tree == tree) {
return true;
}
}
return false;
}
BVHCache *bvhcache_init(void)
{
BVHCache *cache = MEM_callocN(sizeof(BVHCache), __func__);
BLI_mutex_init(&cache->mutex);
return cache;
}
/**
* Inserts a BVHTree of the given type under the cache
* After that the caller no longer needs to worry when to free the BVHTree
* as that will be done when the cache is freed.
*
* A call to this assumes that there was no previous cached tree of the given type
* \warning The #BVHTree can be NULL.
*/
static void bvhcache_insert(BVHCache *bvh_cache, BVHTree *tree, BVHCacheType type)
{
BVHCacheItem *item = &bvh_cache->items[type];
BLI_assert(!item->is_filled);
item->tree = tree;
item->is_filled = true;
}
/**
* frees a bvhcache
*/
void bvhcache_free(BVHCache *bvh_cache)
{
for (BVHCacheType index = 0; index < BVHTREE_MAX_ITEM; index++) {
BVHCacheItem *item = &bvh_cache->items[index];
BLI_bvhtree_free(item->tree);
item->tree = NULL;
}
BLI_mutex_end(&bvh_cache->mutex);
MEM_freeN(bvh_cache);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Local Callbacks
* \{ */
@@ -518,29 +636,26 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache)
BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
if (bvh_cache) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
BLI_rw_mutex_unlock(&cache_rwlock);
if (bvh_cache_p) {
bool lock_started = false;
data->cached = bvhcache_find(
bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, mesh_eval_mutex);
if (data->cached == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
if (data->cached == false) {
tree = bvhtree_from_editmesh_verts_create_tree(
epsilon, tree_type, axis, em, verts_mask, verts_num_active);
tree = bvhtree_from_editmesh_verts_create_tree(
epsilon, tree_type, axis, em, verts_mask, verts_num_active);
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
data->cached = true;
}
BLI_rw_mutex_unlock(&cache_rwlock);
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
bvhcache_insert(*bvh_cache_p, tree, bvh_cache_type);
data->cached = true;
}
bvhcache_unlock(*bvh_cache_p, lock_started);
}
else {
tree = bvhtree_from_editmesh_verts_create_tree(
@@ -553,7 +668,7 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
data->em = em;
data->nearest_callback = NULL;
data->raycast_callback = editmesh_verts_spherecast;
data->cached = bvh_cache != NULL;
data->cached = bvh_cache_p != NULL;
}
return tree;
@@ -562,7 +677,8 @@ BVHTree *bvhtree_from_editmesh_verts_ex(BVHTreeFromEditMesh *data,
BVHTree *bvhtree_from_editmesh_verts(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
return bvhtree_from_editmesh_verts_ex(data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL);
return bvhtree_from_editmesh_verts_ex(
data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
}
/**
@@ -582,32 +698,26 @@ BVHTree *bvhtree_from_mesh_verts_ex(BVHTreeFromMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache)
BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
bool lock_started = false;
BVHTree *tree = NULL;
if (bvh_cache) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
BLI_rw_mutex_unlock(&cache_rwlock);
if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
if (in_cache) {
BLI_rw_mutex_unlock(&cache_rwlock);
}
}
if (bvh_cache_p) {
in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
tree = bvhtree_from_mesh_verts_create_tree(
epsilon, tree_type, axis, vert, verts_num, verts_mask, verts_num_active);
if (bvh_cache) {
if (bvh_cache_p) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
BVHCache *bvh_cache = *bvh_cache_p;
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
BLI_rw_mutex_unlock(&cache_rwlock);
bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -735,29 +845,26 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache)
BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
if (bvh_cache) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
BLI_rw_mutex_unlock(&cache_rwlock);
if (bvh_cache_p) {
bool lock_started = false;
data->cached = bvhcache_find(
bvh_cache_p, bvh_cache_type, &data->tree, &lock_started, mesh_eval_mutex);
BVHCache *bvh_cache = *bvh_cache_p;
if (data->cached == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
data->cached = bvhcache_find(*bvh_cache, bvh_cache_type, &data->tree);
if (data->cached == false) {
tree = bvhtree_from_editmesh_edges_create_tree(
epsilon, tree_type, axis, em, edges_mask, edges_num_active);
tree = bvhtree_from_editmesh_edges_create_tree(
epsilon, tree_type, axis, em, edges_mask, edges_num_active);
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
data->cached = true;
}
BLI_rw_mutex_unlock(&cache_rwlock);
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
data->cached = true;
}
bvhcache_unlock(bvh_cache, lock_started);
}
else {
tree = bvhtree_from_editmesh_edges_create_tree(
@@ -770,7 +877,7 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
data->em = em;
data->nearest_callback = NULL; /* TODO */
data->raycast_callback = NULL; /* TODO */
data->cached = bvh_cache != NULL;
data->cached = bvh_cache_p != NULL;
}
return tree;
@@ -779,7 +886,8 @@ BVHTree *bvhtree_from_editmesh_edges_ex(BVHTreeFromEditMesh *data,
BVHTree *bvhtree_from_editmesh_edges(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
return bvhtree_from_editmesh_edges_ex(data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL);
return bvhtree_from_editmesh_edges_ex(
data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
}
/**
@@ -802,32 +910,26 @@ BVHTree *bvhtree_from_mesh_edges_ex(BVHTreeFromMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache)
BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
bool lock_started = false;
BVHTree *tree = NULL;
if (bvh_cache) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
BLI_rw_mutex_unlock(&cache_rwlock);
if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
if (in_cache) {
BLI_rw_mutex_unlock(&cache_rwlock);
}
}
if (bvh_cache_p) {
in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
tree = bvhtree_from_mesh_edges_create_tree(
vert, edge, edges_num, edges_mask, edges_num_active, epsilon, tree_type, axis);
if (bvh_cache) {
if (bvh_cache_p) {
BVHCache *bvh_cache = *bvh_cache_p;
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
BLI_rw_mutex_unlock(&cache_rwlock);
bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -937,32 +1039,26 @@ BVHTree *bvhtree_from_mesh_faces_ex(BVHTreeFromMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache)
BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
bool lock_started = false;
BVHTree *tree = NULL;
if (bvh_cache) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
BLI_rw_mutex_unlock(&cache_rwlock);
if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
if (in_cache) {
BLI_rw_mutex_unlock(&cache_rwlock);
}
}
if (bvh_cache_p) {
in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
tree = bvhtree_from_mesh_faces_create_tree(
epsilon, tree_type, axis, vert, face, numFaces, faces_mask, faces_num_active);
if (bvh_cache) {
if (bvh_cache_p) {
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
BVHCache *bvh_cache = *bvh_cache_p;
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
BLI_rw_mutex_unlock(&cache_rwlock);
bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -1113,29 +1209,28 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache)
BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex)
{
/* BMESH specific check that we have tessfaces,
* we _could_ tessellate here but rather not - campbell */
BVHTree *tree = NULL;
if (bvh_cache) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
bool in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
BLI_rw_mutex_unlock(&cache_rwlock);
if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
if (in_cache == false) {
tree = bvhtree_from_editmesh_looptri_create_tree(
epsilon, tree_type, axis, em, looptri_mask, looptri_num_active);
if (bvh_cache_p) {
bool lock_started = false;
bool in_cache = bvhcache_find(
bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
BVHCache *bvh_cache = *bvh_cache_p;
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
}
BLI_rw_mutex_unlock(&cache_rwlock);
if (in_cache == false) {
tree = bvhtree_from_editmesh_looptri_create_tree(
epsilon, tree_type, axis, em, looptri_mask, looptri_num_active);
/* Save on cache for later use */
/* printf("BVHTree built and saved on cache\n"); */
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
}
bvhcache_unlock(bvh_cache, lock_started);
}
else {
tree = bvhtree_from_editmesh_looptri_create_tree(
@@ -1147,7 +1242,7 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
data->nearest_callback = editmesh_looptri_nearest_point;
data->raycast_callback = editmesh_looptri_spherecast;
data->em = em;
data->cached = bvh_cache != NULL;
data->cached = bvh_cache_p != NULL;
}
return tree;
}
@@ -1155,7 +1250,8 @@ BVHTree *bvhtree_from_editmesh_looptri_ex(BVHTreeFromEditMesh *data,
BVHTree *bvhtree_from_editmesh_looptri(
BVHTreeFromEditMesh *data, BMEditMesh *em, float epsilon, int tree_type, int axis)
{
return bvhtree_from_editmesh_looptri_ex(data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL);
return bvhtree_from_editmesh_looptri_ex(
data, em, NULL, -1, epsilon, tree_type, axis, 0, NULL, NULL);
}
/**
@@ -1177,21 +1273,14 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
int tree_type,
int axis,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache)
BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex)
{
bool in_cache = false;
bool lock_started = false;
BVHTree *tree = NULL;
if (bvh_cache) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
BLI_rw_mutex_unlock(&cache_rwlock);
if (in_cache == false) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE);
in_cache = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
if (in_cache) {
BLI_rw_mutex_unlock(&cache_rwlock);
}
}
if (bvh_cache_p) {
in_cache = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, &lock_started, mesh_eval_mutex);
}
if (in_cache == false) {
@@ -1206,9 +1295,10 @@ BVHTree *bvhtree_from_mesh_looptri_ex(BVHTreeFromMesh *data,
looptri_mask,
looptri_num_active);
if (bvh_cache) {
if (bvh_cache_p) {
BVHCache *bvh_cache = *bvh_cache_p;
bvhcache_insert(bvh_cache, tree, bvh_cache_type);
BLI_rw_mutex_unlock(&cache_rwlock);
bvhcache_unlock(bvh_cache, lock_started);
in_cache = true;
}
}
@@ -1315,11 +1405,10 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
const int tree_type)
{
BVHTree *tree = NULL;
BVHCache **bvh_cache = &mesh->runtime.bvh_cache;
BVHCache **bvh_cache_p = (BVHCache **)&mesh->runtime.bvh_cache;
ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex;
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
bool is_cached = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
BLI_rw_mutex_unlock(&cache_rwlock);
bool is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, NULL, NULL);
if (is_cached && tree == NULL) {
memset(data, 0, sizeof(*data));
@@ -1351,7 +1440,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
bvh_cache);
bvh_cache_p,
mesh_eval_mutex);
if (loose_verts_mask != NULL) {
MEM_freeN(loose_verts_mask);
@@ -1386,7 +1476,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
bvh_cache);
bvh_cache_p,
mesh_eval_mutex);
if (loose_edges_mask != NULL) {
MEM_freeN(loose_edges_mask);
@@ -1416,7 +1507,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
bvh_cache);
bvh_cache_p,
mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1452,7 +1544,8 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
tree_type,
6,
bvh_cache_type,
bvh_cache);
bvh_cache_p,
mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1464,6 +1557,7 @@ BVHTree *BKE_bvhtree_from_mesh_get(struct BVHTreeFromMesh *data,
case BVHTREE_FROM_EM_VERTS:
case BVHTREE_FROM_EM_EDGES:
case BVHTREE_FROM_EM_LOOPTRI:
case BVHTREE_MAX_ITEM:
BLI_assert(false);
break;
}
@@ -1493,17 +1587,16 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
struct BMEditMesh *em,
const int tree_type,
const BVHCacheType bvh_cache_type,
BVHCache **bvh_cache)
BVHCache **bvh_cache_p,
ThreadMutex *mesh_eval_mutex)
{
BVHTree *tree = NULL;
bool is_cached = false;
memset(data, 0, sizeof(*data));
if (bvh_cache) {
BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ);
is_cached = bvhcache_find(*bvh_cache, bvh_cache_type, &tree);
BLI_rw_mutex_unlock(&cache_rwlock);
if (bvh_cache_p) {
is_cached = bvhcache_find(bvh_cache_p, bvh_cache_type, &tree, NULL, NULL);
if (is_cached && tree == NULL) {
return tree;
@@ -1517,7 +1610,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_EM_VERTS:
if (is_cached == false) {
tree = bvhtree_from_editmesh_verts_ex(
data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
}
else {
data->nearest_callback = NULL;
@@ -1528,7 +1621,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_EM_EDGES:
if (is_cached == false) {
tree = bvhtree_from_editmesh_edges_ex(
data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1540,7 +1633,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_EM_LOOPTRI:
if (is_cached == false) {
tree = bvhtree_from_editmesh_looptri_ex(
data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache);
data, em, NULL, -1, 0.0f, tree_type, 6, bvh_cache_type, bvh_cache_p, mesh_eval_mutex);
}
else {
/* Setup BVHTreeFromMesh */
@@ -1555,6 +1648,7 @@ BVHTree *BKE_bvhtree_from_editmesh_get(BVHTreeFromEditMesh *data,
case BVHTREE_FROM_LOOPTRI_NO_HIDDEN:
case BVHTREE_FROM_LOOSEVERTS:
case BVHTREE_FROM_LOOSEEDGES:
case BVHTREE_MAX_ITEM:
BLI_assert(false);
break;
}
@@ -1615,82 +1709,3 @@ void free_bvhtree_from_mesh(struct BVHTreeFromMesh *data)
memset(data, 0, sizeof(*data));
}
/* -------------------------------------------------------------------- */
/** \name BVHCache
* \{ */
typedef struct BVHCacheItem {
BVHCacheType type;
BVHTree *tree;
} BVHCacheItem;
/**
* Queries a bvhcache for the cache bvhtree of the request type
*/
bool bvhcache_find(const BVHCache *cache, BVHCacheType type, BVHTree **r_tree)
{
while (cache) {
const BVHCacheItem *item = cache->link;
if (item->type == type) {
*r_tree = item->tree;
return true;
}
cache = cache->next;
}
return false;
}
bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree)
{
while (cache) {
const BVHCacheItem *item = cache->link;
if (item->tree == tree) {
return true;
}
cache = cache->next;
}
return false;
}
/**
* Inserts a BVHTree of the given type under the cache
* After that the caller no longer needs to worry when to free the BVHTree
* as that will be done when the cache is freed.
*
* A call to this assumes that there was no previous cached tree of the given type
* \warning The #BVHTree can be NULL.
*/
void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, BVHCacheType type)
{
BVHCacheItem *item = NULL;
BLI_assert(bvhcache_find(*cache_p, type, &(BVHTree *){0}) == false);
item = MEM_mallocN(sizeof(BVHCacheItem), "BVHCacheItem");
item->type = type;
item->tree = tree;
BLI_linklist_prepend(cache_p, item);
}
/**
* frees a bvhcache
*/
static void bvhcacheitem_free(void *_item)
{
BVHCacheItem *item = (BVHCacheItem *)_item;
BLI_bvhtree_free(item->tree);
MEM_freeN(item);
}
void bvhcache_free(BVHCache **cache_p)
{
BLI_linklist_free(*cache_p, (LinkNodeFreeFP)bvhcacheitem_free);
*cache_p = NULL;
}
/** \} */

View File

@@ -1555,6 +1555,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
2,
6,
0,
NULL,
NULL);
}
@@ -1598,6 +1599,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
2,
6,
0,
NULL,
NULL);
}

View File

@@ -53,6 +53,7 @@ void BKE_mesh_runtime_reset(Mesh *mesh)
memset(&mesh->runtime, 0, sizeof(mesh->runtime));
mesh->runtime.eval_mutex = MEM_mallocN(sizeof(ThreadMutex), "mesh runtime eval_mutex");
BLI_mutex_init(mesh->runtime.eval_mutex);
mesh->runtime.bvh_cache = NULL;
}
/* Clear all pointers which we don't want to be shared on copying the datablock.
@@ -227,7 +228,10 @@ bool BKE_mesh_runtime_clear_edit_data(Mesh *mesh)
void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
{
bvhcache_free(&mesh->runtime.bvh_cache);
if (mesh->runtime.bvh_cache) {
bvhcache_free(mesh->runtime.bvh_cache);
mesh->runtime.bvh_cache = NULL;
}
MEM_SAFE_FREE(mesh->runtime.looptris.array);
/* TODO(sergey): Does this really belong here? */
if (mesh->runtime.subdiv_ccg != NULL) {

View File

@@ -104,7 +104,7 @@ typedef struct SnapObjectData {
/* SNAP_EDIT_MESH */
BVHTreeFromEditMesh treedata_editmesh;
float min[3], max[3];
struct LinkNode **bvh_cache_p;
struct Mesh_Runtime *mesh_runtime;
};
};
} SnapObjectData;
@@ -255,17 +255,17 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, Object
return sod;
}
static struct LinkNode **snap_object_data_editmesh_bvh_cache_get(Object *ob)
static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob)
{
BMEditMesh *em = BKE_editmesh_from_object(ob);
if (em->mesh_eval_final) {
return &em->mesh_eval_final->runtime.bvh_cache;
return &em->mesh_eval_final->runtime;
}
if (em->mesh_eval_cage) {
return &em->mesh_eval_cage->runtime.bvh_cache;
return &em->mesh_eval_cage->runtime;
}
return &((Mesh *)ob->data)->runtime.bvh_cache;
return &((Mesh *)ob->data)->runtime;
}
static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
@@ -302,23 +302,23 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
clear_cache = true;
init = true;
}
else if (sod->bvh_cache_p) {
if (sod->bvh_cache_p != snap_object_data_editmesh_bvh_cache_get(ob)) {
else if (sod->mesh_runtime) {
if (sod->mesh_runtime != snap_object_data_editmesh_runtime_get(ob)) {
clear_cache = true;
init = true;
}
else if (sod->treedata_editmesh.tree && sod->treedata_editmesh.cached &&
!bvhcache_has_tree(*sod->bvh_cache_p, sod->treedata_editmesh.tree)) {
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->treedata_editmesh.tree)) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
clear = true;
}
else if (sod->bvhtree[0] && sod->cached[0] &&
!bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[0])) {
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[0])) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
clear = true;
}
else if (sod->bvhtree[1] && sod->cached[1] &&
!bvhcache_has_tree(*sod->bvh_cache_p, sod->bvhtree[1])) {
!bvhcache_has_tree(sod->mesh_runtime->bvh_cache, sod->bvhtree[1])) {
/* The tree is owned by the EditMesh and may have been freed since we last used! */
clear = true;
}
@@ -357,7 +357,7 @@ static SnapObjectData *snap_object_data_editmesh_get(SnapObjectContext *sctx,
bm_mesh_minmax(em->bm, sod->min, sod->max);
}
sod->bvh_cache_p = snap_object_data_editmesh_bvh_cache_get(ob);
sod->mesh_runtime = snap_object_data_editmesh_runtime_get(ob);
}
return sod;
@@ -846,14 +846,19 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_looptri_ex(
treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL);
treedata, em, elem_mask, looptri_num_active, 0.0f, 4, 6, 0, NULL, NULL);
MEM_freeN(elem_mask);
}
else {
/* Only cache if bvhtree is created without a mask.
* This helps keep a standardized bvhtree in cache. */
BKE_bvhtree_from_editmesh_get(treedata, em, 4, BVHTREE_FROM_EM_LOOPTRI, sod->bvh_cache_p);
BKE_bvhtree_from_editmesh_get(treedata,
em,
4,
BVHTREE_FROM_EM_LOOPTRI,
&sod->mesh_runtime->bvh_cache,
sod->mesh_runtime->eval_mutex);
}
if (treedata->tree == NULL) {
@@ -2500,11 +2505,16 @@ static short snapEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_verts_ex(
&treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL);
&treedata, em, verts_mask, verts_num_active, 0.0f, 2, 6, 0, NULL, NULL);
MEM_freeN(verts_mask);
}
else {
BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_VERTS, sod->bvh_cache_p);
BKE_bvhtree_from_editmesh_get(&treedata,
em,
2,
BVHTREE_FROM_EM_VERTS,
&sod->mesh_runtime->bvh_cache,
(ThreadMutex *)sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[0] = treedata.tree;
sod->cached[0] = treedata.cached;
@@ -2527,11 +2537,16 @@ static short snapEditMesh(SnapObjectContext *sctx,
sctx->callbacks.edit_mesh.user_data);
bvhtree_from_editmesh_edges_ex(
&treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL);
&treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6, 0, NULL, NULL);
MEM_freeN(edges_mask);
}
else {
BKE_bvhtree_from_editmesh_get(&treedata, em, 2, BVHTREE_FROM_EM_EDGES, sod->bvh_cache_p);
BKE_bvhtree_from_editmesh_get(&treedata,
em,
2,
BVHTREE_FROM_EM_EDGES,
&sod->mesh_runtime->bvh_cache,
sod->mesh_runtime->eval_mutex);
}
sod->bvhtree[1] = treedata.tree;
sod->cached[1] = treedata.cached;

View File

@@ -33,6 +33,7 @@ extern "C" {
#endif
struct AnimData;
struct BVHCache;
struct Ipo;
struct Key;
struct LinkNode;
@@ -99,8 +100,8 @@ typedef struct Mesh_Runtime {
struct MLoopTri_Store looptris;
/** 'BVHCache', for 'BKE_bvhutil.c' */
struct LinkNode *bvh_cache;
/** `BVHCache` defined in 'BKE_bvhutil.c' */
struct BVHCache *bvh_cache;
/** Non-manifold boundary data for Shrinkwrap Target Project. */
struct ShrinkwrapBoundaryData *shrinkwrap_data;

View File

@@ -1677,8 +1677,18 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContex
/* Get overlap map. */
/* TODO: For a better performanse use KD-Tree. */
struct BVHTreeFromMesh treedata;
BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(
&treedata, mvert, totvert, false, v_mask, v_mask_act, wmd->merge_dist / 2, 2, 6, 0, NULL);
BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata,
mvert,
totvert,
false,
v_mask,
v_mask_act,
wmd->merge_dist / 2,
2,
6,
0,
NULL,
NULL);
if (v_mask) {
MEM_freeN(v_mask);