sculpt-dev: started work on new customdata
backend for BMesh for profiling purposes * Purpose is to test the performance of block vs page vs array CustomData allocation. * Code is as simple as possible. * Patches existing BMesh CustomData API. * Not intended for master.
This commit is contained in:
parent
9d09011f91
commit
5f631ca7c8
|
@ -793,6 +793,16 @@ void CustomData_bmesh_asan_poison(const CustomData *data, void *block);
|
|||
void CustomData_bmesh_asan_unpoison(const CustomData *data, void *block);
|
||||
int CustomData_get_named_offset(const CustomData *data, int type, const char *name);
|
||||
|
||||
void CustomData_setDefaultData(CustomDataType type, void *block, int totelem);
|
||||
size_t CustomData_getTypeSize(CustomDataType type);
|
||||
void CustomData_freeData(CustomDataType type, void *block, int totelem);
|
||||
void CustomData_interpData(CustomDataType type,
|
||||
void *block,
|
||||
int tot,
|
||||
const void **srcs,
|
||||
const float *ws,
|
||||
const float *sub_ws);
|
||||
|
||||
#ifndef NDEBUG
|
||||
struct DynStr;
|
||||
/** Use to inspect mesh data when debugging. */
|
||||
|
|
|
@ -353,9 +353,7 @@ void BKE_pbvh_update_sculpt_verts(struct BMesh *bm,
|
|||
|
||||
/** update original data, only data whose r_** parameters are passed in will be updated*/
|
||||
void BKE_pbvh_bmesh_update_origvert(
|
||||
PBVH *pbvh, struct BMVert *v, float **r_co, float **r_no, float **r_color, bool log_undo);
|
||||
void BKE_pbvh_update_origcolor_bmesh(PBVH *pbvh, PBVHNode *node);
|
||||
void BKE_pbvh_update_origco_bmesh(PBVH *pbvh, PBVHNode *node);
|
||||
PBVH *pbvh, struct BMVert *v, float **r_co, float **r_no, float **r_color);
|
||||
|
||||
/**
|
||||
checks if original data needs to be updated for v, and if so updates it. Stroke_id
|
||||
|
|
|
@ -102,7 +102,7 @@ struct CurveMappingCache *brush_curve_cache = NULL;
|
|||
extern BrushChannelType brush_builtin_channels[];
|
||||
extern int brush_builtin_channel_len;
|
||||
|
||||
static bool brush_mapping_inherits(BrushChannel *ch, BrushMapping *mp)
|
||||
static bool brush_mapping_inherits(const BrushChannel *ch, const BrushMapping *mp)
|
||||
{
|
||||
switch (mp->inherit_mode) {
|
||||
case BRUSH_MAPPING_INHERIT_NEVER:
|
||||
|
|
|
@ -3939,6 +3939,7 @@ void CustomData_bmesh_do_versions_update_active_layers(CustomData *fdata, Custom
|
|||
}
|
||||
}
|
||||
|
||||
#ifndef USE_BMESH_PAGE_CUSTOMDATA
|
||||
void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
|
||||
{
|
||||
CustomData_bmesh_init_pool_ex(data, totelem, htype, __func__);
|
||||
|
@ -3978,6 +3979,7 @@ void CustomData_bmesh_init_pool_ex(CustomData *data,
|
|||
data->pool = BLI_mempool_create_ex(data->totsize, totelem, chunksize, BLI_MEMPOOL_NOP, memtag);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CustomData_bmesh_merge(const CustomData *source,
|
||||
CustomData *dest,
|
||||
|
@ -4122,6 +4124,7 @@ void CustomData_bmesh_free_block_data(CustomData *data, void *block)
|
|||
CustomData_bmesh_asan_poison(data, block);
|
||||
}
|
||||
|
||||
#ifndef USE_BMESH_PAGE_CUSTOMDATA
|
||||
static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
|
||||
{
|
||||
if (*block) {
|
||||
|
@ -4149,6 +4152,7 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
|
|||
*block = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
|
||||
void *block,
|
||||
|
@ -4176,6 +4180,7 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data,
|
|||
CustomData_bmesh_asan_poison(data, block);
|
||||
}
|
||||
|
||||
#ifndef USE_BMESH_PAGE_CUSTOMDATA
|
||||
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n)
|
||||
{
|
||||
if (ELEM(data->layers[n].type, CD_TOOLFLAGS, CD_MESH_ID)) {
|
||||
|
@ -4204,6 +4209,7 @@ void CustomData_bmesh_set_default(CustomData *data, void **block)
|
|||
CustomData_bmesh_set_default_n(data, block, i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void CustomData_bmesh_swap_data_simple(CustomData *data, void **block1, void **block2)
|
||||
{
|
||||
|
@ -4663,6 +4669,7 @@ void CustomData_bmesh_interp_n(CustomData *data,
|
|||
typeInfo->interp(src_blocks_ofs, weights, sub_weights, count, dst_block_ofs);
|
||||
}
|
||||
|
||||
#ifndef USE_BMESH_PAGE_CUSTOMDATA
|
||||
void CustomData_bmesh_interp(CustomData *data,
|
||||
const void **src_blocks,
|
||||
const float *weights,
|
||||
|
@ -4845,6 +4852,8 @@ void CustomData_from_bmesh_block(const CustomData *source,
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void CustomData_file_write_info(int type, const char **r_struct_name, int *r_struct_num)
|
||||
{
|
||||
|
@ -5857,6 +5866,64 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count)
|
|||
CustomData_regen_active_refs(data); // check for corrupted active layer refs
|
||||
}
|
||||
|
||||
size_t CustomData_getTypeSize(CustomDataType type)
|
||||
{
|
||||
const LayerTypeInfo *info = layerType_getInfo(type);
|
||||
|
||||
return info ? info->size : 0ULL;
|
||||
}
|
||||
|
||||
void CustomData_setDefaultData(CustomDataType type, void *block, int totelem)
|
||||
{
|
||||
const LayerTypeInfo *info = layerType_getInfo(type);
|
||||
|
||||
if (info->set_default) {
|
||||
info->set_default(block, totelem);
|
||||
}
|
||||
else {
|
||||
memset(block, 0, info->size * totelem);
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_freeData(CustomDataType type, void *block, int totelem)
|
||||
{
|
||||
const LayerTypeInfo *info = layerType_getInfo(type);
|
||||
|
||||
if (info->free) {
|
||||
info->free(block, totelem, info->size);
|
||||
}
|
||||
}
|
||||
|
||||
#include "BLI_alloca.h"
|
||||
|
||||
void CustomData_interpData(CustomDataType type,
|
||||
void *block,
|
||||
int tot,
|
||||
const void **srcs,
|
||||
const float *ws,
|
||||
const float *sub_ws)
|
||||
{
|
||||
const LayerTypeInfo *info = layerType_getInfo(type);
|
||||
|
||||
if (!info->interp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ws) {
|
||||
float *ws2 = static_cast<float *>(BLI_array_alloca(ws2, tot));
|
||||
float w = 1.0f / (float)tot;
|
||||
|
||||
for (int i = 0; i < tot; i++) {
|
||||
ws2[i] = w;
|
||||
}
|
||||
|
||||
info->interp(srcs, ws2, sub_ws, 1, block);
|
||||
}
|
||||
else {
|
||||
info->interp(srcs, ws, sub_ws, 1, block);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
void CustomData_debug_info_from_layers(const CustomData *data, const char *indent, DynStr *dynstr)
|
||||
|
|
|
@ -1796,44 +1796,6 @@ static int pbvh_flush_bb(PBVH *pbvh, PBVHNode *node, int flag)
|
|||
return update;
|
||||
}
|
||||
|
||||
void BKE_pbvh_update_origcolor_bmesh(PBVH *pbvh, PBVHNode *node)
|
||||
{
|
||||
PBVHVertexIter vd;
|
||||
|
||||
if (!pbvh->bm || pbvh->vcol_type == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pbvh->vcol_type == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
MSculptVert *mv = BKE_PBVH_SCULPTVERT(pbvh->cd_sculpt_vert, vd.bm_vert);
|
||||
|
||||
BKE_pbvh_bmesh_get_vcol(
|
||||
vd.bm_vert, mv->origcolor, pbvh->vcol_type, pbvh->vcol_domain, pbvh->cd_vcol_offset);
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
||||
void BKE_pbvh_update_origco_bmesh(PBVH *pbvh, PBVHNode *node)
|
||||
{
|
||||
PBVHVertexIter vd;
|
||||
|
||||
if (!pbvh->bm || pbvh->cd_sculpt_vert < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
BKE_pbvh_vertex_iter_begin (pbvh, node, vd, PBVH_ITER_UNIQUE) {
|
||||
MSculptVert *mv = BKE_PBVH_SCULPTVERT(pbvh->cd_sculpt_vert, vd.bm_vert);
|
||||
|
||||
copy_v3_v3(mv->origco, vd.bm_vert->co);
|
||||
copy_v3_v3(mv->origno, vd.bm_vert->no);
|
||||
}
|
||||
BKE_pbvh_vertex_iter_end;
|
||||
}
|
||||
|
||||
void BKE_pbvh_update_bounds(PBVH *pbvh, int flag)
|
||||
{
|
||||
if (!pbvh->nodes) {
|
||||
|
|
|
@ -943,16 +943,10 @@ void BKE_pbvh_bmesh_get_vcol(
|
|||
}
|
||||
|
||||
void BKE_pbvh_bmesh_update_origvert(
|
||||
PBVH *pbvh, BMVert *v, float **r_co, float **r_no, float **r_color, bool log_undo)
|
||||
PBVH *pbvh, BMVert *v, float **r_co, float **r_no, float **r_color)
|
||||
{
|
||||
MSculptVert *mv = BKE_PBVH_SCULPTVERT(pbvh->cd_sculpt_vert, v);
|
||||
|
||||
if (log_undo) {
|
||||
bm_logstack_push();
|
||||
BM_log_vert_before_modified(pbvh->bm_log, v, pbvh->cd_vert_mask_offset, r_color != NULL);
|
||||
bm_logstack_pop();
|
||||
}
|
||||
|
||||
if (pbvh->cd_vert_mask_offset) {
|
||||
mv->origmask = (short)(BM_ELEM_CD_GET_FLOAT(v, pbvh->cd_vert_mask_offset) * 65535.0f);
|
||||
}
|
||||
|
@ -995,7 +989,7 @@ bool BKE_pbvh_bmesh_check_origdata(PBVH *pbvh, BMVert *v, int stroke_id)
|
|||
if (mv->stroke_id != stroke_id) {
|
||||
float *dummy;
|
||||
|
||||
BKE_pbvh_bmesh_update_origvert(pbvh, v, &dummy, &dummy, &dummy, false);
|
||||
BKE_pbvh_bmesh_update_origvert(pbvh, v, &dummy, &dummy, &dummy);
|
||||
mv->stroke_id = stroke_id;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -82,6 +82,8 @@ set(SRC
|
|||
intern/bmesh_construct.h
|
||||
intern/bmesh_core.c
|
||||
intern/bmesh_core.h
|
||||
intern/bmesh_data_attr.h
|
||||
intern/bmesh_data_attr.cc
|
||||
intern/bmesh_delete.c
|
||||
intern/bmesh_delete.h
|
||||
intern/bmesh_edgeloop.c
|
||||
|
|
|
@ -401,6 +401,10 @@ typedef struct BMesh {
|
|||
int map_size;
|
||||
int cd_id_off[15];
|
||||
} idmap;
|
||||
|
||||
#ifdef USE_BMESH_PAGE_CUSTOMDATA
|
||||
struct BMeshAttrList *attr_list;
|
||||
#endif
|
||||
} BMesh;
|
||||
|
||||
enum {
|
||||
|
|
|
@ -42,6 +42,10 @@
|
|||
|
||||
#include "range_tree.h"
|
||||
|
||||
#ifdef USE_BMESH_PAGE_CUSTOMDATA
|
||||
#include "intern/bmesh_data_attr.h"
|
||||
#endif
|
||||
|
||||
#define SELECT 1
|
||||
|
||||
#ifdef WITH_BM_ID_FREELIST
|
||||
|
|
|
@ -154,6 +154,7 @@ BMVert *BM_vert_create(BMesh *bm,
|
|||
}
|
||||
else {
|
||||
CustomData_bmesh_set_default(&bm->vdata, &v->head.data);
|
||||
|
||||
zero_v3(v->no);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,391 @@
|
|||
#include "DNA_customdata_types.h"
|
||||
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_mempool.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
#include "bmesh_data_attr.h"
|
||||
|
||||
#ifdef USE_BMESH_PAGE_CUSTOMDATA
|
||||
|
||||
using blender::IndexRange;
|
||||
using blender::bmesh::BMAttrDomain;
|
||||
using blender::bmesh::PageArray;
|
||||
using blender::bmesh::PageElemRef;
|
||||
|
||||
namespace blender {
|
||||
namespace bmesh {
|
||||
|
||||
BMeshAttrList *BMAttr_new()
|
||||
{
|
||||
BMeshAttrList *list = static_cast<BMeshAttrList *>(
|
||||
MEM_callocN(sizeof(BMeshAttrList), "BMeshAttrList"));
|
||||
|
||||
for (int i : IndexRange(ATTR_DOMAIN_NUM)) {
|
||||
list->domains[i] = new BMAttrDomain(static_cast<AttributeDomain>(i));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
void BMAttr_reset(BMeshAttrList *list)
|
||||
{
|
||||
if (list->arrays) {
|
||||
MEM_freeN(static_cast<void *>(list->arrays));
|
||||
}
|
||||
|
||||
list->arrays = nullptr;
|
||||
list->totarray = 0;
|
||||
|
||||
for (int i : IndexRange(ATTR_DOMAIN_NUM)) {
|
||||
delete list->domains[i];
|
||||
}
|
||||
|
||||
for (int i : IndexRange(ATTR_DOMAIN_NUM)) {
|
||||
list->domains[i] = new BMAttrDomain(static_cast<AttributeDomain>(i));
|
||||
}
|
||||
}
|
||||
|
||||
void BMAttr_free(BMeshAttrList *list)
|
||||
{
|
||||
for (int i : IndexRange(ATTR_DOMAIN_NUM)) {
|
||||
delete list->domains[i];
|
||||
}
|
||||
|
||||
if (list->arrays) {
|
||||
MEM_freeN(static_cast<void *>(list->arrays));
|
||||
}
|
||||
|
||||
MEM_freeN(static_cast<void *>(list));
|
||||
}
|
||||
|
||||
static void bm_update_page_pointers(BMeshAttrList *list)
|
||||
{
|
||||
for (int i : IndexRange(list->totarray)) {
|
||||
PageArray<BM_PAGE_SHIFT> *page_array = reinterpret_cast<PageArray<BM_PAGE_SHIFT> *>(
|
||||
list->arrays[i]);
|
||||
list->arrays[i]->pages = page_array->pages.data();
|
||||
}
|
||||
}
|
||||
|
||||
int BMAttr_allocElem(BMeshAttrList *list, AttributeDomain domain)
|
||||
{
|
||||
bool hadNewPage;
|
||||
|
||||
int ret = static_cast<int>(list->domains[domain]->alloc(hadNewPage));
|
||||
|
||||
if (hadNewPage) {
|
||||
bm_update_page_pointers(list);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void BMAttr_freeElem(BMeshAttrList *list, AttributeDomain domain, int elem)
|
||||
{
|
||||
bool pageRemoved;
|
||||
|
||||
list->domains[domain]->free(static_cast<PageElemRef>(elem), pageRemoved);
|
||||
|
||||
if (pageRemoved) {
|
||||
bm_update_page_pointers(list);
|
||||
}
|
||||
}
|
||||
|
||||
int BMAttr_addLayer(BMeshAttrList *list, AttributeDomain domain, CustomDataType type)
|
||||
{
|
||||
list->totarray++;
|
||||
|
||||
if (!list->arrays) {
|
||||
list->arrays = static_cast<BMeshPageArray **>(
|
||||
MEM_malloc_arrayN(list->totarray, sizeof(void *), __func__));
|
||||
}
|
||||
else {
|
||||
list->arrays = static_cast<BMeshPageArray **>(
|
||||
MEM_reallocN(static_cast<void *>(list->arrays), list->totarray * sizeof(void *)));
|
||||
}
|
||||
|
||||
BMeshPageArray *bmarray = list->arrays[list->totarray - 1];
|
||||
PageArray<BM_PAGE_SHIFT> *page_array = list->domains[domain]->addLayer(type);
|
||||
|
||||
bmarray->cppClass = reinterpret_cast<void *>(page_array);
|
||||
bmarray->pages = page_array->pages.data();
|
||||
|
||||
for (PageElemRef i : IndexRange(list->domains[domain]->totalloc)) {
|
||||
page_array->setDefault(i);
|
||||
}
|
||||
|
||||
return list->totarray - 1;
|
||||
}
|
||||
|
||||
void BMAttr_init(BMesh *bm)
|
||||
{
|
||||
#ifdef USE_BMESH_PAGE_CUSTOMDATA
|
||||
CustomData *domains[ATTR_DOMAIN_NUM] = {nullptr};
|
||||
|
||||
domains[ATTR_DOMAIN_POINT] = &bm->vdata;
|
||||
domains[ATTR_DOMAIN_EDGE] = &bm->edata;
|
||||
domains[ATTR_DOMAIN_CORNER] = &bm->ldata;
|
||||
domains[ATTR_DOMAIN_FACE] = &bm->pdata;
|
||||
|
||||
if (!bm->attr_list) {
|
||||
bm->attr_list = BMAttr_new();
|
||||
}
|
||||
|
||||
BMAttr_fromCData(bm->attr_list, domains);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BMAttr_fromCData(BMeshAttrList *list, CustomData *domains[ATTR_DOMAIN_NUM])
|
||||
{
|
||||
AttributeDomain ds[4] = {
|
||||
ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_CORNER, ATTR_DOMAIN_FACE};
|
||||
|
||||
for (int i : IndexRange(4)) {
|
||||
CustomData *cdata = domains[ds[i]];
|
||||
|
||||
cdata->bm_attrs = static_cast<void *>(list);
|
||||
cdata->_pad[0] = static_cast<void *>(domains[ds[i]]);
|
||||
|
||||
for (int j : IndexRange(cdata->totlayer)) {
|
||||
CustomDataLayer *layer = cdata->layers + j;
|
||||
|
||||
layer->offset = BMAttr_addLayer(list, ds[i], static_cast<CustomDataType>(layer->type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static AttributeDomain domain_map[] = {
|
||||
ATTR_DOMAIN_AUTO, // 0
|
||||
ATTR_DOMAIN_POINT, // 1
|
||||
ATTR_DOMAIN_EDGE, // 2
|
||||
ATTR_DOMAIN_AUTO, // 3
|
||||
ATTR_DOMAIN_CORNER, // 4
|
||||
ATTR_DOMAIN_AUTO, // 5
|
||||
ATTR_DOMAIN_AUTO, // 6
|
||||
ATTR_DOMAIN_AUTO, // 7
|
||||
ATTR_DOMAIN_FACE, // 8
|
||||
};
|
||||
|
||||
void bmesh_update_attr_refs(BMesh *bm)
|
||||
{
|
||||
CustomData *cdata = &bm->vdata;
|
||||
|
||||
for (int i = 0; i < 4; i++, cdata++) {
|
||||
cdata->_pad[0] = static_cast<void *>(domain_map[htype]);
|
||||
cdata->bm_attrs = bm->attr_list;
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype)
|
||||
{
|
||||
CustomData_bmesh_init_pool_ex(data, totelem, htype, __func__);
|
||||
}
|
||||
|
||||
void CustomData_bmesh_init_pool_ex(CustomData *data,
|
||||
int totelem,
|
||||
const char htype,
|
||||
const char *memtag)
|
||||
{
|
||||
// store domain in _pad[0] for the purposes of this test
|
||||
data->_pad[0] = static_cast<void *>(domain_map[htype]);
|
||||
|
||||
if (data->pool) {
|
||||
BLI_mempool_destroy(data->pool);
|
||||
}
|
||||
|
||||
data->pool = BLI_mempool_create(sizeof(BMeshPageRef), 0, 1024, 0);
|
||||
}
|
||||
|
||||
static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
|
||||
{
|
||||
BMeshAttrList *list = static_cast<BMeshAttrList *>(data->bm_attrs);
|
||||
BMeshPageRef *ref = static_cast<BMeshPageRef *>(BLI_mempool_calloc(data->pool));
|
||||
|
||||
AttributeDomain domain = static_cast<AttributeDomain>(POINTER_AS_UINT(data->_pad[0]));
|
||||
|
||||
ref->attrs = list;
|
||||
ref->idx = BMAttr_allocElem(list, domain);
|
||||
ref->domain = domain;
|
||||
|
||||
*block = static_cast<void *>(ref);
|
||||
}
|
||||
|
||||
static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n)
|
||||
{
|
||||
if (ELEM(data->layers[n].type, CD_TOOLFLAGS, CD_MESH_ID)) {
|
||||
/* do not do toolflags or mesh ids */
|
||||
return;
|
||||
}
|
||||
|
||||
BMeshAttrList *list = static_cast<BMeshAttrList *>(data->bm_attrs);
|
||||
BMeshPageRef *ref = static_cast<BMeshPageRef *>(*block);
|
||||
|
||||
list->domains[ref->domain]->arrays[n]->setDefault(static_cast<PageElemRef>(ref->idx));
|
||||
}
|
||||
|
||||
static void CustomData_bmesh_set_default(CustomData *data, void **block)
|
||||
{
|
||||
if (!*block) {
|
||||
CustomData_bmesh_alloc_block(data, block, n);
|
||||
}
|
||||
|
||||
BMeshAttrList *list = static_cast<BMeshAttrList *>(data->bm_attrs);
|
||||
BMeshPageRef *ref = static_cast<BMeshPageRef *>(*block);
|
||||
AttributeDomain domain = static_cast<AttributeDomain>(POINTER_AS_UINT(data->_pad[0]));
|
||||
|
||||
list->domains[domain].setDefault(static_cast<PageElemRef>(ref->idx));
|
||||
}
|
||||
|
||||
static void alloc_block(CustomData *data,
|
||||
BMeshAttrList *list,
|
||||
AttributeDomain domain,
|
||||
void **block)
|
||||
{
|
||||
CustomData_bmesh_alloc_block(data, block);
|
||||
BMeshPageRef *ref = static_cast<BMeshPageRef *> * block;
|
||||
|
||||
ref->attrs = list;
|
||||
ref->idx = BMAttr_allocElem(list, domain);
|
||||
}
|
||||
|
||||
void CustomData_bmesh_interp(CustomData *data,
|
||||
const void **src_blocks,
|
||||
const float *weights,
|
||||
const float *sub_weights,
|
||||
int count,
|
||||
void *dst_block)
|
||||
{
|
||||
BMeshPageRef *ref = static_cast<BMeshPageRef *> dst_block;
|
||||
AttributeDomain domain = static_cast<AttributeDomain>(ref->domain);
|
||||
|
||||
PageElemRef *elems = BLI_array_alloca(elems, count);
|
||||
|
||||
for (int i : IndexRange(count)) {
|
||||
BMeshPageRef *ref2 = static_cast<BMeshPageRef *> src_blocks[i];
|
||||
elems[i] = ref2->idx;
|
||||
}
|
||||
|
||||
ref->attrs->domains[domain]->interp(
|
||||
static_cast<PageElemRef>(ref->idx), count, elems, weights, sub_weights);
|
||||
}
|
||||
|
||||
void CustomData_to_bmesh_block(const CustomData *source,
|
||||
CustomData *_dest,
|
||||
int src_index,
|
||||
void **dest_block,
|
||||
bool use_default_init)
|
||||
{
|
||||
if (*dest_block == nullptr) {
|
||||
CustomData_bmesh_alloc_block(dest, dest_block);
|
||||
}
|
||||
|
||||
BMeshPageRef *block = static_cast<BMeshPageRef *> dest_block;
|
||||
BMeshAttrList *list = static_cast<BMeshAttrList *> dest->bm_attrs;
|
||||
auto *dest = list->domains[ref->domain];
|
||||
|
||||
/* copies a layer at a time */
|
||||
int dest_i = 0;
|
||||
for (int src_i = 0; src_i < source->totlayer; src_i++) {
|
||||
auto *array = list->domains[ref->domain]->arrays[dest_i];
|
||||
|
||||
/* find the first dest layer with type >= the source type
|
||||
* (this should work because layers are ordered by type)
|
||||
*/
|
||||
while (dest_i < dest->arrays.size() &&
|
||||
dest->arrays[dest_i].type < source->layers[src_i].type) {
|
||||
if (use_default_init) {
|
||||
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
|
||||
}
|
||||
dest_i++;
|
||||
}
|
||||
|
||||
/* if there are no more dest layers, we're done */
|
||||
if (dest_i >= dest->arrays.size()) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* if we found a matching layer, copy the data */
|
||||
if (dest->arrays[dest_i].type == source->layers[src_i].type) {
|
||||
const void *src_data = source->layers[src_i].data;
|
||||
void *dest_data = dest->getElemPtr(static_cast<PageElemRef>(ref->idx));
|
||||
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->arrays[dest_i].type);
|
||||
const size_t src_offset = (size_t)src_index * typeInfo->size;
|
||||
|
||||
if (typeInfo->copy) {
|
||||
typeInfo->copy(POINTER_OFFSET(src_data, src_offset), dest_data, 1);
|
||||
}
|
||||
else {
|
||||
memcpy(dest_data, POINTER_OFFSET(src_data, src_offset), typeInfo->size);
|
||||
}
|
||||
|
||||
/* if there are multiple source & dest layers of the same type,
|
||||
* we don't want to copy all source layers to the same dest, so
|
||||
* increment dest_i
|
||||
*/
|
||||
dest_i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_default_init) {
|
||||
while (dest_i < dest->arrays.size()) {
|
||||
CustomData_bmesh_set_default_n(dest, dest_block, dest_i);
|
||||
dest_i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CustomData_from_bmesh_block(const CustomData *source,
|
||||
CustomData *dest,
|
||||
void *src_block,
|
||||
int dest_index)
|
||||
{
|
||||
/* copies a layer at a time */
|
||||
int dest_i = 0;
|
||||
for (int src_i = 0; src_i < source->totlayer; src_i++) {
|
||||
if (source->layers[src_i].flag & CD_FLAG_NOCOPY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* find the first dest layer with type >= the source type
|
||||
* (this should work because layers are ordered by type)
|
||||
*/
|
||||
while (dest_i < dest->totlayer && dest->layers[dest_i].type < source->layers[src_i].type) {
|
||||
dest_i++;
|
||||
}
|
||||
|
||||
/* if there are no more dest layers, we're done */
|
||||
if (dest_i >= dest->totlayer) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* if we found a matching layer, copy the data */
|
||||
if (dest->layers[dest_i].type == source->layers[src_i].type) {
|
||||
const LayerTypeInfo *typeInfo = layerType_getInfo(dest->layers[dest_i].type);
|
||||
int offset = source->layers[src_i].offset;
|
||||
const void *src_data = POINTER_OFFSET(src_block, offset);
|
||||
void *dst_data = POINTER_OFFSET(dest->layers[dest_i].data,
|
||||
(size_t)dest_index * typeInfo->size);
|
||||
|
||||
if (typeInfo->copy) {
|
||||
typeInfo->copy(src_data, dst_data, 1);
|
||||
}
|
||||
else {
|
||||
memcpy(dst_data, src_data, typeInfo->size);
|
||||
}
|
||||
|
||||
/* if there are multiple source & dest layers of the same type,
|
||||
* we don't want to copy all source layers to the same dest, so
|
||||
* increment dest_i
|
||||
*/
|
||||
dest_i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace bmesh
|
||||
} // namespace blender
|
||||
#endif
|
|
@ -0,0 +1,274 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
|
||||
This is a minimal page-based CustomData backend for bmesh.
|
||||
It's purpose is to test whether a page-based system would
|
||||
be faster then the current block-based one.
|
||||
|
||||
The idea is to plug into the existing API in as minimal
|
||||
a way as possible.
|
||||
|
||||
*/
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
#include "bmesh.h"
|
||||
|
||||
#ifdef USE_BMESH_PAGE_CUSTOMDATA
|
||||
|
||||
#define BM_PAGE_SHIFT 10
|
||||
#define BM_PAGE_SIZE (1 << BM_PAGE_SHIFT)
|
||||
#define BM_PAGE_MASK (BM_PAGE_SIZE - 1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
# include "BLI_alloca.h"
|
||||
# include "BLI_array.hh"
|
||||
# include <vector>
|
||||
|
||||
namespace blender {
|
||||
namespace bmesh {
|
||||
|
||||
using PageElemRef = int;
|
||||
|
||||
template<int PageSizeShift = BM_PAGE_SHIFT> struct PageArray {
|
||||
std::vector<void *> pages;
|
||||
size_t elemSize;
|
||||
CustomDataType type;
|
||||
|
||||
PageArray(const PageArray &b)
|
||||
{
|
||||
elemSize = b.elemSize;
|
||||
pages = b.pages;
|
||||
}
|
||||
|
||||
PageArray(const PageArray &&b)
|
||||
{
|
||||
elemSize = b.elemSize;
|
||||
pages = std::move(b.pages);
|
||||
}
|
||||
|
||||
PageArray(CustomDataType t, size_t size = 0) : type(t)
|
||||
{
|
||||
elemSize = CustomData_getTypeSize(type);
|
||||
|
||||
reserve(size);
|
||||
}
|
||||
|
||||
~PageArray()
|
||||
{
|
||||
}
|
||||
|
||||
void *getElemPtr(PageElemRef elem)
|
||||
{
|
||||
size_t page = elem >> PageSizeShift;
|
||||
size_t elem_i = elem & ((1 << PageSizeShift) - 1);
|
||||
|
||||
char *ptr = static_cast<char *>(pages[page]);
|
||||
ptr += elem_i * elemSize;
|
||||
|
||||
return static_cast<void *>(ptr);
|
||||
}
|
||||
|
||||
void interp(PageElemRef elem, int count, PageElemRef *srcs, float *ws, float *sub_ws)
|
||||
{
|
||||
void **blocks = static_cast<void **>(BLI_array_alloca(blocks, count));
|
||||
|
||||
for (int i : IndexRange(count)) {
|
||||
blocks[i] = getElemPtr(srcs[i]);
|
||||
}
|
||||
|
||||
CustomData_interpData(type, getElemPtr(elem), count, (const void **)blocks, ws, sub_ws);
|
||||
}
|
||||
|
||||
void free(PageElemRef elem)
|
||||
{
|
||||
CustomData_freeData(type, getElemPtr(elem), 1);
|
||||
}
|
||||
|
||||
void setDefault(PageElemRef elem)
|
||||
{
|
||||
CustomData_setDefaultData(type, getElemPtr(elem), 1);
|
||||
}
|
||||
|
||||
void reserve(size_t size)
|
||||
{
|
||||
size_t totpage = size >> PageSizeShift;
|
||||
// const size_t pagesize = 1ULL << PageSizeShift;
|
||||
|
||||
int curpage = pages.size();
|
||||
pages.resize(totpage);
|
||||
|
||||
for (int i = curpage; i < totpage; i++) {
|
||||
newPage();
|
||||
}
|
||||
}
|
||||
|
||||
void newPage()
|
||||
{
|
||||
const int pagesize = 1 << PageSizeShift;
|
||||
|
||||
pages.resize(pages.size() + 1);
|
||||
pages[pages.size() - 1] = MEM_malloc_arrayN(pagesize, elemSize, "bmesh attribute page");
|
||||
}
|
||||
};
|
||||
|
||||
struct BMAttrDomain {
|
||||
std::vector<PageElemRef> freelist;
|
||||
std::vector<PageArray<BM_PAGE_SHIFT> *> arrays;
|
||||
|
||||
AttributeDomain domain;
|
||||
int totpage;
|
||||
int totelem;
|
||||
int totalloc;
|
||||
|
||||
BMAttrDomain(AttributeDomain d) : domain(d), totpage(0), totelem(0)
|
||||
{
|
||||
}
|
||||
|
||||
~BMAttrDomain()
|
||||
{
|
||||
for (PageArray<BM_PAGE_SHIFT> *array : arrays) {
|
||||
delete array;
|
||||
}
|
||||
}
|
||||
|
||||
void interp(PageElemRef elem, int count, PageElemRef *srcs, float *ws, float *sub_ws)
|
||||
{
|
||||
for (PageArray<BM_PAGE_SHIFT> *array : arrays) {
|
||||
array->interp(elem, count, srcs, ws, sub_ws);
|
||||
}
|
||||
}
|
||||
|
||||
PageArray<BM_PAGE_SHIFT> *addLayer(CustomDataType type)
|
||||
{
|
||||
PageArray<BM_PAGE_SHIFT> *array = new PageArray<BM_PAGE_SHIFT>(type);
|
||||
array->reserve(totelem);
|
||||
|
||||
/* keep layers ordered by type */
|
||||
|
||||
bool state = false;
|
||||
for (auto iter=arrays.begin(); iter != arrays.end(); ++iter) {
|
||||
if ((*iter)->type == type) {
|
||||
state = true;
|
||||
//now find next layer with wrong type, we
|
||||
//will insert before it.
|
||||
}
|
||||
else if (state) {
|
||||
arrays.insert(iter, array);
|
||||
return array;
|
||||
}
|
||||
}
|
||||
|
||||
arrays.push_back(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
PageElemRef alloc(bool &haveNewPage)
|
||||
{
|
||||
if (freelist.size() == 0) {
|
||||
haveNewPage = true;
|
||||
newPage();
|
||||
}
|
||||
else {
|
||||
haveNewPage = false;
|
||||
}
|
||||
|
||||
totelem++;
|
||||
PageElemRef r = freelist[freelist.size() - 1];
|
||||
freelist.pop_back();
|
||||
|
||||
for (auto *array : arrays) {
|
||||
array->setDefault(r);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void setDefault(PageElemRef ref) {
|
||||
for (auto *array : arrays) {
|
||||
array->setDefault(ref);
|
||||
}
|
||||
}
|
||||
|
||||
void free(PageElemRef ref, bool &removedPage)
|
||||
{
|
||||
removedPage = false;
|
||||
|
||||
totelem--;
|
||||
freelist.push_back(ref);
|
||||
}
|
||||
|
||||
private:
|
||||
void newPage()
|
||||
{
|
||||
totpage++;
|
||||
totalloc += BM_PAGE_SIZE;
|
||||
|
||||
for (PageArray<> *array : arrays) {
|
||||
array->newPage();
|
||||
}
|
||||
|
||||
size_t count = 1 << BM_PAGE_SHIFT;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
freelist.push_back(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
#else
|
||||
struct BMAttrDomain;
|
||||
#endif //_cplusplus
|
||||
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "bmesh_class.h"
|
||||
|
||||
struct BMesh;
|
||||
|
||||
typedef struct BMeshPageArray {
|
||||
int esize, psize;
|
||||
void **pages;
|
||||
void *cppClass;
|
||||
} BmeshPageArray;
|
||||
|
||||
typedef struct BMeshAttrList {
|
||||
BMeshPageArray **arrays;
|
||||
int totarray;
|
||||
struct BMAttrDomain *domains[ATTR_DOMAIN_NUM];
|
||||
} BMeshAttrList;
|
||||
|
||||
typedef struct BMeshPageRef {
|
||||
// point to arrays, attribute for all domains go into one
|
||||
// list of arrays
|
||||
BMeshAttrList *attrs;
|
||||
int idx; // index into attribute list, NOT element index
|
||||
int domain;
|
||||
} BMeshPageRef;
|
||||
|
||||
BLI_INLINE void *BM_ELEM_CD_GET_VOID_P_2(BMElem *elem, int offset)
|
||||
{
|
||||
BMeshPageRef *ref = (BMeshPageRef *)elem->head.data;
|
||||
BmeshPageArray *array = ref->attrs->arrays[offset];
|
||||
size_t page = ref->idx >> BM_PAGE_SHIFT;
|
||||
size_t off = ref->idx & BM_PAGE_MASK;
|
||||
|
||||
char *ptr = (char *)array->pages[page];
|
||||
ptr += off * array->esize;
|
||||
|
||||
return (void *)ptr;
|
||||
}
|
||||
|
||||
BMeshAttrList *BMAttr_new();
|
||||
void BMAttr_reset(BMeshAttrList *list);
|
||||
void BMAttr_free(BMeshAttrList *list);
|
||||
void BMAttr_fromCData(BMeshAttrList *list, CustomData *domains[ATTR_DOMAIN_NUM]);
|
||||
void BMAttr_init(struct BMesh *bm);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
} // namespace bmesh
|
||||
} // namespace blender
|
||||
#endif
|
||||
#endif
|
|
@ -237,6 +237,11 @@ BMesh *BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreate
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef USE_BMESH_PAGE_CUSTOMDATA
|
||||
bmesh_update_attr_refs(bm);
|
||||
BMAttr_init(bm);
|
||||
#endif
|
||||
|
||||
return bm;
|
||||
}
|
||||
|
||||
|
@ -365,6 +370,11 @@ void BM_mesh_data_free(BMesh *bm)
|
|||
}
|
||||
|
||||
BMO_error_clear(bm);
|
||||
|
||||
#ifdef USE_BMESH_PAGE_CUSTOMDATA
|
||||
BMAttr_free(bm->attr_list);
|
||||
bm->attr_list = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BM_mesh_clear(BMesh *bm)
|
||||
|
@ -407,6 +417,17 @@ void BM_mesh_clear(BMesh *bm)
|
|||
#endif
|
||||
bm_init_idmap_cdlayers(bm);
|
||||
}
|
||||
|
||||
#ifdef USE_BMESH_PAGE_CUSTOMDATA
|
||||
if (!bm->attr_list) {
|
||||
bm->attr_list = BMAttr_new();
|
||||
}
|
||||
else {
|
||||
BMAttr_reset(bm->attr_list);
|
||||
}
|
||||
|
||||
BMAttr_init(bm);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BM_mesh_free(BMesh *bm)
|
||||
|
|
|
@ -379,6 +379,10 @@ void BM_mesh_bm_from_me(Object *ob,
|
|||
CustomData_bmesh_init_pool_ex(&bm->pdata, me->totpoly, BM_FACE, __func__);
|
||||
}
|
||||
|
||||
#ifdef USE_BMESH_PAGE_CUSTOMDATA
|
||||
bmesh_update_attr_refs(bm);
|
||||
#endif
|
||||
|
||||
if (params->copy_temp_cdlayers) {
|
||||
bm_mark_temp_cdlayers(bm);
|
||||
}
|
||||
|
|
|
@ -482,7 +482,7 @@ void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata,
|
|||
|
||||
MV_ADD_FLAG(mv, SCULPTVERT_NEED_BOUNDARY);
|
||||
|
||||
normal_short_to_float_v3(fno, ss->vert_normals + ml->v);
|
||||
copy_v3_v3(fno, ss->vert_normals[ml->v]);
|
||||
float mask = ss->vmask ? ss->vmask[ml->v] : 0.0f;
|
||||
|
||||
const float fade2 = bstrength *
|
||||
|
|
|
@ -94,6 +94,9 @@ typedef struct CustomData {
|
|||
struct BLI_mempool *pool;
|
||||
/** External file storing customdata layers. */
|
||||
CustomDataExternal *external;
|
||||
|
||||
/** for use with USE_BMESH_PAGE_CUSTOMDATA test, remove later*/
|
||||
void *bm_attrs, *_pad[1];
|
||||
} CustomData;
|
||||
|
||||
/* CustomData.type */
|
||||
|
|
Loading…
Reference in New Issue