Refactor: Draw Cache: use 'BLI_task_parallel_range'

This is an adaptation of {D11488}.

A disadvantage of manually setting the iter ranges per thread is that
we don't know how many threads are running in the background and so we
don't know how to best distribute the ranges.

To solve this limitation we can use `parallel_reduce` and thus let the
driver choose the best distribution of ranges among the threads.

This proved to be especially beneficial for computers with few cores.

**Benchmarking:**
Here's the result on an 4-core laptop:
||master:|PATCH:
|---|---|---|
|large_mesh_editing:|Average: 5.203638 FPS|Average: 5.398925 FPS
||rdata 15ms iter 43ms (frame 193ms)|rdata 14ms iter 36ms (frame 187ms)

Here's the result on an 8-core PC:
||master:|PATCH:
|---|---|---|
|large_mesh_editing:|Average: 15.267482 FPS|Average: 15.906881 FPS
||rdata 9ms iter 28ms (frame 65ms)|rdata 9ms iter 25ms (frame 63ms)
|large_mesh_editing_ledge: |Average: 15.145966 FPS|Average: 15.520474 FPS
||rdata 9ms iter 29ms (frame 65ms)|rdata 9ms iter 25ms (frame 64ms)
|looptris_test:|Average: 4.001917 FPS|Average: 4.061105 FPS
||rdata 12ms iter 90ms (frame 236ms)|rdata 12ms iter 87ms (frame 230ms)
|subdiv_mesh_cage_and_final:|Average: 1.917769 FPS|Average: 1.971790 FPS
||rdata 7ms iter 37ms (frame 261ms)|rdata 7ms iter 31ms (frame 258ms)
||rdata 7ms iter 38ms (frame 252ms)|rdata 7ms iter 33ms (frame 249ms)
|subdiv_mesh_final_only:|Average: 6.387240 FPS|Average: 6.591251 FPS
||rdata 3ms iter 25ms (frame 151ms)|rdata 3ms iter 16ms (frame 145ms)
|subdiv_mesh_final_only_ledge:|Average: 6.247393 FPS|Average: 6.596024 FPS
||rdata 3ms iter 26ms (frame 158ms)|rdata 3ms iter 16ms (frame 148ms)

**Notes:**
- The improvement can only be noticed if all extracts are multithreaded.
- This patch touches different areas of the code, so it can be split into another patch if the idea is accepted.

These screenshots show how threads behave in a quadcore:
Master:
{F10164664}
Patch:
{F10164666}

Differential Revision: https://developer.blender.org/D11558
This commit is contained in:
Germano Cavalcante 2021-06-10 11:01:36 -03:00 committed by Germano Cavalcante
parent fe22635bf6
commit 2330cec2c6
Notes: blender-bot 2023-02-14 05:36:11 +01:00
Referenced by issue #102545, Regression: Wireframe overlay: toggling edit-mode shows different edges in object-mode each time
Referenced by issue #90644, Inconsistency on toggling triangulate option of Decimate modifier
Referenced by issue #89176, Blender Crash in weight paint mode when wireframe overlay is activated on a mesh with Solidify Modifier
13 changed files with 689 additions and 1256 deletions

View File

@ -50,7 +50,7 @@
# include "PIL_time_utildefines.h"
#endif
#define CHUNK_SIZE 8192
#define CHUNK_SIZE 1024
namespace blender::draw {
@ -65,26 +65,12 @@ struct ExtractorRunData {
const MeshExtract *extractor;
/* During iteration the VBO/IBO that is being build. */
void *buffer = nullptr;
/* User data during iteration. Created in MeshExtract.init and passed along to other MeshExtract
* functions. */
void *user_data = nullptr;
std::optional<Array<void *>> task_user_datas;
uint32_t data_offset = 0;
ExtractorRunData(const MeshExtract *extractor) : extractor(extractor)
{
}
void init_task_user_datas(const TaskLen task_len)
{
task_user_datas = Array<void *>(task_len);
}
void *&operator[](const TaskId task_id)
{
BLI_assert(task_user_datas);
return (*task_user_datas)[task_id];
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DRAW:ExtractorRunData")
#endif
@ -157,6 +143,16 @@ class ExtractorRunDatas : public Vector<ExtractorRunData> {
return data_type;
}
size_t data_size_total()
{
size_t data_size = 0;
for (const ExtractorRunData &data : *this) {
const MeshExtract *extractor = data.extractor;
data_size += extractor->data_size;
}
return data_size;
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DRAW:ExtractorRunDatas")
#endif
@ -164,323 +160,24 @@ class ExtractorRunDatas : public Vector<ExtractorRunData> {
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Extract
* \{ */
BLI_INLINE void extract_init(const MeshRenderData *mr,
struct MeshBatchCache *cache,
ExtractorRunDatas &extractors,
MeshBufferCache *mbc)
{
/* Multi thread. */
for (ExtractorRunData &run_data : extractors) {
const MeshExtract *extractor = run_data.extractor;
run_data.buffer = mesh_extract_buffer_get(extractor, mbc);
run_data.user_data = extractor->init(mr, cache, run_data.buffer);
}
}
BLI_INLINE void extract_iter_looptri_bm(const MeshRenderData *mr,
const ExtractTriBMesh_Params *params,
const ExtractorRunDatas &all_extractors,
const TaskId task_id)
{
ExtractorRunDatas extractors;
all_extractors.filter_into(extractors, MR_ITER_LOOPTRI);
EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, elt_index, params)
{
for (ExtractorRunData &run_data : extractors) {
run_data.extractor->iter_looptri_bm(mr, elt, elt_index, run_data[task_id]);
}
}
EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END;
}
BLI_INLINE void extract_iter_looptri_mesh(const MeshRenderData *mr,
const ExtractTriMesh_Params *params,
const ExtractorRunDatas &all_extractors,
const TaskId task_id)
{
ExtractorRunDatas extractors;
all_extractors.filter_into(extractors, MR_ITER_LOOPTRI);
EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, mlt_index, params)
{
for (ExtractorRunData &run_data : extractors) {
run_data.extractor->iter_looptri_mesh(mr, mlt, mlt_index, run_data[task_id]);
}
}
EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END;
}
BLI_INLINE void extract_iter_poly_bm(const MeshRenderData *mr,
const ExtractPolyBMesh_Params *params,
const ExtractorRunDatas &all_extractors,
const TaskId task_id)
{
ExtractorRunDatas extractors;
all_extractors.filter_into(extractors, MR_ITER_POLY);
EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr)
{
for (ExtractorRunData &run_data : extractors) {
run_data.extractor->iter_poly_bm(mr, f, f_index, run_data[task_id]);
}
}
EXTRACT_POLY_FOREACH_BM_END;
}
BLI_INLINE void extract_iter_poly_mesh(const MeshRenderData *mr,
const ExtractPolyMesh_Params *params,
const ExtractorRunDatas &all_extractors,
const TaskId task_id)
{
ExtractorRunDatas extractors;
all_extractors.filter_into(extractors, MR_ITER_POLY);
EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr)
{
for (ExtractorRunData &run_data : extractors) {
run_data.extractor->iter_poly_mesh(mr, mp, mp_index, run_data[task_id]);
}
}
EXTRACT_POLY_FOREACH_MESH_END;
}
BLI_INLINE void extract_iter_ledge_bm(const MeshRenderData *mr,
const ExtractLEdgeBMesh_Params *params,
const ExtractorRunDatas &all_extractors,
const TaskId task_id)
{
ExtractorRunDatas extractors;
all_extractors.filter_into(extractors, MR_ITER_LEDGE);
EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params)
{
for (ExtractorRunData &run_data : extractors) {
run_data.extractor->iter_ledge_bm(mr, eed, ledge_index, run_data[task_id]);
}
}
EXTRACT_LEDGE_FOREACH_BM_END;
}
BLI_INLINE void extract_iter_ledge_mesh(const MeshRenderData *mr,
const ExtractLEdgeMesh_Params *params,
const ExtractorRunDatas &all_extractors,
const TaskId task_id)
{
ExtractorRunDatas extractors;
all_extractors.filter_into(extractors, MR_ITER_LEDGE);
EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr)
{
for (ExtractorRunData &run_data : extractors) {
run_data.extractor->iter_ledge_mesh(mr, med, ledge_index, run_data[task_id]);
}
}
EXTRACT_LEDGE_FOREACH_MESH_END;
}
BLI_INLINE void extract_iter_lvert_bm(const MeshRenderData *mr,
const ExtractLVertBMesh_Params *params,
const ExtractorRunDatas &all_extractors,
const TaskId task_id)
{
ExtractorRunDatas extractors;
all_extractors.filter_into(extractors, MR_ITER_LVERT);
EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params)
{
for (ExtractorRunData &run_data : extractors) {
run_data.extractor->iter_lvert_bm(mr, eve, lvert_index, run_data[task_id]);
}
}
EXTRACT_LVERT_FOREACH_BM_END;
}
BLI_INLINE void extract_iter_lvert_mesh(const MeshRenderData *mr,
const ExtractLVertMesh_Params *params,
const ExtractorRunDatas &all_extractors,
const TaskId task_id)
{
ExtractorRunDatas extractors;
all_extractors.filter_into(extractors, MR_ITER_LVERT);
EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr)
{
for (ExtractorRunData &run_data : extractors) {
run_data.extractor->iter_lvert_mesh(mr, mv, lvert_index, run_data[task_id]);
}
}
EXTRACT_LVERT_FOREACH_MESH_END;
}
BLI_INLINE void extract_finish(const MeshRenderData *mr,
struct MeshBatchCache *cache,
const ExtractorRunDatas &extractors)
{
for (const ExtractorRunData &run_data : extractors) {
const MeshExtract *extractor = run_data.extractor;
if (extractor->finish) {
extractor->finish(mr, cache, run_data.buffer, run_data.user_data);
}
}
}
BLI_INLINE void extract_task_init(ExtractorRunDatas &extractors, const TaskLen task_len)
{
for (ExtractorRunData &run_data : extractors) {
run_data.init_task_user_datas(task_len);
const MeshExtract *extractor = run_data.extractor;
for (TaskId task_id = 0; task_id < task_len; task_id++) {
void *user_task_data = run_data.user_data;
if (extractor->task_init) {
user_task_data = extractor->task_init(run_data.user_data);
}
run_data[task_id] = user_task_data;
}
}
}
BLI_INLINE void extract_task_finish(ExtractorRunDatas &extractors, const TaskLen task_len)
{
for (ExtractorRunData &run_data : extractors) {
const MeshExtract *extractor = run_data.extractor;
if (extractor->task_finish) {
for (TaskId task_id = 0; task_id < task_len; task_id++) {
void *task_user_data = run_data[task_id];
extractor->task_finish(run_data.user_data, task_user_data);
run_data[task_id] = nullptr;
}
}
}
}
/* Single Thread. */
BLI_INLINE void extract_run_single_threaded(const MeshRenderData *mr,
struct MeshBatchCache *cache,
ExtractorRunDatas &extractors,
eMRIterType iter_type,
MeshBufferCache *mbc)
{
const TaskLen task_len = 1;
const TaskId task_id = 0;
extract_init(mr, cache, extractors, mbc);
extract_task_init(extractors, task_len);
bool is_mesh = mr->extract_type != MR_EXTRACT_BMESH;
if (iter_type & MR_ITER_LOOPTRI) {
if (is_mesh) {
ExtractTriMesh_Params params;
params.mlooptri = mr->mlooptri;
params.tri_range[0] = 0;
params.tri_range[1] = mr->tri_len;
extract_iter_looptri_mesh(mr, &params, extractors, task_id);
}
else {
ExtractTriBMesh_Params params;
params.looptris = mr->edit_bmesh->looptris;
params.tri_range[0] = 0;
params.tri_range[1] = mr->tri_len;
extract_iter_looptri_bm(mr, &params, extractors, task_id);
}
}
if (iter_type & MR_ITER_POLY) {
if (is_mesh) {
ExtractPolyMesh_Params params;
params.poly_range[0] = 0;
params.poly_range[1] = mr->poly_len;
extract_iter_poly_mesh(mr, &params, extractors, task_id);
}
else {
ExtractPolyBMesh_Params params;
params.poly_range[0] = 0;
params.poly_range[1] = mr->poly_len;
extract_iter_poly_bm(mr, &params, extractors, task_id);
}
}
if (iter_type & MR_ITER_LEDGE) {
if (is_mesh) {
ExtractLEdgeMesh_Params params;
params.ledge = mr->ledges;
params.ledge_range[0] = 0;
params.ledge_range[1] = mr->edge_loose_len;
extract_iter_ledge_mesh(mr, &params, extractors, task_id);
}
else {
ExtractLEdgeBMesh_Params params;
params.ledge = mr->ledges;
params.ledge_range[0] = 0;
params.ledge_range[1] = mr->edge_loose_len;
extract_iter_ledge_bm(mr, &params, extractors, task_id);
}
}
if (iter_type & MR_ITER_LVERT) {
if (is_mesh) {
ExtractLVertMesh_Params params;
params.lvert = mr->lverts;
params.lvert_range[0] = 0;
params.lvert_range[1] = mr->vert_loose_len;
extract_iter_lvert_mesh(mr, &params, extractors, task_id);
}
else {
ExtractLVertBMesh_Params params;
params.lvert = mr->lverts;
params.lvert_range[0] = 0;
params.lvert_range[1] = mr->vert_loose_len;
extract_iter_lvert_bm(mr, &params, extractors, task_id);
}
}
extract_task_finish(extractors, task_len);
extract_finish(mr, cache, extractors);
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name ExtractTaskData
* \{ */
struct ExtractTaskData {
const MeshRenderData *mr = nullptr;
MeshBatchCache *cache = nullptr;
/* #UserData is shared between the iterations as it holds counters to detect if the
* extraction is finished. To make sure the duplication of the user_data does not create a new
* instance of the counters we allocate the user_data in its own container.
*
* This structure makes sure that when extract_init is called, that the user data of all
* iterations are updated. */
ExtractorRunDatas *extractors = nullptr;
MeshBufferCache *mbc = nullptr;
int32_t *task_counter = nullptr;
/* Total number of tasks that are created for multi threaded extraction.
* (= 1 for single threaded extractors). */
uint task_len;
/* Task id of the extraction task. Must never exceed task_len. (= 0 for single threaded
* extractors). */
uint task_id = 0;
eMRIterType iter_type;
int start = 0;
int end = INT_MAX;
/** Decremented each time a task is finished. */
bool use_threading = false;
ExtractTaskData(const MeshRenderData *mr,
struct MeshBatchCache *cache,
ExtractorRunDatas *extractors,
MeshBufferCache *mbc,
int32_t *task_counter,
const uint task_len)
: mr(mr),
cache(cache),
extractors(extractors),
mbc(mbc),
task_counter(task_counter),
task_len(task_len)
const bool use_threading)
: mr(mr), cache(cache), extractors(extractors), mbc(mbc), use_threading(use_threading)
{
iter_type = extractors->iter_types();
};
@ -503,108 +200,295 @@ static void extract_task_data_free(void *data)
delete task_data;
}
static void extract_task_data_free_ex(void *data)
{
ExtractTaskData *task_data = static_cast<ExtractTaskData *>(data);
task_data->extractors = nullptr;
delete task_data;
}
/** \} */
BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr,
const eMRIterType iter_type,
int start,
int end,
ExtractorRunDatas &extractors,
const TaskId task_id)
/* ---------------------------------------------------------------------- */
/** \name Extract Init and Finish
* \{ */
BLI_INLINE void extract_init(const MeshRenderData *mr,
struct MeshBatchCache *cache,
ExtractorRunDatas &extractors,
MeshBufferCache *mbc,
void *data_stack)
{
switch (mr->extract_type) {
case MR_EXTRACT_BMESH:
if (iter_type & MR_ITER_LOOPTRI) {
ExtractTriBMesh_Params params;
params.looptris = mr->edit_bmesh->looptris;
params.tri_range[0] = start;
params.tri_range[1] = min_ii(mr->tri_len, end);
extract_iter_looptri_bm(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_POLY) {
ExtractPolyBMesh_Params params;
params.poly_range[0] = start;
params.poly_range[1] = min_ii(mr->poly_len, end);
extract_iter_poly_bm(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_LEDGE) {
ExtractLEdgeBMesh_Params params;
params.ledge = mr->ledges;
params.ledge_range[0] = start;
params.ledge_range[1] = min_ii(mr->edge_loose_len, end);
extract_iter_ledge_bm(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_LVERT) {
ExtractLVertBMesh_Params params;
params.lvert = mr->lverts;
params.lvert_range[0] = start;
params.lvert_range[1] = min_ii(mr->vert_loose_len, end);
extract_iter_lvert_bm(mr, &params, extractors, task_id);
}
break;
case MR_EXTRACT_MAPPED:
case MR_EXTRACT_MESH:
if (iter_type & MR_ITER_LOOPTRI) {
ExtractTriMesh_Params params;
params.mlooptri = mr->mlooptri;
params.tri_range[0] = start;
params.tri_range[1] = min_ii(mr->tri_len, end);
extract_iter_looptri_mesh(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_POLY) {
ExtractPolyMesh_Params params;
params.poly_range[0] = start;
params.poly_range[1] = min_ii(mr->poly_len, end);
extract_iter_poly_mesh(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_LEDGE) {
ExtractLEdgeMesh_Params params;
params.ledge = mr->ledges;
params.ledge_range[0] = start;
params.ledge_range[1] = min_ii(mr->edge_loose_len, end);
extract_iter_ledge_mesh(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_LVERT) {
ExtractLVertMesh_Params params;
params.lvert = mr->lverts;
params.lvert_range[0] = start;
params.lvert_range[1] = min_ii(mr->vert_loose_len, end);
extract_iter_lvert_mesh(mr, &params, extractors, task_id);
}
break;
uint32_t data_offset = 0;
for (ExtractorRunData &run_data : extractors) {
const MeshExtract *extractor = run_data.extractor;
run_data.buffer = mesh_extract_buffer_get(extractor, mbc);
run_data.data_offset = data_offset;
extractor->init(mr, cache, run_data.buffer, POINTER_OFFSET(data_stack, data_offset));
data_offset += (uint32_t)extractor->data_size;
}
}
static void extract_task_init(ExtractTaskData *data)
BLI_INLINE void extract_finish(const MeshRenderData *mr,
struct MeshBatchCache *cache,
const ExtractorRunDatas &extractors,
void *data_stack)
{
extract_init(data->mr, data->cache, *data->extractors, data->mbc);
extract_task_init(*data->extractors, data->task_len);
}
static void extract_task_run(void *__restrict taskdata)
{
ExtractTaskData *data = (ExtractTaskData *)taskdata;
mesh_extract_iter(
data->mr, data->iter_type, data->start, data->end, *data->extractors, data->task_id);
/* If this is the last task, we do the finish function. */
int remainin_tasks = atomic_sub_and_fetch_int32(data->task_counter, 1);
if (remainin_tasks == 0) {
extract_task_finish(*data->extractors, data->task_len);
extract_finish(data->mr, data->cache, *data->extractors);
for (const ExtractorRunData &run_data : extractors) {
const MeshExtract *extractor = run_data.extractor;
if (extractor->finish) {
extractor->finish(
mr, cache, run_data.buffer, POINTER_OFFSET(data_stack, run_data.data_offset));
}
}
}
static void extract_task_init_and_run(void *__restrict taskdata)
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Extract In Parallel Ranges
* \{ */
struct ExtractorIterData {
ExtractorRunDatas extractors;
const MeshRenderData *mr = nullptr;
const void *elems = nullptr;
const int *loose_elems = nullptr;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DRW:MeshRenderDataUpdateTaskData")
#endif
};
static void extract_task_reduce(const void *__restrict userdata,
void *__restrict chunk_to,
void *__restrict chunk_from)
{
const ExtractorIterData *data = static_cast<const ExtractorIterData *>(userdata);
for (const ExtractorRunData &run_data : data->extractors) {
const MeshExtract *extractor = run_data.extractor;
if (extractor->task_reduce) {
extractor->task_reduce(POINTER_OFFSET(chunk_to, run_data.data_offset),
POINTER_OFFSET(chunk_from, run_data.data_offset));
}
}
}
static void extract_range_iter_looptri_bm(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
void *extract_data = tls->userdata_chunk;
const MeshRenderData *mr = data->mr;
BMLoop **elt = ((BMLoop * (*)[3]) data->elems)[iter];
for (const ExtractorRunData &run_data : data->extractors) {
run_data.extractor->iter_looptri_bm(
mr, elt, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
}
static void extract_range_iter_looptri_mesh(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
void *extract_data = tls->userdata_chunk;
const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
const MeshRenderData *mr = data->mr;
const MLoopTri *mlt = &((const MLoopTri *)data->elems)[iter];
for (const ExtractorRunData &run_data : data->extractors) {
run_data.extractor->iter_looptri_mesh(
mr, mlt, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
}
static void extract_range_iter_poly_bm(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
void *extract_data = tls->userdata_chunk;
const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
const MeshRenderData *mr = data->mr;
const BMFace *f = ((const BMFace **)data->elems)[iter];
for (const ExtractorRunData &run_data : data->extractors) {
run_data.extractor->iter_poly_bm(
mr, f, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
}
static void extract_range_iter_poly_mesh(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
void *extract_data = tls->userdata_chunk;
const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
const MeshRenderData *mr = data->mr;
const MPoly *mp = &((const MPoly *)data->elems)[iter];
for (const ExtractorRunData &run_data : data->extractors) {
run_data.extractor->iter_poly_mesh(
mr, mp, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
}
static void extract_range_iter_ledge_bm(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
void *extract_data = tls->userdata_chunk;
const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
const MeshRenderData *mr = data->mr;
const int ledge_index = data->loose_elems[iter];
const BMEdge *eed = ((const BMEdge **)data->elems)[ledge_index];
for (const ExtractorRunData &run_data : data->extractors) {
run_data.extractor->iter_ledge_bm(
mr, eed, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
}
static void extract_range_iter_ledge_mesh(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
void *extract_data = tls->userdata_chunk;
const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
const MeshRenderData *mr = data->mr;
const int ledge_index = data->loose_elems[iter];
const MEdge *med = &((const MEdge *)data->elems)[ledge_index];
for (const ExtractorRunData &run_data : data->extractors) {
run_data.extractor->iter_ledge_mesh(
mr, med, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
}
static void extract_range_iter_lvert_bm(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
void *extract_data = tls->userdata_chunk;
const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
const MeshRenderData *mr = data->mr;
const int lvert_index = data->loose_elems[iter];
const BMVert *eve = ((const BMVert **)data->elems)[lvert_index];
for (const ExtractorRunData &run_data : data->extractors) {
run_data.extractor->iter_lvert_bm(
mr, eve, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
}
static void extract_range_iter_lvert_mesh(void *__restrict userdata,
const int iter,
const TaskParallelTLS *__restrict tls)
{
void *extract_data = tls->userdata_chunk;
const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
const MeshRenderData *mr = data->mr;
const int lvert_index = data->loose_elems[iter];
const MVert *mv = &((const MVert *)data->elems)[lvert_index];
for (const ExtractorRunData &run_data : data->extractors) {
run_data.extractor->iter_lvert_mesh(
mr, mv, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
}
}
BLI_INLINE void extract_task_range_run_iter(const MeshRenderData *mr,
ExtractorRunDatas *extractors,
const eMRIterType iter_type,
bool is_mesh,
TaskParallelSettings *settings)
{
ExtractorIterData range_data;
range_data.mr = mr;
TaskParallelRangeFunc func;
int stop;
switch (iter_type) {
case MR_ITER_LOOPTRI:
range_data.elems = is_mesh ? mr->mlooptri : (void *)mr->edit_bmesh->looptris;
func = is_mesh ? extract_range_iter_looptri_mesh : extract_range_iter_looptri_bm;
stop = mr->tri_len;
break;
case MR_ITER_POLY:
range_data.elems = is_mesh ? mr->mpoly : (void *)mr->bm->ftable;
func = is_mesh ? extract_range_iter_poly_mesh : extract_range_iter_poly_bm;
stop = mr->poly_len;
break;
case MR_ITER_LEDGE:
range_data.loose_elems = mr->ledges;
range_data.elems = is_mesh ? mr->medge : (void *)mr->bm->etable;
func = is_mesh ? extract_range_iter_ledge_mesh : extract_range_iter_ledge_bm;
stop = mr->edge_loose_len;
break;
case MR_ITER_LVERT:
range_data.loose_elems = mr->lverts;
range_data.elems = is_mesh ? mr->mvert : (void *)mr->bm->vtable;
func = is_mesh ? extract_range_iter_lvert_mesh : extract_range_iter_lvert_bm;
stop = mr->vert_loose_len;
break;
default:
BLI_assert(false);
return;
}
extractors->filter_into(range_data.extractors, iter_type);
BLI_task_parallel_range(0, stop, &range_data, func, settings);
}
static void extract_task_range_run(void *__restrict taskdata)
{
ExtractTaskData *data = (ExtractTaskData *)taskdata;
extract_run_single_threaded(
data->mr, data->cache, *data->extractors, data->iter_type, data->mbc);
const eMRIterType iter_type = data->iter_type;
const bool is_mesh = data->mr->extract_type != MR_EXTRACT_BMESH;
TaskParallelSettings settings;
BLI_parallel_range_settings_defaults(&settings);
settings.func_reduce = extract_task_reduce;
settings.min_iter_per_thread = CHUNK_SIZE;
settings.use_threading = data->use_threading;
size_t chunk_size = data->extractors->data_size_total();
char *chunk = new char[chunk_size];
extract_init(data->mr, data->cache, *data->extractors, data->mbc, (void *)chunk);
settings.userdata_chunk = chunk;
settings.userdata_chunk_size = chunk_size;
if (iter_type & MR_ITER_LOOPTRI) {
extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_LOOPTRI, is_mesh, &settings);
}
if (iter_type & MR_ITER_POLY) {
extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_POLY, is_mesh, &settings);
}
if (iter_type & MR_ITER_LEDGE) {
extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_LEDGE, is_mesh, &settings);
}
if (iter_type & MR_ITER_LVERT) {
extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_LVERT, is_mesh, &settings);
}
extract_finish(data->mr, data->cache, *data->extractors, (void *)chunk);
delete[] chunk;
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Extract Single Thread
* \{ */
static struct TaskNode *extract_task_node_create(struct TaskGraph *task_graph,
const MeshRenderData *mr,
MeshBatchCache *cache,
ExtractorRunDatas *extractors,
MeshBufferCache *mbc,
const bool use_threading)
{
ExtractTaskData *taskdata = new ExtractTaskData(mr, cache, extractors, mbc, use_threading);
struct TaskNode *task_node = BLI_task_graph_node_create(
task_graph,
extract_task_range_run,
taskdata,
(TaskGraphNodeFreeFunction)extract_task_data_free);
return task_node;
}
/** \} */
@ -669,154 +553,10 @@ static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *t
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Task Node - Extract Single Threaded
* \{ */
static struct TaskNode *extract_single_threaded_task_node_create(struct TaskGraph *task_graph,
ExtractTaskData *task_data)
{
struct TaskNode *task_node = BLI_task_graph_node_create(
task_graph,
extract_task_init_and_run,
task_data,
(TaskGraphNodeFreeFunction)extract_task_data_free);
return task_node;
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Task Node - UserData Initializer
* \{ */
struct UserDataInitTaskData {
ExtractTaskData *td = nullptr;
int32_t task_counter = 0;
~UserDataInitTaskData()
{
extract_task_data_free(td);
}
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("DRW:UserDataInitTaskData")
#endif
};
static void user_data_init_task_data_free(void *data)
{
UserDataInitTaskData *taskdata = static_cast<UserDataInitTaskData *>(data);
delete taskdata;
}
static void user_data_init_task_data_exec(void *__restrict task_data)
{
UserDataInitTaskData *extract_task_data = static_cast<UserDataInitTaskData *>(task_data);
ExtractTaskData *taskdata_base = extract_task_data->td;
extract_task_init(taskdata_base);
}
static struct TaskNode *user_data_init_task_node_create(struct TaskGraph *task_graph,
UserDataInitTaskData *task_data)
{
struct TaskNode *task_node = BLI_task_graph_node_create(
task_graph,
user_data_init_task_data_exec,
task_data,
(TaskGraphNodeFreeFunction)user_data_init_task_data_free);
return task_node;
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Extract Loop
* \{ */
static void extract_range_task_create(struct TaskGraph *task_graph,
struct TaskNode *task_node_user_data_init,
ExtractTaskData *taskdata,
const eMRIterType type,
int start,
int length)
{
taskdata = new ExtractTaskData(*taskdata);
taskdata->task_id = atomic_fetch_and_add_int32(taskdata->task_counter, 1);
BLI_assert(taskdata->task_id < taskdata->task_len);
taskdata->iter_type = type;
taskdata->start = start;
taskdata->end = start + length;
struct TaskNode *task_node = BLI_task_graph_node_create(
task_graph, extract_task_run, taskdata, extract_task_data_free_ex);
BLI_task_graph_edge_create(task_node_user_data_init, task_node);
}
static int extract_range_task_num_elements_get(const MeshRenderData *mr,
const eMRIterType iter_type)
{
/* Divide task into sensible chunks. */
int iter_len = 0;
if (iter_type & MR_ITER_LOOPTRI) {
iter_len += mr->tri_len;
}
if (iter_type & MR_ITER_POLY) {
iter_len += mr->poly_len;
}
if (iter_type & MR_ITER_LEDGE) {
iter_len += mr->edge_loose_len;
}
if (iter_type & MR_ITER_LVERT) {
iter_len += mr->vert_loose_len;
}
return iter_len;
}
static int extract_range_task_chunk_size_get(const MeshRenderData *mr,
const eMRIterType iter_type,
const int num_threads)
{
/* Divide task into sensible chunks. */
const int num_elements = extract_range_task_num_elements_get(mr, iter_type);
int range_len = (num_elements + num_threads) / num_threads;
CLAMP_MIN(range_len, CHUNK_SIZE);
return range_len;
}
static void extract_task_in_ranges_create(struct TaskGraph *task_graph,
struct TaskNode *task_node_user_data_init,
ExtractTaskData *taskdata_base,
const int num_threads)
{
const MeshRenderData *mr = taskdata_base->mr;
const int range_len = extract_range_task_chunk_size_get(
mr, taskdata_base->iter_type, num_threads);
if (taskdata_base->iter_type & MR_ITER_LOOPTRI) {
for (int i = 0; i < mr->tri_len; i += range_len) {
extract_range_task_create(
task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LOOPTRI, i, range_len);
}
}
if (taskdata_base->iter_type & MR_ITER_POLY) {
for (int i = 0; i < mr->poly_len; i += range_len) {
extract_range_task_create(
task_graph, task_node_user_data_init, taskdata_base, MR_ITER_POLY, i, range_len);
}
}
if (taskdata_base->iter_type & MR_ITER_LEDGE) {
for (int i = 0; i < mr->edge_loose_len; i += range_len) {
extract_range_task_create(
task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LEDGE, i, range_len);
}
}
if (taskdata_base->iter_type & MR_ITER_LVERT) {
for (int i = 0; i < mr->vert_loose_len; i += range_len) {
extract_range_task_create(
task_graph, task_node_user_data_init, taskdata_base, MR_ITER_LVERT, i, range_len);
}
}
}
static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
MeshBatchCache *cache,
MeshBufferCache *mbc,
@ -968,20 +708,16 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
const bool use_thread = (mr->loop_len + mr->loop_loose_len) > CHUNK_SIZE;
if (use_thread) {
uint single_threaded_extractors_len = 0;
/* First run the requested extractors that do not support asynchronous ranges. */
for (const ExtractorRunData &run_data : extractors) {
const MeshExtract *extractor = run_data.extractor;
if (!extractor->use_threading) {
ExtractorRunDatas *single_threaded_extractors = new ExtractorRunDatas();
single_threaded_extractors->append(extractor);
ExtractTaskData *taskdata = new ExtractTaskData(
mr, cache, single_threaded_extractors, mbc, nullptr, 1);
struct TaskNode *task_node = extract_single_threaded_task_node_create(task_graph,
taskdata);
struct TaskNode *task_node = extract_task_node_create(
task_graph, mr, cache, single_threaded_extractors, mbc, false);
BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
single_threaded_extractors_len++;
}
}
@ -989,31 +725,10 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
ExtractorRunDatas *multi_threaded_extractors = new ExtractorRunDatas();
extractors.filter_threaded_extractors_into(*multi_threaded_extractors);
if (!multi_threaded_extractors->is_empty()) {
/*
* Determine the number of thread to use for multithreading.
* Thread can be used for single threaded tasks. These typically take longer to execute so
* fill the rest of the threads for range operations.
*/
int num_threads = BLI_task_scheduler_num_threads();
num_threads -= single_threaded_extractors_len % num_threads;
const int max_multithreaded_task_len = multi_threaded_extractors->iter_types_len() +
num_threads;
struct TaskNode *task_node = extract_task_node_create(
task_graph, mr, cache, multi_threaded_extractors, mbc, true);
UserDataInitTaskData *user_data_init_task_data = new UserDataInitTaskData();
struct TaskNode *task_node_user_data_init = user_data_init_task_node_create(
task_graph, user_data_init_task_data);
user_data_init_task_data->td = new ExtractTaskData(mr,
cache,
multi_threaded_extractors,
mbc,
&user_data_init_task_data->task_counter,
max_multithreaded_task_len);
extract_task_in_ranges_create(
task_graph, task_node_user_data_init, user_data_init_task_data->td, num_threads);
BLI_task_graph_edge_create(task_node_mesh_render_data, task_node_user_data_init);
BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
}
else {
/* No tasks created freeing extractors list. */
@ -1023,9 +738,9 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph,
else {
/* Run all requests on the same thread. */
ExtractorRunDatas *extractors_copy = new ExtractorRunDatas(extractors);
ExtractTaskData *taskdata = new ExtractTaskData(mr, cache, extractors_copy, mbc, nullptr, 1);
struct TaskNode *task_node = extract_task_node_create(
task_graph, mr, cache, extractors_copy, mbc, false);
struct TaskNode *task_node = extract_single_threaded_task_node_create(task_graph, taskdata);
BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
}

View File

@ -150,278 +150,56 @@ BLI_INLINE const float *bm_face_no_get(const MeshRenderData *mr, const BMFace *e
return efa->no;
}
/* TODO(jbakker): phase out batch iteration macros as they are only used once. */
/* ---------------------------------------------------------------------- */
/** \name Mesh Elements Extract: Loop Triangles
* \{ */
typedef struct ExtractTriBMesh_Params {
BMLoop *(*looptris)[3];
int tri_range[2];
} ExtractTriBMesh_Params;
typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
BMLoop **elt,
const int elt_index,
void *data);
#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elem_tri, index_tri, params) \
CHECK_TYPE(params, const ExtractTriBMesh_Params *); \
{ \
const int _tri_index_end = (params)->tri_range[1]; \
BMLoop **elem_tri = (params)->looptris[(params)->tri_range[0]]; \
for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
index_tri += 1, elem_tri += 3)
#define EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END }
typedef struct ExtractTriMesh_Params {
const MLoopTri *mlooptri;
int tri_range[2];
} ExtractTriMesh_Params;
typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
const MLoopTri *mlt,
const int elt_index,
void *data);
#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(elem_tri, index_tri, params) \
CHECK_TYPE(params, const ExtractTriMesh_Params *); \
{ \
const int _tri_index_end = (params)->tri_range[1]; \
const MLoopTri *elem_tri = &(params)->mlooptri[(params)->tri_range[0]]; \
for (int index_tri = (params)->tri_range[0]; index_tri < _tri_index_end; \
index_tri += 1, elem_tri += 1)
#define EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END }
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Mesh Elements Extract: Polygons, Loops
* \{ */
typedef struct ExtractPolyBMesh_Params {
BMLoop *(*looptris)[3];
int poly_range[2];
} ExtractPolyBMesh_Params;
typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
BMFace *f,
const int f_index,
void *data);
#define EXTRACT_POLY_FOREACH_BM_BEGIN(elem_poly, index_poly, params, mr) \
CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
{ \
BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
BMFace **_ftable = mr->bm->ftable; \
const int _poly_index_end = (params)->poly_range[1]; \
for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
index_poly += 1) { \
BMFace *elem_poly = _ftable[index_poly]; \
(void)elem_poly;
#define EXTRACT_POLY_FOREACH_BM_END \
} \
}
/* Iterate over polygon and loop. */
#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_BEGIN(elem_loop, index_loop, params, mr) \
CHECK_TYPE(params, const ExtractPolyBMesh_Params *); \
{ \
BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
BMFace **_ftable = mr->bm->ftable; \
const int _poly_index_end = (params)->poly_range[1]; \
for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
index_poly += 1) { \
BMFace *elem_face = _ftable[index_poly]; \
BMLoop *elem_loop, *l_first; \
elem_loop = l_first = BM_FACE_FIRST_LOOP(elem_face); \
do { \
const int index_loop = BM_elem_index_get(elem_loop); \
(void)index_loop; /* Quiet warning when unused. */
#define EXTRACT_POLY_AND_LOOP_FOREACH_BM_END(elem_loop) \
} \
while ((elem_loop = elem_loop->next) != l_first) \
; \
} \
}
typedef struct ExtractPolyMesh_Params {
int poly_range[2];
} ExtractPolyMesh_Params;
typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
const MPoly *mp,
const int mp_index,
void *data);
#define EXTRACT_POLY_FOREACH_MESH_BEGIN(elem_poly, index_poly, params, mr) \
CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
{ \
const MPoly *_mpoly = mr->mpoly; \
const int _poly_index_end = (params)->poly_range[1]; \
for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
index_poly += 1) { \
const MPoly *elem_poly = &_mpoly[index_poly]; \
(void)elem_poly;
#define EXTRACT_POLY_FOREACH_MESH_END \
} \
}
/* Iterate over polygon and loop. */
#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_BEGIN( \
elem_poly, index_poly, elem_loop, index_loop, params, mr) \
CHECK_TYPE(params, const ExtractPolyMesh_Params *); \
{ \
const MPoly *_mpoly = mr->mpoly; \
const MLoop *_mloop = mr->mloop; \
const int _poly_index_end = (params)->poly_range[1]; \
for (int index_poly = (params)->poly_range[0]; index_poly < _poly_index_end; \
index_poly += 1) { \
const MPoly *elem_poly = &_mpoly[index_poly]; \
const int _index_end = elem_poly->loopstart + elem_poly->totloop; \
for (int index_loop = elem_poly->loopstart; index_loop < _index_end; index_loop += 1) { \
const MLoop *elem_loop = &_mloop[index_loop]; \
(void)elem_loop;
#define EXTRACT_POLY_AND_LOOP_FOREACH_MESH_END \
} \
} \
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Mesh Elements Extract: Loose Edges
* \{ */
typedef struct ExtractLEdgeBMesh_Params {
const int *ledge;
int ledge_range[2];
} ExtractLEdgeBMesh_Params;
typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
BMEdge *eed,
const int ledge_index,
void *data);
#define EXTRACT_LEDGE_FOREACH_BM_BEGIN(elem_edge, index_ledge, params) \
CHECK_TYPE(params, const ExtractLEdgeBMesh_Params *); \
{ \
BLI_assert((mr->bm->elem_table_dirty & BM_EDGE) == 0); \
BMEdge **_etable = mr->bm->etable; \
const int *_ledge = (params)->ledge; \
const int _ledge_index_end = (params)->ledge_range[1]; \
for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
index_ledge += 1) { \
BMEdge *elem_edge = _etable[_ledge[index_ledge]]; \
(void)elem_edge; /* Quiet warning when unused. */ \
{
#define EXTRACT_LEDGE_FOREACH_BM_END \
} \
} \
}
typedef struct ExtractLEdgeMesh_Params {
const int *ledge;
int ledge_range[2];
} ExtractLEdgeMesh_Params;
typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
const MEdge *med,
const int ledge_index,
void *data);
#define EXTRACT_LEDGE_FOREACH_MESH_BEGIN(elem_edge, index_ledge, params, mr) \
CHECK_TYPE(params, const ExtractLEdgeMesh_Params *); \
{ \
const MEdge *_medge = mr->medge; \
const int *_ledge = (params)->ledge; \
const int _ledge_index_end = (params)->ledge_range[1]; \
for (int index_ledge = (params)->ledge_range[0]; index_ledge < _ledge_index_end; \
index_ledge += 1) { \
const MEdge *elem_edge = &_medge[_ledge[index_ledge]]; \
(void)elem_edge; /* Quiet warning when unused. */ \
{
#define EXTRACT_LEDGE_FOREACH_MESH_END \
} \
} \
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Mesh Elements Extract: Loose Vertices
* \{ */
typedef struct ExtractLVertBMesh_Params {
const int *lvert;
int lvert_range[2];
} ExtractLVertBMesh_Params;
typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
BMVert *eve,
const int lvert_index,
void *data);
#define EXTRACT_LVERT_FOREACH_BM_BEGIN(elem_vert, index_lvert, params) \
CHECK_TYPE(params, const ExtractLVertBMesh_Params *); \
{ \
BLI_assert((mr->bm->elem_table_dirty & BM_FACE) == 0); \
BMVert **vtable = mr->bm->vtable; \
const int *lverts = (params)->lvert; \
const int _lvert_index_end = (params)->lvert_range[1]; \
for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
index_lvert += 1) { \
BMVert *elem_vert = vtable[lverts[index_lvert]]; \
(void)elem_vert; /* Quiet warning when unused. */ \
{
#define EXTRACT_LVERT_FOREACH_BM_END \
} \
} \
}
typedef struct ExtractLVertMesh_Params {
const int *lvert;
int lvert_range[2];
} ExtractLVertMesh_Params;
typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
const MVert *mv,
const int lvert_index,
void *data);
#define EXTRACT_LVERT_FOREACH_MESH_BEGIN(elem, index_lvert, params, mr) \
CHECK_TYPE(params, const ExtractLVertMesh_Params *); \
{ \
const MVert *mvert = mr->mvert; \
const int *lverts = (params)->lvert; \
const int _lvert_index_end = (params)->lvert_range[1]; \
for (int index_lvert = (params)->lvert_range[0]; index_lvert < _lvert_index_end; \
index_lvert += 1) { \
const MVert *elem = &mvert[lverts[index_lvert]]; \
(void)elem; /* Quiet warning when unused. */ \
{
#define EXTRACT_LVERT_FOREACH_MESH_END \
} \
} \
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Mesh Elements Extract Struct
* \{ */
/* TODO(jbakker): move parameters inside a struct. */
typedef void *(ExtractInitFn)(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buffer);
typedef void(ExtractTriBMeshFn)(const MeshRenderData *mr,
BMLoop **elt,
const int elt_index,
void *data);
typedef void(ExtractTriMeshFn)(const MeshRenderData *mr,
const MLoopTri *mlt,
const int elt_index,
void *data);
typedef void(ExtractPolyBMeshFn)(const MeshRenderData *mr,
const BMFace *f,
const int f_index,
void *data);
typedef void(ExtractPolyMeshFn)(const MeshRenderData *mr,
const MPoly *mp,
const int mp_index,
void *data);
typedef void(ExtractLEdgeBMeshFn)(const MeshRenderData *mr,
const BMEdge *eed,
const int ledge_index,
void *data);
typedef void(ExtractLEdgeMeshFn)(const MeshRenderData *mr,
const MEdge *med,
const int ledge_index,
void *data);
typedef void(ExtractLVertBMeshFn)(const MeshRenderData *mr,
const BMVert *eve,
const int lvert_index,
void *data);
typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr,
const MVert *mv,
const int lvert_index,
void *data);
typedef void(ExtractInitFn)(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buffer,
void *r_data);
typedef void(ExtractFinishFn)(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buffer,
void *data);
typedef void *(ExtractTaskInitFn)(void *userdata);
typedef void(ExtractTaskInitFn)(void *userdata, void *r_task_userdata);
typedef void(ExtractTaskFinishFn)(void *userdata, void *task_userdata);
typedef struct MeshExtract {
/** Executed on main thread and return user data for iteration functions. */
ExtractInitFn *init;
/** Task local data. */
ExtractTaskInitFn *task_init;
/** Executed on one (or more if use_threading) worker thread(s). */
ExtractTriBMeshFn *iter_looptri_bm;
ExtractTriMeshFn *iter_looptri_mesh;
@ -432,10 +210,11 @@ typedef struct MeshExtract {
ExtractLVertBMeshFn *iter_lvert_bm;
ExtractLVertMeshFn *iter_lvert_mesh;
/** Executed on one worker thread after all elements iterations. */
ExtractTaskFinishFn *task_finish;
ExtractTaskFinishFn *task_reduce;
ExtractFinishFn *finish;
/** Used to request common data. */
eMRDataType data_type;
size_t data_size;
/** Used to know if the element callbacks are thread-safe and can be parallelized. */
bool use_threading;
/**

View File

@ -37,15 +37,14 @@ struct MeshExtract_EditUvElem_Data {
bool sync_selection;
};
static void *extract_edituv_tris_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo))
static void extract_edituv_tris_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(
MEM_callocN(sizeof(*data), __func__));
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, mr->tri_len, mr->loop_len);
data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
return data;
}
BLI_INLINE void edituv_tri_add(
@ -93,7 +92,6 @@ static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr),
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(&data->elb, ibo);
MEM_freeN(data);
}
constexpr MeshExtract create_extractor_edituv_tris()
@ -104,6 +102,7 @@ constexpr MeshExtract create_extractor_edituv_tris()
extractor.iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh;
extractor.finish = extract_edituv_tris_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_tris);
return extractor;
@ -115,15 +114,14 @@ constexpr MeshExtract create_extractor_edituv_tris()
/** \name Extract Edit UV Line Indices around faces
* \{ */
static void *extract_edituv_lines_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo))
static void extract_edituv_lines_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(
MEM_callocN(sizeof(*data), __func__));
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES, mr->loop_len, mr->loop_len);
data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
return data;
}
BLI_INLINE void edituv_edge_add(
@ -135,7 +133,7 @@ BLI_INLINE void edituv_edge_add(
}
static void extract_edituv_lines_iter_poly_bm(const MeshRenderData *UNUSED(mr),
BMFace *f,
const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@ -184,7 +182,6 @@ static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr),
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(&data->elb, ibo);
MEM_freeN(data);
}
constexpr MeshExtract create_extractor_edituv_lines()
@ -195,6 +192,7 @@ constexpr MeshExtract create_extractor_edituv_lines()
extractor.iter_poly_mesh = extract_edituv_lines_iter_poly_mesh;
extractor.finish = extract_edituv_lines_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_lines);
return extractor;
@ -206,15 +204,14 @@ constexpr MeshExtract create_extractor_edituv_lines()
/** \name Extract Edit UV Points Indices
* \{ */
static void *extract_edituv_points_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo))
static void extract_edituv_points_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(
MEM_callocN(sizeof(*data), __func__));
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
GPU_indexbuf_init(&data->elb, GPU_PRIM_POINTS, mr->loop_len, mr->loop_len);
data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
return data;
}
BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data,
@ -228,7 +225,7 @@ BLI_INLINE void edituv_point_add(MeshExtract_EditUvElem_Data *data,
}
static void extract_edituv_points_iter_poly_bm(const MeshRenderData *UNUSED(mr),
BMFace *f,
const BMFace *f,
const int UNUSED(f_index),
void *_data)
{
@ -269,7 +266,6 @@ static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr),
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(&data->elb, ibo);
MEM_freeN(data);
}
constexpr MeshExtract create_extractor_edituv_points()
@ -280,6 +276,7 @@ constexpr MeshExtract create_extractor_edituv_points()
extractor.iter_poly_mesh = extract_edituv_points_iter_poly_mesh;
extractor.finish = extract_edituv_points_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_points);
return extractor;
@ -291,15 +288,14 @@ constexpr MeshExtract create_extractor_edituv_points()
/** \name Extract Edit UV Face-dots Indices
* \{ */
static void *extract_edituv_fdots_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo))
static void extract_edituv_fdots_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(
MEM_callocN(sizeof(*data), __func__));
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data);
GPU_indexbuf_init(&data->elb, GPU_PRIM_POINTS, mr->poly_len, mr->poly_len);
data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0;
return data;
}
BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data,
@ -316,7 +312,7 @@ BLI_INLINE void edituv_facedot_add(MeshExtract_EditUvElem_Data *data,
}
static void extract_edituv_fdots_iter_poly_bm(const MeshRenderData *UNUSED(mr),
BMFace *f,
const BMFace *f,
const int f_index,
void *_data)
{
@ -366,7 +362,6 @@ static void extract_edituv_fdots_finish(const MeshRenderData *UNUSED(mr),
MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(&data->elb, ibo);
MEM_freeN(data);
}
constexpr MeshExtract create_extractor_edituv_fdots()
@ -377,6 +372,7 @@ constexpr MeshExtract create_extractor_edituv_fdots()
extractor.iter_poly_mesh = extract_edituv_fdots_iter_poly_mesh;
extractor.finish = extract_edituv_fdots_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUvElem_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.edituv_fdots);
return extractor;

View File

@ -32,17 +32,17 @@ namespace blender::draw {
/** \name Extract Face-dots Indices
* \{ */
static void *extract_fdots_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf))
static void extract_fdots_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(MEM_mallocN(sizeof(*elb), __func__));
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
GPU_indexbuf_init(elb, GPU_PRIM_POINTS, mr->poly_len, mr->poly_len);
return elb;
}
static void extract_fdots_iter_poly_bm(const MeshRenderData *UNUSED(mr),
BMFace *f,
const BMFace *f,
const int f_index,
void *_userdata)
{
@ -93,7 +93,6 @@ static void extract_fdots_finish(const MeshRenderData *UNUSED(mr),
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(elb, ibo);
MEM_freeN(elb);
}
constexpr MeshExtract create_extractor_fdots()
@ -104,6 +103,7 @@ constexpr MeshExtract create_extractor_fdots()
extractor.iter_poly_mesh = extract_fdots_iter_poly_mesh;
extractor.finish = extract_fdots_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.fdots);
return extractor;

View File

@ -31,28 +31,19 @@ namespace blender::draw {
/** \name Extract Edges Indices
* \{ */
static void *extract_lines_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf))
static void extract_lines_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(MEM_mallocN(sizeof(*elb), __func__));
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
/* Put loose edges at the end. */
GPU_indexbuf_init(
elb, GPU_PRIM_LINES, mr->edge_len + mr->edge_loose_len, mr->loop_len + mr->loop_loose_len);
return elb;
}
static void *extract_lines_task_init(void *_userdata)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(
MEM_mallocN(sizeof(*sub_builder), __func__));
GPU_indexbuf_subbuilder_init(elb, sub_builder);
return sub_builder;
}
static void extract_lines_iter_poly_bm(const MeshRenderData *UNUSED(mr),
BMFace *f,
const BMFace *f,
const int UNUSED(f_index),
void *data)
{
@ -109,7 +100,7 @@ static void extract_lines_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_lines_iter_ledge_bm(const MeshRenderData *mr,
BMEdge *eed,
const BMEdge *eed,
const int ledge_index,
void *data)
{
@ -147,12 +138,11 @@ static void extract_lines_iter_ledge_mesh(const MeshRenderData *mr,
GPU_indexbuf_set_line_restart(elb, e_index);
}
static void extract_lines_task_finish(void *_userdata, void *_task_userdata)
static void extract_lines_task_finish(void *_userdata_to, void *_userdata_from)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(_task_userdata);
GPU_indexbuf_subbuilder_finish(elb, sub_builder);
MEM_freeN(sub_builder);
GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to);
GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from);
GPU_indexbuf_join_copies(elb_to, elb_from);
}
static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
@ -163,21 +153,20 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr),
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(elb, ibo);
MEM_freeN(elb);
}
constexpr MeshExtract create_extractor_lines()
{
MeshExtract extractor = {0};
extractor.init = extract_lines_init;
extractor.task_init = extract_lines_task_init;
extractor.iter_poly_bm = extract_lines_iter_poly_bm;
extractor.iter_poly_mesh = extract_lines_iter_poly_mesh;
extractor.iter_ledge_bm = extract_lines_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh;
extractor.task_finish = extract_lines_task_finish;
extractor.task_reduce = extract_lines_task_finish;
extractor.finish = extract_lines_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines);
return extractor;
@ -209,21 +198,20 @@ static void extract_lines_with_lines_loose_finish(const MeshRenderData *mr,
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(elb, ibo);
extract_lines_loose_subbuffer(mr, cache);
MEM_freeN(elb);
}
constexpr MeshExtract create_extractor_lines_with_lines_loose()
{
MeshExtract extractor = {0};
extractor.init = extract_lines_init;
extractor.task_init = extract_lines_task_init;
extractor.iter_poly_bm = extract_lines_iter_poly_bm;
extractor.iter_poly_mesh = extract_lines_iter_poly_mesh;
extractor.iter_ledge_bm = extract_lines_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh;
extractor.task_finish = extract_lines_task_finish;
extractor.task_reduce = extract_lines_task_finish;
extractor.finish = extract_lines_with_lines_loose_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines);
return extractor;
@ -235,14 +223,14 @@ constexpr MeshExtract create_extractor_lines_with_lines_loose()
/** \name Extract Loose Edges Sub Buffer
* \{ */
static void *extract_lines_loose_only_init(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buf)
static void extract_lines_loose_only_init(const MeshRenderData *mr,
struct MeshBatchCache *cache,
void *buf,
void *UNUSED(tls_data))
{
BLI_assert(buf == cache->final.ibo.lines_loose);
UNUSED_VARS_NDEBUG(buf);
extract_lines_loose_subbuffer(mr, cache);
return NULL;
}
constexpr MeshExtract create_extractor_lines_loose_only()
@ -250,6 +238,7 @@ constexpr MeshExtract create_extractor_lines_loose_only()
MeshExtract extractor = {0};
extractor.init = extract_lines_loose_only_init;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = 0;
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_loose);
return extractor;

View File

@ -41,26 +41,25 @@ struct MeshExtract_LineAdjacency_Data {
EdgeHash *eh;
bool is_manifold;
/* Array to convert vert index to any loop index of this vert. */
uint vert_to_loop[0];
uint *vert_to_loop;
};
static void *extract_lines_adjacency_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf))
static void extract_lines_adjacency_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
/* Similar to poly_to_tri_count().
* There is always (loop + triangle - 1) edges inside a polygon.
* Accumulate for all polys and you get : */
uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len;
size_t vert_to_loop_size = sizeof(uint) * mr->vert_len;
MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(tls_data);
data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * mr->vert_len, __func__));
MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(
MEM_callocN(sizeof(*data) + vert_to_loop_size, __func__));
GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len);
data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
data->is_manifold = true;
return data;
}
BLI_INLINE void lines_adjacency_triangle(
@ -169,7 +168,7 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr),
cache->is_manifold = data->is_manifold;
GPU_indexbuf_build_in_place(&data->elb, ibo);
MEM_freeN(data);
MEM_freeN(data->vert_to_loop);
}
#undef NO_EDGE
@ -184,6 +183,7 @@ constexpr MeshExtract create_extractor_lines_adjacency()
extractor.iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh;
extractor.finish = extract_lines_adjacency_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_LineAdjacency_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_adjacency);
return extractor;

View File

@ -37,18 +37,17 @@ namespace blender::draw {
struct MeshExtract_LinePaintMask_Data {
GPUIndexBufBuilder elb;
/** One bit per edge set if face is selected. */
BLI_bitmap select_map[0];
BLI_bitmap *select_map;
};
static void *extract_lines_paint_mask_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo))
static void extract_lines_paint_mask_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
size_t bitmap_size = BLI_BITMAP_SIZE(mr->edge_len);
MeshExtract_LinePaintMask_Data *data = static_cast<MeshExtract_LinePaintMask_Data *>(
MEM_callocN(sizeof(*data) + bitmap_size, __func__));
MeshExtract_LinePaintMask_Data *data = static_cast<MeshExtract_LinePaintMask_Data *>(tls_data);
data->select_map = BLI_BITMAP_NEW(mr->edge_len, __func__);
GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES, mr->edge_len, mr->loop_len);
return data;
}
static void extract_lines_paint_mask_iter_poly_mesh(const MeshRenderData *mr,
@ -101,7 +100,7 @@ static void extract_lines_paint_mask_finish(const MeshRenderData *UNUSED(mr),
MeshExtract_LinePaintMask_Data *data = static_cast<MeshExtract_LinePaintMask_Data *>(_data);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(&data->elb, ibo);
MEM_freeN(data);
MEM_freeN(data->select_map);
}
/** \} */
@ -113,6 +112,7 @@ constexpr MeshExtract create_extractor_lines_paint_mask()
extractor.iter_poly_mesh = extract_lines_paint_mask_iter_poly_mesh;
extractor.finish = extract_lines_paint_mask_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_LinePaintMask_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.lines_paint_mask);
return extractor;

View File

@ -32,25 +32,16 @@ namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Point Indices
* \{ */
static void *extract_points_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf))
static void extract_points_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(buf),
void *tls_data)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(MEM_mallocN(sizeof(*elb), __func__));
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
GPU_indexbuf_init(elb, GPU_PRIM_POINTS, mr->vert_len, mr->loop_len + mr->loop_loose_len);
return elb;
}
static void *extract_points_task_init(void *_userdata)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(
MEM_mallocN(sizeof(*sub_builder), __func__));
GPU_indexbuf_subbuilder_init(elb, sub_builder);
return sub_builder;
}
BLI_INLINE void vert_set_bm(GPUIndexBufBuilder *elb, BMVert *eve, int l_index)
BLI_INLINE void vert_set_bm(GPUIndexBufBuilder *elb, const BMVert *eve, int l_index)
{
const int v_index = BM_elem_index_get(eve);
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
@ -78,7 +69,7 @@ BLI_INLINE void vert_set_mesh(GPUIndexBufBuilder *elb,
}
static void extract_points_iter_poly_bm(const MeshRenderData *UNUSED(mr),
BMFace *f,
const BMFace *f,
const int UNUSED(f_index),
void *_userdata)
{
@ -107,7 +98,7 @@ static void extract_points_iter_poly_mesh(const MeshRenderData *mr,
}
static void extract_points_iter_ledge_bm(const MeshRenderData *mr,
BMEdge *eed,
const BMEdge *eed,
const int ledge_index,
void *_userdata)
{
@ -127,7 +118,7 @@ static void extract_points_iter_ledge_mesh(const MeshRenderData *mr,
}
static void extract_points_iter_lvert_bm(const MeshRenderData *mr,
BMVert *eve,
const BMVert *eve,
const int lvert_index,
void *_userdata)
{
@ -146,12 +137,11 @@ static void extract_points_iter_lvert_mesh(const MeshRenderData *mr,
vert_set_mesh(elb, mr, mr->lverts[lvert_index], offset + lvert_index);
}
static void extract_points_task_finish(void *_userdata, void *_task_userdata)
static void extract_points_task_finish(void *_userdata_to, void *_userdata_from)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(_task_userdata);
GPU_indexbuf_subbuilder_finish(elb, sub_builder);
MEM_freeN(sub_builder);
GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to);
GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from);
GPU_indexbuf_join_copies(elb_to, elb_from);
}
static void extract_points_finish(const MeshRenderData *UNUSED(mr),
@ -162,24 +152,23 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr),
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
GPU_indexbuf_build_in_place(elb, ibo);
MEM_freeN(elb);
}
constexpr MeshExtract create_extractor_points()
{
MeshExtract extractor = {0};
extractor.init = extract_points_init;
extractor.task_init = extract_points_task_init;
extractor.iter_poly_bm = extract_points_iter_poly_bm;
extractor.iter_poly_mesh = extract_points_iter_poly_mesh;
extractor.iter_ledge_bm = extract_points_iter_ledge_bm;
extractor.iter_ledge_mesh = extract_points_iter_ledge_mesh;
extractor.iter_lvert_bm = extract_points_iter_lvert_bm;
extractor.iter_lvert_mesh = extract_points_iter_lvert_mesh;
extractor.task_finish = extract_points_task_finish;
extractor.task_reduce = extract_points_task_finish;
extractor.finish = extract_points_finish;
extractor.use_threading = true;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.points);
return extractor;
}

View File

@ -37,12 +37,12 @@ struct MeshExtract_Tri_Data {
int *tri_mat_end;
};
static void *extract_tris_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo))
static void extract_tris_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(
MEM_callocN(sizeof(*data), __func__));
MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(tls_data);
size_t mat_tri_idx_size = sizeof(int) * mr->mat_len;
data->tri_mat_start = static_cast<int *>(MEM_callocN(mat_tri_idx_size, __func__));
@ -82,8 +82,6 @@ static void *extract_tris_init(const MeshRenderData *mr,
int visible_tri_tot = ofs;
GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, visible_tri_tot, mr->loop_len);
return data;
}
static void extract_tris_iter_looptri_bm(const MeshRenderData *mr,
@ -150,7 +148,6 @@ static void extract_tris_finish(const MeshRenderData *mr,
}
MEM_freeN(data->tri_mat_start);
MEM_freeN(data->tri_mat_end);
MEM_freeN(data);
}
constexpr MeshExtract create_extractor_tris()
@ -161,6 +158,7 @@ constexpr MeshExtract create_extractor_tris()
extractor.iter_looptri_mesh = extract_tris_iter_looptri_mesh;
extractor.finish = extract_tris_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_Tri_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris);
return extractor;
@ -171,22 +169,13 @@ constexpr MeshExtract create_extractor_tris()
/** \name Extract Triangles Indices (single material)
* \{ */
static void *extract_tris_single_mat_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo))
static void extract_tris_single_mat_init(const MeshRenderData *mr,
struct MeshBatchCache *UNUSED(cache),
void *UNUSED(ibo),
void *tls_data)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(MEM_mallocN(sizeof(*elb), __func__));
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr->tri_len, mr->loop_len);
return elb;
}
static void *extract_tris_single_mat_task_init(void *_userdata)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(
MEM_mallocN(sizeof(*sub_builder), __func__));
GPU_indexbuf_subbuilder_init(elb, sub_builder);
return sub_builder;
}
static void extract_tris_single_mat_iter_looptri_bm(const MeshRenderData *UNUSED(mr),
@ -222,12 +211,11 @@ static void extract_tris_single_mat_iter_looptri_mesh(const MeshRenderData *mr,
}
}
static void extract_tris_single_mat_task_finish(void *_userdata, void *_task_userdata)
static void extract_tris_single_mat_task_finish(void *_userdata_to, void *_userdata_from)
{
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata);
GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>(_task_userdata);
GPU_indexbuf_subbuilder_finish(elb, sub_builder);
MEM_freeN(sub_builder);
GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to);
GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from);
GPU_indexbuf_join_copies(elb_to, elb_from);
}
static void extract_tris_single_mat_finish(const MeshRenderData *mr,
@ -254,19 +242,18 @@ static void extract_tris_single_mat_finish(const MeshRenderData *mr,
GPU_indexbuf_create_subrange_in_place(mbc->tris_per_mat[i], ibo, 0, len);
}
}
MEM_freeN(elb);
}
constexpr MeshExtract create_extractor_tris_single_mat()
{
MeshExtract extractor = {0};
extractor.init = extract_tris_single_mat_init;
extractor.task_init = extract_tris_single_mat_task_init;
extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm;
extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh;
extractor.task_finish = extract_tris_single_mat_task_finish;
extractor.task_reduce = extract_tris_single_mat_task_finish;
extractor.finish = extract_tris_single_mat_finish;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(GPUIndexBufBuilder);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris);
return extractor;

View File

@ -44,7 +44,6 @@ typedef struct GPUIndexBufBuilder {
uint index_max;
GPUPrimType prim_type;
uint32_t *data;
const struct GPUIndexBufBuilder *parent;
} GPUIndexBufBuilder;
/* supports all primitive types. */
@ -55,17 +54,12 @@ void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint ve
GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len);
/*
* Thread safe sub builders.
* Thread safe.
*
* Note that `GPU_indexbuf_subbuilder_init` and `GPU_indexbuf_subbuilder_finish` are not thread
* safe and should be called when no threads are active. The pattern is to create a subbuilder for
* each thread/task. Each thread/task would update their sub builder. When all thread are completed
* the sub-builders can then be merged back to the parent builder.
* Function inspired by the reduction directives of multithread work APIs..
*/
void GPU_indexbuf_subbuilder_init(const GPUIndexBufBuilder *parent_builder,
GPUIndexBufBuilder *sub_builder);
void GPU_indexbuf_subbuilder_finish(GPUIndexBufBuilder *builder,
const GPUIndexBufBuilder *parent_builder);
void GPU_indexbuf_join_copies(GPUIndexBufBuilder *builder,
const GPUIndexBufBuilder *parent_builder);
void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *, uint v);
void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *);

View File

@ -57,7 +57,6 @@ void GPU_indexbuf_init_ex(GPUIndexBufBuilder *builder,
builder->index_max = 0;
builder->prim_type = prim_type;
builder->data = (uint *)MEM_callocN(builder->max_index_len * sizeof(uint), "GPUIndexBuf data");
builder->parent = nullptr;
}
void GPU_indexbuf_init(GPUIndexBufBuilder *builder,
@ -80,21 +79,13 @@ GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len)
return elem_;
}
void GPU_indexbuf_subbuilder_init(const GPUIndexBufBuilder *parent_builder,
GPUIndexBufBuilder *sub_builder)
void GPU_indexbuf_join_copies(GPUIndexBufBuilder *builder_to,
const GPUIndexBufBuilder *builder_from)
{
BLI_assert(parent_builder->parent == nullptr);
memcpy(sub_builder, parent_builder, sizeof(GPUIndexBufBuilder));
sub_builder->parent = parent_builder;
}
void GPU_indexbuf_subbuilder_finish(GPUIndexBufBuilder *parent_builder,
const GPUIndexBufBuilder *sub_builder)
{
BLI_assert(parent_builder == sub_builder->parent);
parent_builder->index_len = max_uu(parent_builder->index_len, sub_builder->index_len);
parent_builder->index_min = min_uu(parent_builder->index_min, sub_builder->index_min);
parent_builder->index_max = max_uu(parent_builder->index_max, sub_builder->index_max);
BLI_assert(builder_to->data == builder_from->data);
builder_to->index_len = max_uu(builder_to->index_len, builder_from->index_len);
builder_to->index_min = min_uu(builder_to->index_min, builder_from->index_min);
builder_to->index_max = max_uu(builder_to->index_max, builder_from->index_max);
}
void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *builder, uint v)

@ -1 +1 @@
Subproject commit 01f51a0e551ab730f0934dc6488613690ac4bf8f
Subproject commit 2afbb8ec472cac5102eb239f57b006f8c9387685