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:
Joseph Eagar 2022-02-01 20:14:27 -08:00
parent 9d09011f91
commit 5f631ca7c8
16 changed files with 786 additions and 51 deletions

View File

@ -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. */

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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) {

View File

@ -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;
}

View File

@ -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

View File

@ -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 {

View File

@ -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

View File

@ -154,6 +154,7 @@ BMVert *BM_vert_create(BMesh *bm,
}
else {
CustomData_bmesh_set_default(&bm->vdata, &v->head.data);
zero_v3(v->no);
}

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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);
}

View File

@ -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 *

View File

@ -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 */