From 98c662672998a16a7ac00ab283357de17f3ae54c Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 1 Jun 2021 12:12:13 +0200 Subject: DrawManager: Use CPP for Mesh Extraction Scheduling. More cleanups will come to make this more CPP-like. --- source/blender/draw/CMakeLists.txt | 2 +- source/blender/draw/intern/draw_cache_extract.h | 11 +- .../blender/draw/intern/draw_cache_extract_mesh.c | 987 ------------------- .../blender/draw/intern/draw_cache_extract_mesh.cc | 1006 ++++++++++++++++++++ .../draw/intern/draw_cache_extract_mesh_private.h | 8 + 5 files changed, 1025 insertions(+), 989 deletions(-) delete mode 100644 source/blender/draw/intern/draw_cache_extract_mesh.c create mode 100644 source/blender/draw/intern/draw_cache_extract_mesh.cc diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index adbe7fdf274..d6598bf79b0 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -53,7 +53,7 @@ set(SRC intern/draw_cache.c intern/draw_cache_extract_mesh_extractors.c intern/draw_cache_extract_mesh_render_data.c - intern/draw_cache_extract_mesh.c + intern/draw_cache_extract_mesh.cc intern/draw_cache_impl_curve.cc intern/draw_cache_impl_displist.c intern/draw_cache_impl_gpencil.c diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index abba3aeeb70..36756616ca7 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -68,13 +68,13 @@ typedef struct DRW_MeshCDMask { * bit-wise and atomic operations are used to compare and update the struct. * See `mesh_cd_layers_type_*` functions. */ BLI_STATIC_ASSERT(sizeof(DRW_MeshCDMask) <= sizeof(uint64_t), "DRW_MeshCDMask exceeds 64 bits") - typedef enum eMRIterType { MR_ITER_LOOPTRI = 1 << 0, MR_ITER_POLY = 1 << 1, MR_ITER_LEDGE = 1 << 2, MR_ITER_LVERT = 1 << 3, } eMRIterType; +ENUM_OPERATORS(eMRIterType, MR_ITER_LVERT) typedef enum eMRDataType { MR_DATA_POLY_NOR = 1 << 1, @@ -83,6 +83,11 @@ typedef enum eMRDataType { /** Force loop normals calculation. */ MR_DATA_TAN_LOOP_NOR = 1 << 4, } eMRDataType; +ENUM_OPERATORS(eMRDataType, MR_DATA_TAN_LOOP_NOR) + +#ifdef __cplusplus +extern "C" { +#endif BLI_INLINE int mesh_render_mat_len_get(Mesh *me) { @@ -298,3 +303,7 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, const Scene *scene, const ToolSettings *ts, const bool use_hide); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.c b/source/blender/draw/intern/draw_cache_extract_mesh.c deleted file mode 100644 index 0d2a4704b1b..00000000000 --- a/source/blender/draw/intern/draw_cache_extract_mesh.c +++ /dev/null @@ -1,987 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2017 by Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup draw - * - * \brief Extraction of Mesh data into VBO to feed to GPU. - */ -#include "MEM_guardedalloc.h" - -#include "atomic_ops.h" - -#include "DNA_mesh_types.h" -#include "DNA_scene_types.h" - -#include "BLI_task.h" - -#include "BKE_editmesh.h" - -#include "GPU_capabilities.h" - -#include "draw_cache_extract.h" -#include "draw_cache_extract_mesh_private.h" -#include "draw_cache_inline.h" - -// #define DEBUG_TIME - -#ifdef DEBUG_TIME -# include "PIL_time_utildefines.h" -#endif - -#define CHUNK_SIZE 8192 - -/* ---------------------------------------------------------------------- */ -/** \name Mesh Elements Extract Struct - * \{ */ - -typedef struct MeshExtractRunData { - const MeshExtract *extractor; - void *buffer; - void *user_data; -} MeshExtractRunData; - -typedef struct MeshExtractRunDataArray { - int len; - MeshExtractRunData items[M_EXTRACT_LEN]; -} MeshExtractRunDataArray; - -static void mesh_extract_run_data_array_init(MeshExtractRunDataArray *array) -{ - array->len = 0; -} - -static void mesh_extract_run_data_array_add_ex(MeshExtractRunDataArray *array, - const MeshExtractRunData *run_data) -{ - array->items[array->len] = *run_data; - array->len++; -} - -static void mesh_extract_run_data_array_add(MeshExtractRunDataArray *array, - const MeshExtract *extractor) -{ - MeshExtractRunData run_data; - run_data.extractor = extractor; - run_data.buffer = NULL; - run_data.user_data = NULL; - mesh_extract_run_data_array_add_ex(array, &run_data); -} - -static void mesh_extract_run_data_array_filter_iter_type(const MeshExtractRunDataArray *src, - MeshExtractRunDataArray *dst, - eMRIterType iter_type) -{ - for (int i = 0; i < src->len; i++) { - - const MeshExtractRunData *data = &src->items[i]; - const MeshExtract *extractor = data->extractor; - if ((iter_type & MR_ITER_LOOPTRI) && extractor->iter_looptri_bm) { - BLI_assert(extractor->iter_looptri_mesh); - mesh_extract_run_data_array_add_ex(dst, data); - continue; - } - if ((iter_type & MR_ITER_POLY) && extractor->iter_poly_bm) { - BLI_assert(extractor->iter_poly_mesh); - mesh_extract_run_data_array_add_ex(dst, data); - continue; - } - if ((iter_type & MR_ITER_LEDGE) && extractor->iter_ledge_bm) { - BLI_assert(extractor->iter_ledge_mesh); - mesh_extract_run_data_array_add_ex(dst, data); - continue; - } - if ((iter_type & MR_ITER_LVERT) && extractor->iter_lvert_bm) { - BLI_assert(extractor->iter_lvert_mesh); - mesh_extract_run_data_array_add_ex(dst, data); - continue; - } - } -} - -static void mesh_extract_run_data_array_filter_threading( - const MeshExtractRunDataArray *src, MeshExtractRunDataArray *dst_multi_threaded) -{ - for (int i = 0; i < src->len; i++) { - const MeshExtract *extractor = src->items[i].extractor; - if (extractor->use_threading) { - mesh_extract_run_data_array_add(dst_multi_threaded, extractor); - } - } -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Extract - * \{ */ - -static void extracts_flags_get(const MeshExtractRunDataArray *extractors, - eMRIterType *r_iter_type, - eMRDataType *r_data_flag) -{ - eMRIterType iter_type = 0; - eMRDataType data_flag = 0; - - for (int i = 0; i < extractors->len; i++) { - const MeshExtract *extractor = extractors->items[i].extractor; - iter_type |= mesh_extract_iter_type(extractor); - data_flag |= extractor->data_flag; - } - - if (r_iter_type) { - *r_iter_type = iter_type; - } - if (r_data_flag) { - *r_data_flag = data_flag; - } -} - -BLI_INLINE void extract_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - MeshExtractRunDataArray *extractors, - MeshBufferCache *mbc) -{ - /* Multi thread. */ - for (int i = 0; i < extractors->len; i++) { - MeshExtractRunData *run_data = &extractors->items[i]; - 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 MeshExtractRunDataArray *_extractors) -{ - MeshExtractRunDataArray extractors; - mesh_extract_run_data_array_init(&extractors); - mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LOOPTRI); - - EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, elt_index, params) - { - for (int i = 0; i < extractors.len; i++) { - MeshExtractRunData *run_data = &extractors.items[i]; - run_data->extractor->iter_looptri_bm(mr, elt, elt_index, run_data->user_data); - } - } - EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; -} - -BLI_INLINE void extract_iter_looptri_mesh(const MeshRenderData *mr, - const ExtractTriMesh_Params *params, - const MeshExtractRunDataArray *_extractors) -{ - MeshExtractRunDataArray extractors; - mesh_extract_run_data_array_init(&extractors); - mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LOOPTRI); - - EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, mlt_index, params) - { - for (int i = 0; i < extractors.len; i++) { - MeshExtractRunData *run_data = &extractors.items[i]; - run_data->extractor->iter_looptri_mesh(mr, mlt, mlt_index, run_data->user_data); - } - } - EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; -} - -BLI_INLINE void extract_iter_poly_bm(const MeshRenderData *mr, - const ExtractPolyBMesh_Params *params, - const MeshExtractRunDataArray *_extractors) -{ - MeshExtractRunDataArray extractors; - mesh_extract_run_data_array_init(&extractors); - mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_POLY); - - EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) - { - for (int i = 0; i < extractors.len; i++) { - MeshExtractRunData *run_data = &extractors.items[i]; - run_data->extractor->iter_poly_bm(mr, f, f_index, run_data->user_data); - } - } - EXTRACT_POLY_FOREACH_BM_END; -} - -BLI_INLINE void extract_iter_poly_mesh(const MeshRenderData *mr, - const ExtractPolyMesh_Params *params, - const MeshExtractRunDataArray *_extractors) -{ - MeshExtractRunDataArray extractors; - mesh_extract_run_data_array_init(&extractors); - mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_POLY); - - EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) - { - for (int i = 0; i < extractors.len; i++) { - MeshExtractRunData *run_data = &extractors.items[i]; - run_data->extractor->iter_poly_mesh(mr, mp, mp_index, run_data->user_data); - } - } - EXTRACT_POLY_FOREACH_MESH_END; -} - -BLI_INLINE void extract_iter_ledge_bm(const MeshRenderData *mr, - const ExtractLEdgeBMesh_Params *params, - const MeshExtractRunDataArray *_extractors) -{ - MeshExtractRunDataArray extractors; - mesh_extract_run_data_array_init(&extractors); - mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LEDGE); - - EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) - { - for (int i = 0; i < extractors.len; i++) { - MeshExtractRunData *run_data = &extractors.items[i]; - run_data->extractor->iter_ledge_bm(mr, eed, ledge_index, run_data->user_data); - } - } - EXTRACT_LEDGE_FOREACH_BM_END; -} - -BLI_INLINE void extract_iter_ledge_mesh(const MeshRenderData *mr, - const ExtractLEdgeMesh_Params *params, - const MeshExtractRunDataArray *_extractors) -{ - MeshExtractRunDataArray extractors; - mesh_extract_run_data_array_init(&extractors); - mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LEDGE); - - EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) - { - for (int i = 0; i < extractors.len; i++) { - MeshExtractRunData *run_data = &extractors.items[i]; - run_data->extractor->iter_ledge_mesh(mr, med, ledge_index, run_data->user_data); - } - } - EXTRACT_LEDGE_FOREACH_MESH_END; -} - -BLI_INLINE void extract_iter_lvert_bm(const MeshRenderData *mr, - const ExtractLVertBMesh_Params *params, - const MeshExtractRunDataArray *_extractors) -{ - MeshExtractRunDataArray extractors; - mesh_extract_run_data_array_init(&extractors); - mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LVERT); - - EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) - { - for (int i = 0; i < extractors.len; i++) { - MeshExtractRunData *run_data = &extractors.items[i]; - run_data->extractor->iter_lvert_bm(mr, eve, lvert_index, run_data->user_data); - } - } - EXTRACT_LVERT_FOREACH_BM_END; -} - -BLI_INLINE void extract_iter_lvert_mesh(const MeshRenderData *mr, - const ExtractLVertMesh_Params *params, - const MeshExtractRunDataArray *_extractors) -{ - MeshExtractRunDataArray extractors; - mesh_extract_run_data_array_init(&extractors); - mesh_extract_run_data_array_filter_iter_type(_extractors, &extractors, MR_ITER_LVERT); - - EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) - { - for (int i = 0; i < extractors.len; i++) { - MeshExtractRunData *run_data = &extractors.items[i]; - run_data->extractor->iter_lvert_mesh(mr, mv, lvert_index, run_data->user_data); - } - } - EXTRACT_LVERT_FOREACH_MESH_END; -} - -BLI_INLINE void extract_finish(const MeshRenderData *mr, - struct MeshBatchCache *cache, - const MeshExtractRunDataArray *extractors) -{ - for (int i = 0; i < extractors->len; i++) { - const MeshExtractRunData *run_data = &extractors->items[i]; - const MeshExtract *extractor = run_data->extractor; - if (extractor->finish) { - extractor->finish(mr, cache, run_data->buffer, run_data->user_data); - } - } -} - -/* Single Thread. */ -BLI_INLINE void extract_run_and_finish_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - MeshExtractRunDataArray *extractors, - eMRIterType iter_type, - MeshBufferCache *mbc) -{ - extract_init(mr, cache, extractors, mbc); - - bool is_mesh = mr->extract_type != MR_EXTRACT_BMESH; - if (iter_type & MR_ITER_LOOPTRI) { - if (is_mesh) { - extract_iter_looptri_mesh(mr, - &(const ExtractTriMesh_Params){ - .mlooptri = mr->mlooptri, - .tri_range = {0, mr->tri_len}, - }, - extractors); - } - else { - extract_iter_looptri_bm(mr, - &(const ExtractTriBMesh_Params){ - .looptris = mr->edit_bmesh->looptris, - .tri_range = {0, mr->tri_len}, - }, - extractors); - } - } - if (iter_type & MR_ITER_POLY) { - if (is_mesh) { - extract_iter_poly_mesh(mr, - &(const ExtractPolyMesh_Params){ - .poly_range = {0, mr->poly_len}, - }, - extractors); - } - else { - extract_iter_poly_bm(mr, - &(const ExtractPolyBMesh_Params){ - .poly_range = {0, mr->poly_len}, - }, - extractors); - } - } - if (iter_type & MR_ITER_LEDGE) { - if (is_mesh) { - extract_iter_ledge_mesh(mr, - &(const ExtractLEdgeMesh_Params){ - .ledge = mr->ledges, - .ledge_range = {0, mr->edge_loose_len}, - }, - extractors); - } - else { - extract_iter_ledge_bm(mr, - &(const ExtractLEdgeBMesh_Params){ - .ledge = mr->ledges, - .ledge_range = {0, mr->edge_loose_len}, - }, - extractors); - } - } - if (iter_type & MR_ITER_LVERT) { - if (is_mesh) { - extract_iter_lvert_mesh(mr, - &(const ExtractLVertMesh_Params){ - .lvert = mr->lverts, - .lvert_range = {0, mr->vert_loose_len}, - }, - extractors); - } - else { - extract_iter_lvert_bm(mr, - &(const ExtractLVertBMesh_Params){ - .lvert = mr->lverts, - .lvert_range = {0, mr->vert_loose_len}, - }, - extractors); - } - } - extract_finish(mr, cache, extractors); -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name ExtractTaskData - * \{ */ -typedef struct ExtractTaskData { - void *next, *prev; - const MeshRenderData *mr; - struct MeshBatchCache *cache; - MeshExtractRunDataArray *extractors; - eMRIterType iter_type; - int start, end; - /** Decremented each time a task is finished. */ - int32_t *task_counter; - MeshBufferCache *mbc; -} ExtractTaskData; - -static ExtractTaskData *extract_extract_iter_task_data_create_mesh( - const MeshRenderData *mr, - struct MeshBatchCache *cache, - MeshExtractRunDataArray *extractors, - MeshBufferCache *mbc, - int32_t *task_counter) -{ - ExtractTaskData *taskdata = MEM_mallocN(sizeof(*taskdata), __func__); - taskdata->next = NULL; - taskdata->prev = NULL; - taskdata->mr = mr; - taskdata->cache = cache; - taskdata->mbc = mbc; - - /* #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. */ - taskdata->extractors = extractors; - taskdata->task_counter = task_counter; - - extracts_flags_get(extractors, &taskdata->iter_type, NULL); - taskdata->start = 0; - taskdata->end = INT_MAX; - return taskdata; -} - -static void extract_task_data_free(void *data) -{ - ExtractTaskData *task_data = data; - MEM_SAFE_FREE(task_data->extractors); - MEM_freeN(task_data); -} - -BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, - const eMRIterType iter_type, - int start, - int end, - MeshExtractRunDataArray *extractors) -{ - switch (mr->extract_type) { - case MR_EXTRACT_BMESH: - if (iter_type & MR_ITER_LOOPTRI) { - extract_iter_looptri_bm(mr, - &(const ExtractTriBMesh_Params){ - .looptris = mr->edit_bmesh->looptris, - .tri_range = {start, min_ii(mr->tri_len, end)}, - }, - extractors); - } - if (iter_type & MR_ITER_POLY) { - extract_iter_poly_bm(mr, - &(const ExtractPolyBMesh_Params){ - .poly_range = {start, min_ii(mr->poly_len, end)}, - }, - extractors); - } - if (iter_type & MR_ITER_LEDGE) { - extract_iter_ledge_bm(mr, - &(const ExtractLEdgeBMesh_Params){ - .ledge = mr->ledges, - .ledge_range = {start, min_ii(mr->edge_loose_len, end)}, - }, - extractors); - } - if (iter_type & MR_ITER_LVERT) { - extract_iter_lvert_bm(mr, - &(const ExtractLVertBMesh_Params){ - .lvert = mr->lverts, - .lvert_range = {start, min_ii(mr->vert_loose_len, end)}, - }, - extractors); - } - break; - case MR_EXTRACT_MAPPED: - case MR_EXTRACT_MESH: - if (iter_type & MR_ITER_LOOPTRI) { - extract_iter_looptri_mesh(mr, - &(const ExtractTriMesh_Params){ - .mlooptri = mr->mlooptri, - .tri_range = {start, min_ii(mr->tri_len, end)}, - }, - extractors); - } - if (iter_type & MR_ITER_POLY) { - extract_iter_poly_mesh(mr, - &(const ExtractPolyMesh_Params){ - .poly_range = {start, min_ii(mr->poly_len, end)}, - }, - extractors); - } - if (iter_type & MR_ITER_LEDGE) { - extract_iter_ledge_mesh(mr, - &(const ExtractLEdgeMesh_Params){ - .ledge = mr->ledges, - .ledge_range = {start, min_ii(mr->edge_loose_len, end)}, - }, - extractors); - } - if (iter_type & MR_ITER_LVERT) { - extract_iter_lvert_mesh(mr, - &(const ExtractLVertMesh_Params){ - .lvert = mr->lverts, - .lvert_range = {start, min_ii(mr->vert_loose_len, end)}, - }, - extractors); - } - break; - } -} - -static void extract_task_init(ExtractTaskData *data) -{ - extract_init(data->mr, data->cache, data->extractors, data->mbc); -} - -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); - - /* 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_finish(data->mr, data->cache, data->extractors); - } -} - -static void extract_task_init_and_run(void *__restrict taskdata) -{ - ExtractTaskData *data = (ExtractTaskData *)taskdata; - extract_run_and_finish_init(data->mr, data->cache, data->extractors, data->iter_type, data->mbc); -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \name Task Node - Update Mesh Render Data - * \{ */ -typedef struct MeshRenderDataUpdateTaskData { - MeshRenderData *mr; - eMRIterType iter_type; - eMRDataType data_flag; -} MeshRenderDataUpdateTaskData; - -static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata) -{ - BLI_assert(taskdata); - MeshRenderData *mr = taskdata->mr; - mesh_render_data_free(mr); - MEM_freeN(taskdata); -} - -static void mesh_extract_render_data_node_exec(void *__restrict task_data) -{ - MeshRenderDataUpdateTaskData *update_task_data = task_data; - MeshRenderData *mr = update_task_data->mr; - const eMRIterType iter_type = update_task_data->iter_type; - const eMRDataType data_flag = update_task_data->data_flag; - - mesh_render_data_update_normals(mr, iter_type, data_flag); - mesh_render_data_update_looptris(mr, iter_type, data_flag); -} - -static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph, - MeshRenderData *mr, - const eMRIterType iter_type, - const eMRDataType data_flag) -{ - MeshRenderDataUpdateTaskData *task_data = MEM_mallocN(sizeof(MeshRenderDataUpdateTaskData), - __func__); - task_data->mr = mr; - task_data->iter_type = iter_type; - task_data->data_flag = data_flag; - - struct TaskNode *task_node = BLI_task_graph_node_create( - task_graph, - mesh_extract_render_data_node_exec, - task_data, - (TaskGraphNodeFreeFunction)mesh_render_data_update_task_data_free); - return task_node; -} - -/** \} */ - -/* ---------------------------------------------------------------------- */ -/** \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 - * \{ */ -typedef struct UserDataInitTaskData { - ExtractTaskData *td; - int32_t task_counter; - -} UserDataInitTaskData; - -static void user_data_init_task_data_free(UserDataInitTaskData *taskdata) -{ - BLI_assert(taskdata); - extract_task_data_free(taskdata->td); - MEM_freeN(taskdata); -} - -static void user_data_init_task_data_exec(void *__restrict task_data) -{ - UserDataInitTaskData *extract_task_data = 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 = MEM_dupallocN(taskdata); - atomic_add_and_fetch_int32(taskdata->task_counter, 1); - 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, MEM_freeN); - 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); - } - } -} - -void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, - MeshBatchCache *cache, - MeshBufferCache *mbc, - MeshBufferExtractionCache *extraction_cache, - Mesh *me, - - const bool is_editmode, - const bool is_paint_mode, - const bool is_mode_active, - const float obmat[4][4], - const bool do_final, - const bool do_uvedit, - const bool use_subsurf_fdots, - const DRW_MeshCDMask *cd_layer_used, - const Scene *scene, - const ToolSettings *ts, - const bool use_hide) -{ - /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph. - * This sub-graph starts with an extract_render_data_node. This fills/converts the required - * data from Mesh. - * - * Small extractions and extractions that can't be multi-threaded are grouped in a single - * `extract_single_threaded_task_node`. - * - * Other extractions will create a node for each loop exceeding 8192 items. these nodes are - * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the - * user_data needed for the extraction based on the data extracted from the mesh. - * counters are used to check if the finalize of a task has to be called. - * - * Mesh extraction sub graph - * - * +----------------------+ - * +-----> | extract_task1_loop_1 | - * | +----------------------+ - * +------------------+ +----------------------+ +----------------------+ - * | mesh_render_data | --> | | --> | extract_task1_loop_2 | - * +------------------+ | | +----------------------+ - * | | | +----------------------+ - * | | user_data_init | --> | extract_task2_loop_1 | - * v | | +----------------------+ - * +------------------+ | | +----------------------+ - * | single_threaded | | | --> | extract_task2_loop_2 | - * +------------------+ +----------------------+ +----------------------+ - * | +----------------------+ - * +-----> | extract_task2_loop_3 | - * +----------------------+ - */ - const bool do_lines_loose_subbuffer = mbc->ibo.lines_loose != NULL; - const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 || - GPU_use_hq_normals_workaround(); - - /* Create an array containing all the extractors that needs to be executed. */ - MeshExtractRunDataArray extractors; - mesh_extract_run_data_array_init(&extractors); - -#define EXTRACT_ADD_REQUESTED(type, type_lowercase, name) \ - do { \ - if (DRW_##type_lowercase##_requested(mbc->type_lowercase.name)) { \ - const MeshExtract *extractor = mesh_extract_override_get( \ - &extract_##name, do_hq_normals, do_lines_loose_subbuffer); \ - mesh_extract_run_data_array_add(&extractors, extractor); \ - } \ - } while (0) - - EXTRACT_ADD_REQUESTED(VBO, vbo, pos_nor); - EXTRACT_ADD_REQUESTED(VBO, vbo, lnor); - EXTRACT_ADD_REQUESTED(VBO, vbo, uv); - EXTRACT_ADD_REQUESTED(VBO, vbo, tan); - EXTRACT_ADD_REQUESTED(VBO, vbo, vcol); - EXTRACT_ADD_REQUESTED(VBO, vbo, sculpt_data); - EXTRACT_ADD_REQUESTED(VBO, vbo, orco); - EXTRACT_ADD_REQUESTED(VBO, vbo, edge_fac); - EXTRACT_ADD_REQUESTED(VBO, vbo, weights); - EXTRACT_ADD_REQUESTED(VBO, vbo, edit_data); - EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_data); - EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_stretch_area); - EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_stretch_angle); - EXTRACT_ADD_REQUESTED(VBO, vbo, mesh_analysis); - EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_pos); - EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_nor); - EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_uv); - EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_edituv_data); - EXTRACT_ADD_REQUESTED(VBO, vbo, poly_idx); - EXTRACT_ADD_REQUESTED(VBO, vbo, edge_idx); - EXTRACT_ADD_REQUESTED(VBO, vbo, vert_idx); - EXTRACT_ADD_REQUESTED(VBO, vbo, fdot_idx); - EXTRACT_ADD_REQUESTED(VBO, vbo, skin_roots); - - EXTRACT_ADD_REQUESTED(IBO, ibo, tris); - EXTRACT_ADD_REQUESTED(IBO, ibo, lines); - EXTRACT_ADD_REQUESTED(IBO, ibo, points); - EXTRACT_ADD_REQUESTED(IBO, ibo, fdots); - EXTRACT_ADD_REQUESTED(IBO, ibo, lines_paint_mask); - EXTRACT_ADD_REQUESTED(IBO, ibo, lines_adjacency); - EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_tris); - EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_lines); - EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_points); - EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_fdots); - -#undef EXTRACT_ADD_REQUESTED - - if (extractors.len == 0) { - return; - } - -#ifdef DEBUG_TIME - double rdata_start = PIL_check_seconds_timer(); -#endif - - eMRIterType iter_type; - eMRDataType data_flag; - extracts_flags_get(&extractors, &iter_type, &data_flag); - - MeshRenderData *mr = mesh_render_data_create(me, - extraction_cache, - is_editmode, - is_paint_mode, - is_mode_active, - obmat, - do_final, - do_uvedit, - cd_layer_used, - ts, - iter_type); - mr->use_hide = use_hide; - mr->use_subsurf_fdots = use_subsurf_fdots; - mr->use_final_mesh = do_final; - -#ifdef DEBUG_TIME - double rdata_end = PIL_check_seconds_timer(); -#endif - - struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create( - task_graph, mr, iter_type, data_flag); - - /* Simple heuristic. */ - const bool use_thread = (mr->loop_len + mr->loop_loose_len) > CHUNK_SIZE; - - if (use_thread) { - uint threads_to_use = 0; - - /* First run the requested extractors that do not support asynchronous ranges. */ - for (int i = 0; i < extractors.len; i++) { - const MeshExtract *extractor = extractors.items[i].extractor; - if (!extractor->use_threading) { - MeshExtractRunDataArray *single_threaded_extractors = MEM_callocN( - sizeof(MeshExtractRunDataArray), - "mesh_buffer_cache_create_requested.single_threaded_extractors"); - mesh_extract_run_data_array_add(single_threaded_extractors, extractor); - ExtractTaskData *taskdata = extract_extract_iter_task_data_create_mesh( - mr, cache, single_threaded_extractors, mbc, NULL); - 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); - } - threads_to_use++; - } - - /* Distribute the remaining extractors into ranges per core. */ - MeshExtractRunDataArray *multi_threaded_extractors = MEM_callocN( - sizeof(MeshExtractRunDataArray), - "mesh_buffer_cache_create_requested.multi_threaded_extractors"); - mesh_extract_run_data_array_filter_threading(&extractors, multi_threaded_extractors); - if (multi_threaded_extractors->len) { - /* - * 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(); - if (threads_to_use < num_threads) { - num_threads -= threads_to_use; - } - - UserDataInitTaskData *user_data_init_task_data = MEM_callocN( - sizeof(UserDataInitTaskData), - "mesh_buffer_cache_create_requested.user_data_init_task_data"); - 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 = extract_extract_iter_task_data_create_mesh( - mr, cache, multi_threaded_extractors, mbc, &user_data_init_task_data->task_counter); - - 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); - } - else { - /* No tasks created freeing extractors list. */ - MEM_freeN(multi_threaded_extractors); - } - } - else { - /* Run all requests on the same thread. */ - MeshExtractRunDataArray *extractors_copy = MEM_mallocN( - sizeof(MeshExtractRunDataArray), "mesh_buffer_cache_create_requested.extractors_copy"); - memcpy(extractors_copy, &extractors, sizeof(MeshExtractRunDataArray)); - ExtractTaskData *taskdata = extract_extract_iter_task_data_create_mesh( - mr, cache, extractors_copy, mbc, NULL); - - 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); - } - - /* Trigger the sub-graph for this mesh. */ - BLI_task_graph_node_push_work(task_node_mesh_render_data); - -#ifdef DEBUG_TIME - BLI_task_graph_work_and_wait(task_graph); - double end = PIL_check_seconds_timer(); - - static double avg = 0; - static double avg_fps = 0; - static double avg_rdata = 0; - static double end_prev = 0; - - if (end_prev == 0) { - end_prev = end; - } - - avg = avg * 0.95 + (end - rdata_end) * 0.05; - avg_fps = avg_fps * 0.95 + (end - end_prev) * 0.05; - avg_rdata = avg_rdata * 0.95 + (rdata_end - rdata_start) * 0.05; - - printf( - "rdata %.0fms iter %.0fms (frame %.0fms)\n", avg_rdata * 1000, avg * 1000, avg_fps * 1000); - - end_prev = end; -#endif -} - -/** \} */ diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc new file mode 100644 index 00000000000..b3ebce98524 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -0,0 +1,1006 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + * + * \brief Extraction of Mesh data into VBO to feed to GPU. + */ +#include "MEM_guardedalloc.h" + +#include "atomic_ops.h" + +#include "DNA_mesh_types.h" +#include "DNA_scene_types.h" + +#include "BLI_task.h" +#include "BLI_vector.hh" + +#include "BKE_editmesh.h" + +#include "GPU_capabilities.h" + +#include "draw_cache_extract.h" +#include "draw_cache_extract_mesh_private.h" +#include "draw_cache_inline.h" + +// #define DEBUG_TIME + +#ifdef DEBUG_TIME +# include "PIL_time_utildefines.h" +#endif + +#define CHUNK_SIZE 8192 + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Mesh Elements Extract Struct + * \{ */ + +struct MeshExtractRunData { + const MeshExtract *extractor; + void *buffer; + void *user_data; +}; + +using MeshExtractRunDataArray = blender::Vector; + +static void mesh_extract_run_data_array_add(MeshExtractRunDataArray &array, + const MeshExtract *extractor) +{ + MeshExtractRunData run_data; + run_data.extractor = extractor; + run_data.buffer = NULL; + run_data.user_data = NULL; + array.append(run_data); +} + +static void mesh_extract_run_data_array_filter_iter_type(const MeshExtractRunDataArray &src, + MeshExtractRunDataArray &dst, + eMRIterType iter_type) +{ + for (const MeshExtractRunData &data : src) { + const MeshExtract *extractor = data.extractor; + if ((iter_type & MR_ITER_LOOPTRI) && extractor->iter_looptri_bm) { + BLI_assert(extractor->iter_looptri_mesh); + dst.append(data); + continue; + } + if ((iter_type & MR_ITER_POLY) && extractor->iter_poly_bm) { + BLI_assert(extractor->iter_poly_mesh); + dst.append(data); + continue; + } + if ((iter_type & MR_ITER_LEDGE) && extractor->iter_ledge_bm) { + BLI_assert(extractor->iter_ledge_mesh); + dst.append(data); + continue; + } + if ((iter_type & MR_ITER_LVERT) && extractor->iter_lvert_bm) { + BLI_assert(extractor->iter_lvert_mesh); + dst.append(data); + continue; + } + } +} + +static void mesh_extract_run_data_array_filter_threading( + const MeshExtractRunDataArray &src, MeshExtractRunDataArray &dst_multi_threaded) +{ + for (const MeshExtractRunData &data : src) { + const MeshExtract *extractor = data.extractor; + if (extractor->use_threading) { + mesh_extract_run_data_array_add(dst_multi_threaded, extractor); + } + } +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Extract + * \{ */ + +static void extracts_flags_get(const MeshExtractRunDataArray &extractors, + eMRIterType *r_iter_type, + eMRDataType *r_data_flag) +{ + eMRIterType iter_type = static_cast(0); + eMRDataType data_flag = static_cast(0); + + for (const MeshExtractRunData &data : extractors) { + const MeshExtract *extractor = data.extractor; + iter_type |= mesh_extract_iter_type(extractor); + data_flag |= extractor->data_flag; + } + + if (r_iter_type) { + *r_iter_type = iter_type; + } + if (r_data_flag) { + *r_data_flag = data_flag; + } +} + +BLI_INLINE void extract_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + MeshExtractRunDataArray &extractors, + MeshBufferCache *mbc) +{ + /* Multi thread. */ + for (MeshExtractRunData &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 MeshExtractRunDataArray &all_extractors) +{ + MeshExtractRunDataArray extractors; + mesh_extract_run_data_array_filter_iter_type(all_extractors, extractors, MR_ITER_LOOPTRI); + + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_BEGIN(elt, elt_index, params) + { + for (MeshExtractRunData &run_data : extractors) { + run_data.extractor->iter_looptri_bm(mr, elt, elt_index, run_data.user_data); + } + } + EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; +} + +BLI_INLINE void extract_iter_looptri_mesh(const MeshRenderData *mr, + const ExtractTriMesh_Params *params, + const MeshExtractRunDataArray &all_extractors) +{ + MeshExtractRunDataArray extractors; + mesh_extract_run_data_array_filter_iter_type(all_extractors, extractors, MR_ITER_LOOPTRI); + + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_BEGIN(mlt, mlt_index, params) + { + for (MeshExtractRunData &run_data : extractors) { + run_data.extractor->iter_looptri_mesh(mr, mlt, mlt_index, run_data.user_data); + } + } + EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; +} + +BLI_INLINE void extract_iter_poly_bm(const MeshRenderData *mr, + const ExtractPolyBMesh_Params *params, + const MeshExtractRunDataArray &all_extractors) +{ + MeshExtractRunDataArray extractors; + mesh_extract_run_data_array_filter_iter_type(all_extractors, extractors, MR_ITER_POLY); + + EXTRACT_POLY_FOREACH_BM_BEGIN(f, f_index, params, mr) + { + for (MeshExtractRunData &run_data : extractors) { + run_data.extractor->iter_poly_bm(mr, f, f_index, run_data.user_data); + } + } + EXTRACT_POLY_FOREACH_BM_END; +} + +BLI_INLINE void extract_iter_poly_mesh(const MeshRenderData *mr, + const ExtractPolyMesh_Params *params, + const MeshExtractRunDataArray &all_extractors) +{ + MeshExtractRunDataArray extractors; + mesh_extract_run_data_array_filter_iter_type(all_extractors, extractors, MR_ITER_POLY); + + EXTRACT_POLY_FOREACH_MESH_BEGIN(mp, mp_index, params, mr) + { + for (MeshExtractRunData &run_data : extractors) { + run_data.extractor->iter_poly_mesh(mr, mp, mp_index, run_data.user_data); + } + } + EXTRACT_POLY_FOREACH_MESH_END; +} + +BLI_INLINE void extract_iter_ledge_bm(const MeshRenderData *mr, + const ExtractLEdgeBMesh_Params *params, + const MeshExtractRunDataArray &all_extractors) +{ + MeshExtractRunDataArray extractors; + mesh_extract_run_data_array_filter_iter_type(all_extractors, extractors, MR_ITER_LEDGE); + + EXTRACT_LEDGE_FOREACH_BM_BEGIN(eed, ledge_index, params) + { + for (MeshExtractRunData &run_data : extractors) { + run_data.extractor->iter_ledge_bm(mr, eed, ledge_index, run_data.user_data); + } + } + EXTRACT_LEDGE_FOREACH_BM_END; +} + +BLI_INLINE void extract_iter_ledge_mesh(const MeshRenderData *mr, + const ExtractLEdgeMesh_Params *params, + const MeshExtractRunDataArray &all_extractors) +{ + MeshExtractRunDataArray extractors; + mesh_extract_run_data_array_filter_iter_type(all_extractors, extractors, MR_ITER_LEDGE); + + EXTRACT_LEDGE_FOREACH_MESH_BEGIN(med, ledge_index, params, mr) + { + for (MeshExtractRunData &run_data : extractors) { + run_data.extractor->iter_ledge_mesh(mr, med, ledge_index, run_data.user_data); + } + } + EXTRACT_LEDGE_FOREACH_MESH_END; +} + +BLI_INLINE void extract_iter_lvert_bm(const MeshRenderData *mr, + const ExtractLVertBMesh_Params *params, + const MeshExtractRunDataArray &all_extractors) +{ + MeshExtractRunDataArray extractors; + mesh_extract_run_data_array_filter_iter_type(all_extractors, extractors, MR_ITER_LVERT); + + EXTRACT_LVERT_FOREACH_BM_BEGIN(eve, lvert_index, params) + { + for (MeshExtractRunData &run_data : extractors) { + run_data.extractor->iter_lvert_bm(mr, eve, lvert_index, run_data.user_data); + } + } + EXTRACT_LVERT_FOREACH_BM_END; +} + +BLI_INLINE void extract_iter_lvert_mesh(const MeshRenderData *mr, + const ExtractLVertMesh_Params *params, + const MeshExtractRunDataArray &all_extractors) +{ + MeshExtractRunDataArray extractors; + mesh_extract_run_data_array_filter_iter_type(all_extractors, extractors, MR_ITER_LVERT); + + EXTRACT_LVERT_FOREACH_MESH_BEGIN(mv, lvert_index, params, mr) + { + for (MeshExtractRunData &run_data : extractors) { + run_data.extractor->iter_lvert_mesh(mr, mv, lvert_index, run_data.user_data); + } + } + EXTRACT_LVERT_FOREACH_MESH_END; +} + +BLI_INLINE void extract_finish(const MeshRenderData *mr, + struct MeshBatchCache *cache, + const MeshExtractRunDataArray &extractors) +{ + for (const MeshExtractRunData &run_data : extractors) { + const MeshExtract *extractor = run_data.extractor; + if (extractor->finish) { + extractor->finish(mr, cache, run_data.buffer, run_data.user_data); + } + } +} + +/* Single Thread. */ +BLI_INLINE void extract_run_and_finish_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + MeshExtractRunDataArray &extractors, + eMRIterType iter_type, + MeshBufferCache *mbc) +{ + extract_init(mr, cache, extractors, mbc); + + 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, ¶ms, extractors); + } + 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, ¶ms, extractors); + } + } + 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, ¶ms, extractors); + } + else { + ExtractPolyBMesh_Params params; + params.poly_range[0] = 0; + params.poly_range[1] = mr->poly_len; + extract_iter_poly_bm(mr, ¶ms, extractors); + } + } + 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, ¶ms, extractors); + } + 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, ¶ms, extractors); + } + } + 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, ¶ms, extractors); + } + 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, ¶ms, extractors); + } + } + extract_finish(mr, cache, extractors); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name ExtractTaskData + * \{ */ +struct ExtractTaskData { + void *next = nullptr; + void *prev = nullptr; + + 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. */ + + MeshExtractRunDataArray *extractors = nullptr; + MeshBufferCache *mbc = nullptr; + int32_t *task_counter = nullptr; + + eMRIterType iter_type; + int start = 0; + int end = INT_MAX; + /** Decremented each time a task is finished. */ + + ExtractTaskData(const MeshRenderData *mr, + struct MeshBatchCache *cache, + MeshExtractRunDataArray *extractors, + MeshBufferCache *mbc, + int32_t *task_counter) + : mr(mr), cache(cache), extractors(extractors), mbc(mbc), task_counter(task_counter) + { + extracts_flags_get(*extractors, &iter_type, NULL); + }; + + ExtractTaskData(const ExtractTaskData &src) = default; + + ~ExtractTaskData() + { + delete extractors; + } + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("DRW:ExtractTaskData") +#endif +}; + +static ExtractTaskData *extract_extract_iter_task_data_create_mesh( + const MeshRenderData *mr, + MeshBatchCache *cache, + MeshExtractRunDataArray *extractors, + MeshBufferCache *mbc, + int32_t *task_counter) + +{ + ExtractTaskData *taskdata = new ExtractTaskData(mr, cache, extractors, mbc, task_counter); + return taskdata; +} + +static void extract_task_data_free(void *data) +{ + ExtractTaskData *task_data = static_cast(data); + delete task_data; +} + +static void extract_task_data_free_ex(void *data) +{ + ExtractTaskData *task_data = static_cast(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, + MeshExtractRunDataArray &extractors) +{ + 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, ¶ms, extractors); + } + 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, ¶ms, extractors); + } + 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, ¶ms, extractors); + } + 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, ¶ms, extractors); + } + 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, ¶ms, extractors); + } + 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, ¶ms, extractors); + } + 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, ¶ms, extractors); + } + 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, ¶ms, extractors); + } + break; + } +} + +static void extract_task_init(ExtractTaskData *data) +{ + extract_init(data->mr, data->cache, *data->extractors, data->mbc); +} + +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); + + /* 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_finish(data->mr, data->cache, *data->extractors); + } +} + +static void extract_task_init_and_run(void *__restrict taskdata) +{ + ExtractTaskData *data = (ExtractTaskData *)taskdata; + extract_run_and_finish_init( + data->mr, data->cache, *data->extractors, data->iter_type, data->mbc); +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \name Task Node - Update Mesh Render Data + * \{ */ +struct MeshRenderDataUpdateTaskData { + MeshRenderData *mr = nullptr; + eMRIterType iter_type; + eMRDataType data_flag; + + ~MeshRenderDataUpdateTaskData() + { + mesh_render_data_free(mr); + } + +#ifdef WITH_CXX_GUARDEDALLOC + MEM_CXX_CLASS_ALLOC_FUNCS("DRW:MeshRenderDataUpdateTaskData") +#endif +}; + +static void mesh_render_data_update_task_data_free(MeshRenderDataUpdateTaskData *taskdata) +{ + BLI_assert(taskdata); + delete taskdata; +} + +static void mesh_extract_render_data_node_exec(void *__restrict task_data) +{ + MeshRenderDataUpdateTaskData *update_task_data = static_cast( + task_data); + MeshRenderData *mr = update_task_data->mr; + const eMRIterType iter_type = update_task_data->iter_type; + const eMRDataType data_flag = update_task_data->data_flag; + + mesh_render_data_update_normals(mr, iter_type, data_flag); + mesh_render_data_update_looptris(mr, iter_type, data_flag); +} + +static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph, + MeshRenderData *mr, + const eMRIterType iter_type, + const eMRDataType data_flag) +{ + MeshRenderDataUpdateTaskData *task_data = new (MeshRenderDataUpdateTaskData); + task_data->mr = mr; + task_data->iter_type = iter_type; + task_data->data_flag = data_flag; + + struct TaskNode *task_node = BLI_task_graph_node_create( + task_graph, + mesh_extract_render_data_node_exec, + task_data, + (TaskGraphNodeFreeFunction)mesh_render_data_update_task_data_free); + return task_node; +} + +/** \} */ + +/* ---------------------------------------------------------------------- */ +/** \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; + 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(UserDataInitTaskData *taskdata) +{ + delete taskdata; +} + +static void user_data_init_task_data_exec(void *__restrict task_data) +{ + UserDataInitTaskData *extract_task_data = static_cast(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); + atomic_add_and_fetch_int32(taskdata->task_counter, 1); + 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, + MeshBufferExtractionCache *extraction_cache, + Mesh *me, + + const bool is_editmode, + const bool is_paint_mode, + const bool is_mode_active, + const float obmat[4][4], + const bool do_final, + const bool do_uvedit, + const bool use_subsurf_fdots, + const DRW_MeshCDMask *cd_layer_used, + const Scene *scene, + const ToolSettings *ts, + const bool use_hide) +{ + /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph. + * This sub-graph starts with an extract_render_data_node. This fills/converts the required + * data from Mesh. + * + * Small extractions and extractions that can't be multi-threaded are grouped in a single + * `extract_single_threaded_task_node`. + * + * Other extractions will create a node for each loop exceeding 8192 items. these nodes are + * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the + * user_data needed for the extraction based on the data extracted from the mesh. + * counters are used to check if the finalize of a task has to be called. + * + * Mesh extraction sub graph + * + * +----------------------+ + * +-----> | extract_task1_loop_1 | + * | +----------------------+ + * +------------------+ +----------------------+ +----------------------+ + * | mesh_render_data | --> | | --> | extract_task1_loop_2 | + * +------------------+ | | +----------------------+ + * | | | +----------------------+ + * | | user_data_init | --> | extract_task2_loop_1 | + * v | | +----------------------+ + * +------------------+ | | +----------------------+ + * | single_threaded | | | --> | extract_task2_loop_2 | + * +------------------+ +----------------------+ +----------------------+ + * | +----------------------+ + * +-----> | extract_task2_loop_3 | + * +----------------------+ + */ + const bool do_lines_loose_subbuffer = mbc->ibo.lines_loose != NULL; + const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 || + GPU_use_hq_normals_workaround(); + + /* Create an array containing all the extractors that needs to be executed. */ + MeshExtractRunDataArray extractors; + +#define EXTRACT_ADD_REQUESTED(type, type_lowercase, name) \ + do { \ + if (DRW_##type_lowercase##_requested(mbc->type_lowercase.name)) { \ + const MeshExtract *extractor = mesh_extract_override_get( \ + &extract_##name, do_hq_normals, do_lines_loose_subbuffer); \ + mesh_extract_run_data_array_add(extractors, extractor); \ + } \ + } while (0) + + EXTRACT_ADD_REQUESTED(VBO, vbo, pos_nor); + EXTRACT_ADD_REQUESTED(VBO, vbo, lnor); + EXTRACT_ADD_REQUESTED(VBO, vbo, uv); + EXTRACT_ADD_REQUESTED(VBO, vbo, tan); + EXTRACT_ADD_REQUESTED(VBO, vbo, vcol); + EXTRACT_ADD_REQUESTED(VBO, vbo, sculpt_data); + EXTRACT_ADD_REQUESTED(VBO, vbo, orco); + EXTRACT_ADD_REQUESTED(VBO, vbo, edge_fac); + EXTRACT_ADD_REQUESTED(VBO, vbo, weights); + EXTRACT_ADD_REQUESTED(VBO, vbo, edit_data); + EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_data); + EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_stretch_area); + EXTRACT_ADD_REQUESTED(VBO, vbo, edituv_stretch_angle); + EXTRACT_ADD_REQUESTED(VBO, vbo, mesh_analysis); + EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_pos); + EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_nor); + EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_uv); + EXTRACT_ADD_REQUESTED(VBO, vbo, fdots_edituv_data); + EXTRACT_ADD_REQUESTED(VBO, vbo, poly_idx); + EXTRACT_ADD_REQUESTED(VBO, vbo, edge_idx); + EXTRACT_ADD_REQUESTED(VBO, vbo, vert_idx); + EXTRACT_ADD_REQUESTED(VBO, vbo, fdot_idx); + EXTRACT_ADD_REQUESTED(VBO, vbo, skin_roots); + + EXTRACT_ADD_REQUESTED(IBO, ibo, tris); + EXTRACT_ADD_REQUESTED(IBO, ibo, lines); + EXTRACT_ADD_REQUESTED(IBO, ibo, points); + EXTRACT_ADD_REQUESTED(IBO, ibo, fdots); + EXTRACT_ADD_REQUESTED(IBO, ibo, lines_paint_mask); + EXTRACT_ADD_REQUESTED(IBO, ibo, lines_adjacency); + EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_tris); + EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_lines); + EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_points); + EXTRACT_ADD_REQUESTED(IBO, ibo, edituv_fdots); + +#undef EXTRACT_ADD_REQUESTED + + if (extractors.is_empty()) { + return; + } + +#ifdef DEBUG_TIME + double rdata_start = PIL_check_seconds_timer(); +#endif + + eMRIterType iter_type; + eMRDataType data_flag; + extracts_flags_get(extractors, &iter_type, &data_flag); + + MeshRenderData *mr = mesh_render_data_create(me, + extraction_cache, + is_editmode, + is_paint_mode, + is_mode_active, + obmat, + do_final, + do_uvedit, + cd_layer_used, + ts, + iter_type); + mr->use_hide = use_hide; + mr->use_subsurf_fdots = use_subsurf_fdots; + mr->use_final_mesh = do_final; + +#ifdef DEBUG_TIME + double rdata_end = PIL_check_seconds_timer(); +#endif + + struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create( + task_graph, mr, iter_type, data_flag); + + /* Simple heuristic. */ + const bool use_thread = (mr->loop_len + mr->loop_loose_len) > CHUNK_SIZE; + + if (use_thread) { + uint threads_to_use = 0; + + /* First run the requested extractors that do not support asynchronous ranges. */ + for (const MeshExtractRunData &run_data : extractors) { + const MeshExtract *extractor = run_data.extractor; + if (!extractor->use_threading) { + MeshExtractRunDataArray *single_threaded_extractors = new MeshExtractRunDataArray(); + mesh_extract_run_data_array_add(*single_threaded_extractors, extractor); + ExtractTaskData *taskdata = extract_extract_iter_task_data_create_mesh( + mr, cache, single_threaded_extractors, mbc, NULL); + 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); + } + threads_to_use++; + } + + /* Distribute the remaining extractors into ranges per core. */ + MeshExtractRunDataArray *multi_threaded_extractors = new MeshExtractRunDataArray(); + mesh_extract_run_data_array_filter_threading(extractors, *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(); + if (threads_to_use < num_threads) { + num_threads -= threads_to_use; + } + + 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 = extract_extract_iter_task_data_create_mesh( + mr, cache, multi_threaded_extractors, mbc, &user_data_init_task_data->task_counter); + + 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); + } + else { + /* No tasks created freeing extractors list. */ + delete multi_threaded_extractors; + } + } + else { + /* Run all requests on the same thread. */ + MeshExtractRunDataArray *extractors_copy = new MeshExtractRunDataArray(extractors); + ExtractTaskData *taskdata = extract_extract_iter_task_data_create_mesh( + mr, cache, extractors_copy, mbc, NULL); + + 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); + } + + /* Trigger the sub-graph for this mesh. */ + BLI_task_graph_node_push_work(task_node_mesh_render_data); + +#ifdef DEBUG_TIME + BLI_task_graph_work_and_wait(task_graph); + double end = PIL_check_seconds_timer(); + + static double avg = 0; + static double avg_fps = 0; + static double avg_rdata = 0; + static double end_prev = 0; + + if (end_prev == 0) { + end_prev = end; + } + + avg = avg * 0.95 + (end - rdata_end) * 0.05; + avg_fps = avg_fps * 0.95 + (end - end_prev) * 0.05; + avg_rdata = avg_rdata * 0.95 + (rdata_end - rdata_start) * 0.05; + + printf( + "rdata %.0fms iter %.0fms (frame %.0fms)\n", avg_rdata * 1000, avg * 1000, avg_fps * 1000); + + end_prev = end; +#endif +} + +} // namespace blender::draw + +extern "C" { +void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, + MeshBatchCache *cache, + MeshBufferCache *mbc, + MeshBufferExtractionCache *extraction_cache, + Mesh *me, + + const bool is_editmode, + const bool is_paint_mode, + const bool is_mode_active, + const float obmat[4][4], + const bool do_final, + const bool do_uvedit, + const bool use_subsurf_fdots, + const DRW_MeshCDMask *cd_layer_used, + const Scene *scene, + const ToolSettings *ts, + const bool use_hide) +{ + blender::draw::mesh_buffer_cache_create_requested(task_graph, + cache, + mbc, + extraction_cache, + me, + is_editmode, + is_paint_mode, + is_mode_active, + obmat, + do_final, + do_uvedit, + use_subsurf_fdots, + cd_layer_used, + scene, + ts, + use_hide); +} + +} // extern "C" + +/** \} */ diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_private.h b/source/blender/draw/intern/draw_cache_extract_mesh_private.h index 3360b90139d..6dd2ef4c16f 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_private.h +++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h @@ -34,6 +34,10 @@ #include "draw_cache_extract.h" +#ifdef __cplusplus +extern "C" { +#endif + typedef enum eMRExtractType { MR_EXTRACT_BMESH, MR_EXTRACT_MAPPED, @@ -507,3 +511,7 @@ extern const MeshExtract extract_poly_idx; extern const MeshExtract extract_edge_idx; extern const MeshExtract extract_vert_idx; extern const MeshExtract extract_fdot_idx; + +#ifdef __cplusplus +} +#endif -- cgit v1.2.3