diff options
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/draw/intern/draw_cache_extract_mesh.cc | 189 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_extract_mesh_private.h | 6 | ||||
-rw-r--r-- | source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc | 21 | ||||
-rw-r--r-- | source/blender/gpu/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/gpu/GPU_index_buffer.h | 14 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_index_buffer.cc | 19 | ||||
-rw-r--r-- | source/blender/gpu/tests/gpu_index_buffer_test.cc | 47 |
7 files changed, 241 insertions, 57 deletions
diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc index 8d6064179ad..7b2c0da4dd9 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -24,11 +24,15 @@ */ #include "MEM_guardedalloc.h" +#include <optional> + #include "atomic_ops.h" #include "DNA_mesh_types.h" #include "DNA_scene_types.h" +#include "BLI_array.hh" +#include "BLI_math_bits.h" #include "BLI_task.h" #include "BLI_vector.hh" @@ -53,6 +57,8 @@ namespace blender::draw { /* ---------------------------------------------------------------------- */ /** \name Mesh Elements Extract Struct * \{ */ +using TaskId = int; +using TaskLen = int; struct ExtractorRunData { /* Extractor where this run data belongs to. */ @@ -62,11 +68,23 @@ struct ExtractorRunData { /* 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; 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 @@ -111,7 +129,7 @@ class ExtractorRunDatas : public Vector<ExtractorRunData> { } } - eMRIterType iter_types() + eMRIterType iter_types() const { eMRIterType iter_type = static_cast<eMRIterType>(0); @@ -122,6 +140,13 @@ class ExtractorRunDatas : public Vector<ExtractorRunData> { return iter_type; } + const uint iter_types_len() const + { + const eMRIterType iter_type = iter_types(); + uint bits = static_cast<uint>(iter_type); + return count_bits_i(bits); + } + eMRDataType data_types() { eMRDataType data_type = static_cast<eMRDataType>(0); @@ -158,7 +183,8 @@ BLI_INLINE void extract_init(const MeshRenderData *mr, BLI_INLINE void extract_iter_looptri_bm(const MeshRenderData *mr, const ExtractTriBMesh_Params *params, - const ExtractorRunDatas &all_extractors) + const ExtractorRunDatas &all_extractors, + const TaskId task_id) { ExtractorRunDatas extractors; all_extractors.filter_into(extractors, MR_ITER_LOOPTRI); @@ -166,7 +192,7 @@ BLI_INLINE void extract_iter_looptri_bm(const MeshRenderData *mr, 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.user_data); + run_data.extractor->iter_looptri_bm(mr, elt, elt_index, run_data[task_id]); } } EXTRACT_TRIS_LOOPTRI_FOREACH_BM_END; @@ -174,7 +200,8 @@ BLI_INLINE void extract_iter_looptri_bm(const MeshRenderData *mr, BLI_INLINE void extract_iter_looptri_mesh(const MeshRenderData *mr, const ExtractTriMesh_Params *params, - const ExtractorRunDatas &all_extractors) + const ExtractorRunDatas &all_extractors, + const TaskId task_id) { ExtractorRunDatas extractors; all_extractors.filter_into(extractors, MR_ITER_LOOPTRI); @@ -182,7 +209,7 @@ BLI_INLINE void extract_iter_looptri_mesh(const MeshRenderData *mr, 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.user_data); + run_data.extractor->iter_looptri_mesh(mr, mlt, mlt_index, run_data[task_id]); } } EXTRACT_TRIS_LOOPTRI_FOREACH_MESH_END; @@ -190,7 +217,8 @@ BLI_INLINE void extract_iter_looptri_mesh(const MeshRenderData *mr, BLI_INLINE void extract_iter_poly_bm(const MeshRenderData *mr, const ExtractPolyBMesh_Params *params, - const ExtractorRunDatas &all_extractors) + const ExtractorRunDatas &all_extractors, + const TaskId task_id) { ExtractorRunDatas extractors; all_extractors.filter_into(extractors, MR_ITER_POLY); @@ -198,7 +226,7 @@ BLI_INLINE void extract_iter_poly_bm(const MeshRenderData *mr, 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.user_data); + run_data.extractor->iter_poly_bm(mr, f, f_index, run_data[task_id]); } } EXTRACT_POLY_FOREACH_BM_END; @@ -206,7 +234,8 @@ BLI_INLINE void extract_iter_poly_bm(const MeshRenderData *mr, BLI_INLINE void extract_iter_poly_mesh(const MeshRenderData *mr, const ExtractPolyMesh_Params *params, - const ExtractorRunDatas &all_extractors) + const ExtractorRunDatas &all_extractors, + const TaskId task_id) { ExtractorRunDatas extractors; all_extractors.filter_into(extractors, MR_ITER_POLY); @@ -214,7 +243,7 @@ BLI_INLINE void extract_iter_poly_mesh(const MeshRenderData *mr, 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.user_data); + run_data.extractor->iter_poly_mesh(mr, mp, mp_index, run_data[task_id]); } } EXTRACT_POLY_FOREACH_MESH_END; @@ -222,7 +251,8 @@ BLI_INLINE void extract_iter_poly_mesh(const MeshRenderData *mr, BLI_INLINE void extract_iter_ledge_bm(const MeshRenderData *mr, const ExtractLEdgeBMesh_Params *params, - const ExtractorRunDatas &all_extractors) + const ExtractorRunDatas &all_extractors, + const TaskId task_id) { ExtractorRunDatas extractors; all_extractors.filter_into(extractors, MR_ITER_LEDGE); @@ -230,7 +260,7 @@ BLI_INLINE void extract_iter_ledge_bm(const MeshRenderData *mr, 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.user_data); + run_data.extractor->iter_ledge_bm(mr, eed, ledge_index, run_data[task_id]); } } EXTRACT_LEDGE_FOREACH_BM_END; @@ -238,7 +268,8 @@ BLI_INLINE void extract_iter_ledge_bm(const MeshRenderData *mr, BLI_INLINE void extract_iter_ledge_mesh(const MeshRenderData *mr, const ExtractLEdgeMesh_Params *params, - const ExtractorRunDatas &all_extractors) + const ExtractorRunDatas &all_extractors, + const TaskId task_id) { ExtractorRunDatas extractors; all_extractors.filter_into(extractors, MR_ITER_LEDGE); @@ -246,7 +277,7 @@ BLI_INLINE void extract_iter_ledge_mesh(const MeshRenderData *mr, 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.user_data); + run_data.extractor->iter_ledge_mesh(mr, med, ledge_index, run_data[task_id]); } } EXTRACT_LEDGE_FOREACH_MESH_END; @@ -254,7 +285,8 @@ BLI_INLINE void extract_iter_ledge_mesh(const MeshRenderData *mr, BLI_INLINE void extract_iter_lvert_bm(const MeshRenderData *mr, const ExtractLVertBMesh_Params *params, - const ExtractorRunDatas &all_extractors) + const ExtractorRunDatas &all_extractors, + const TaskId task_id) { ExtractorRunDatas extractors; all_extractors.filter_into(extractors, MR_ITER_LVERT); @@ -262,7 +294,7 @@ BLI_INLINE void extract_iter_lvert_bm(const MeshRenderData *mr, 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.user_data); + run_data.extractor->iter_lvert_bm(mr, eve, lvert_index, run_data[task_id]); } } EXTRACT_LVERT_FOREACH_BM_END; @@ -270,7 +302,8 @@ BLI_INLINE void extract_iter_lvert_bm(const MeshRenderData *mr, BLI_INLINE void extract_iter_lvert_mesh(const MeshRenderData *mr, const ExtractLVertMesh_Params *params, - const ExtractorRunDatas &all_extractors) + const ExtractorRunDatas &all_extractors, + const TaskId task_id) { ExtractorRunDatas extractors; all_extractors.filter_into(extractors, MR_ITER_LVERT); @@ -278,7 +311,7 @@ BLI_INLINE void extract_iter_lvert_mesh(const MeshRenderData *mr, 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.user_data); + run_data.extractor->iter_lvert_mesh(mr, mv, lvert_index, run_data[task_id]); } } EXTRACT_LVERT_FOREACH_MESH_END; @@ -296,6 +329,35 @@ BLI_INLINE void extract_finish(const MeshRenderData *mr, } } +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, @@ -303,7 +365,11 @@ BLI_INLINE void extract_run_single_threaded(const MeshRenderData *mr, 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) { @@ -312,14 +378,14 @@ BLI_INLINE void extract_run_single_threaded(const MeshRenderData *mr, params.mlooptri = mr->mlooptri; params.tri_range[0] = 0; params.tri_range[1] = mr->tri_len; - extract_iter_looptri_mesh(mr, ¶ms, extractors); + extract_iter_looptri_mesh(mr, ¶ms, 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, ¶ms, extractors); + extract_iter_looptri_bm(mr, ¶ms, extractors, task_id); } } if (iter_type & MR_ITER_POLY) { @@ -327,13 +393,13 @@ BLI_INLINE void extract_run_single_threaded(const MeshRenderData *mr, ExtractPolyMesh_Params params; params.poly_range[0] = 0; params.poly_range[1] = mr->poly_len; - extract_iter_poly_mesh(mr, ¶ms, extractors); + extract_iter_poly_mesh(mr, ¶ms, extractors, task_id); } else { ExtractPolyBMesh_Params params; params.poly_range[0] = 0; params.poly_range[1] = mr->poly_len; - extract_iter_poly_bm(mr, ¶ms, extractors); + extract_iter_poly_bm(mr, ¶ms, extractors, task_id); } } if (iter_type & MR_ITER_LEDGE) { @@ -342,14 +408,14 @@ BLI_INLINE void extract_run_single_threaded(const MeshRenderData *mr, params.ledge = mr->ledges; params.ledge_range[0] = 0; params.ledge_range[1] = mr->edge_loose_len; - extract_iter_ledge_mesh(mr, ¶ms, extractors); + extract_iter_ledge_mesh(mr, ¶ms, 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, ¶ms, extractors); + extract_iter_ledge_bm(mr, ¶ms, extractors, task_id); } } if (iter_type & MR_ITER_LVERT) { @@ -358,16 +424,17 @@ BLI_INLINE void extract_run_single_threaded(const MeshRenderData *mr, params.lvert = mr->lverts; params.lvert_range[0] = 0; params.lvert_range[1] = mr->vert_loose_len; - extract_iter_lvert_mesh(mr, ¶ms, extractors); + extract_iter_lvert_mesh(mr, ¶ms, 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, ¶ms, extractors); + extract_iter_lvert_bm(mr, ¶ms, extractors, task_id); } } + extract_task_finish(extractors, task_len); extract_finish(mr, cache, extractors); } @@ -390,6 +457,13 @@ struct ExtractTaskData { 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; @@ -399,8 +473,14 @@ struct ExtractTaskData { struct MeshBatchCache *cache, ExtractorRunDatas *extractors, MeshBufferCache *mbc, - int32_t *task_counter) - : mr(mr), cache(cache), extractors(extractors), mbc(mbc), task_counter(task_counter) + int32_t *task_counter, + const uint task_len) + : mr(mr), + cache(cache), + extractors(extractors), + mbc(mbc), + task_counter(task_counter), + task_len(task_len) { iter_type = extractors->iter_types(); }; @@ -417,17 +497,6 @@ struct ExtractTaskData { #endif }; -static ExtractTaskData *extract_extract_iter_task_data_create_mesh(const MeshRenderData *mr, - MeshBatchCache *cache, - ExtractorRunDatas *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<ExtractTaskData *>(data); @@ -445,7 +514,8 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, const eMRIterType iter_type, int start, int end, - ExtractorRunDatas &extractors) + ExtractorRunDatas &extractors, + const TaskId task_id) { switch (mr->extract_type) { case MR_EXTRACT_BMESH: @@ -454,27 +524,27 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, 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); + extract_iter_looptri_bm(mr, ¶ms, 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, ¶ms, extractors); + extract_iter_poly_bm(mr, ¶ms, 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, ¶ms, extractors); + extract_iter_ledge_bm(mr, ¶ms, 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, ¶ms, extractors); + extract_iter_lvert_bm(mr, ¶ms, extractors, task_id); } break; case MR_EXTRACT_MAPPED: @@ -484,27 +554,27 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, 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); + extract_iter_looptri_mesh(mr, ¶ms, 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, ¶ms, extractors); + extract_iter_poly_mesh(mr, ¶ms, 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, ¶ms, extractors); + extract_iter_ledge_mesh(mr, ¶ms, 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, ¶ms, extractors); + extract_iter_lvert_mesh(mr, ¶ms, extractors, task_id); } break; } @@ -513,16 +583,19 @@ BLI_INLINE void mesh_extract_iter(const MeshRenderData *mr, static void extract_task_init(ExtractTaskData *data) { 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); + 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); } } @@ -668,7 +741,8 @@ static void extract_range_task_create(struct TaskGraph *task_graph, int length) { taskdata = new ExtractTaskData(*taskdata); - atomic_add_and_fetch_int32(taskdata->task_counter, 1); + 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; @@ -900,8 +974,8 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, if (!extractor->use_threading) { ExtractorRunDatas *single_threaded_extractors = new ExtractorRunDatas(); single_threaded_extractors->append(extractor); - ExtractTaskData *taskdata = extract_extract_iter_task_data_create_mesh( - mr, cache, single_threaded_extractors, mbc, nullptr); + 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); BLI_task_graph_edge_create(task_node_mesh_render_data, task_node); @@ -920,13 +994,19 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, */ 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; 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); + 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); @@ -941,8 +1021,7 @@ 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 = extract_extract_iter_task_data_create_mesh( - mr, cache, extractors_copy, mbc, nullptr); + ExtractTaskData *taskdata = new ExtractTaskData(mr, cache, extractors_copy, mbc, nullptr, 1); 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); 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 a1249203060..e4ea3e44843 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_private.h +++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h @@ -406,7 +406,6 @@ typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr, /* ---------------------------------------------------------------------- */ /** \name Mesh Elements Extract Struct * \{ */ - /* TODO(jbakker): move parameters inside a struct. */ typedef void *(ExtractInitFn)(const MeshRenderData *mr, struct MeshBatchCache *cache, @@ -415,10 +414,14 @@ typedef void(ExtractFinishFn)(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buffer, void *data); +typedef void *(ExtractTaskInitFn)(void *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; @@ -429,6 +432,7 @@ typedef struct MeshExtract { ExtractLVertBMeshFn *iter_lvert_bm; ExtractLVertMeshFn *iter_lvert_mesh; /** Executed on one worker thread after all elements iterations. */ + ExtractTaskFinishFn *task_finish; ExtractFinishFn *finish; /** Used to request common data. */ eMRDataType data_type; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc index d749a3ab8d1..9220198d799 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc @@ -41,6 +41,15 @@ static void *extract_points_init(const MeshRenderData *mr, 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) { const int v_index = BM_elem_index_get(eve); @@ -137,6 +146,14 @@ 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) +{ + 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); +} + static void extract_points_finish(const MeshRenderData *UNUSED(mr), struct MeshBatchCache *UNUSED(cache), void *buf, @@ -152,15 +169,17 @@ 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.finish = extract_points_finish; + extractor.use_threading = true; extractor.data_type = MR_DATA_NONE; - extractor.use_threading = false; extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.points); return extractor; } diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index cf6009c2881..8468985309f 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -394,6 +394,8 @@ if(WITH_GTESTS) if(WITH_OPENGL_DRAW_TESTS) set(TEST_SRC tests/gpu_testing.cc + + tests/gpu_index_buffer_test.cc tests/gpu_shader_test.cc tests/gpu_testing.hh diff --git a/source/blender/gpu/GPU_index_buffer.h b/source/blender/gpu/GPU_index_buffer.h index 4e8d854c7ce..03d60c60b4b 100644 --- a/source/blender/gpu/GPU_index_buffer.h +++ b/source/blender/gpu/GPU_index_buffer.h @@ -44,6 +44,7 @@ typedef struct GPUIndexBufBuilder { uint index_max; GPUPrimType prim_type; uint32_t *data; + const struct GPUIndexBufBuilder *parent; } GPUIndexBufBuilder; /* supports all primitive types. */ @@ -53,6 +54,19 @@ void GPU_indexbuf_init_ex(GPUIndexBufBuilder *, GPUPrimType, uint index_len, uin void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len); GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len); +/* + * Thread safe sub builders. + * + * 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. + */ +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_add_generic_vert(GPUIndexBufBuilder *, uint v); void GPU_indexbuf_add_primitive_restart(GPUIndexBufBuilder *); diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc index 9f283a3a944..3cdcaac5544 100644 --- a/source/blender/gpu/intern/gpu_index_buffer.cc +++ b/source/blender/gpu/intern/gpu_index_buffer.cc @@ -25,6 +25,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_math_base.h" #include "BLI_utildefines.h" #include "gpu_backend.hh" @@ -56,6 +57,7 @@ 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, @@ -78,6 +80,23 @@ GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len) return elem_; } +void GPU_indexbuf_subbuilder_init(const GPUIndexBufBuilder *parent_builder, + GPUIndexBufBuilder *sub_builder) +{ + 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); +} + void GPU_indexbuf_add_generic_vert(GPUIndexBufBuilder *builder, uint v) { #if TRUST_NO_ONE diff --git a/source/blender/gpu/tests/gpu_index_buffer_test.cc b/source/blender/gpu/tests/gpu_index_buffer_test.cc new file mode 100644 index 00000000000..ebc110056e3 --- /dev/null +++ b/source/blender/gpu/tests/gpu_index_buffer_test.cc @@ -0,0 +1,47 @@ +/* Apache License, Version 2.0 */ + +#include "testing/testing.h" + +#include "MEM_guardedalloc.h" + +#include "GPU_index_buffer.h" + +#include "gpu_testing.hh" + +namespace blender::gpu::tests { + +TEST_F(GPUTest, gpu_index_buffer_subbuilders) +{ + const uint num_subbuilders = 10; + const uint verts_per_subbuilders = 100; + const uint vertex_len = num_subbuilders * verts_per_subbuilders; + + GPUIndexBufBuilder builder; + GPU_indexbuf_init(&builder, GPU_PRIM_POINTS, vertex_len, vertex_len); + + GPUIndexBufBuilder subbuilders[num_subbuilders]; + for (int subbuilder_index = 0; subbuilder_index < num_subbuilders; subbuilder_index++) { + GPU_indexbuf_subbuilder_init(&builder, &subbuilders[subbuilder_index]); + } + + for (int subbuilder_index = 0; subbuilder_index < num_subbuilders; subbuilder_index++) { + GPUIndexBufBuilder &subbuilder = subbuilders[subbuilder_index]; + for (int subbuilder_vert_index = 0; subbuilder_vert_index < verts_per_subbuilders; + subbuilder_vert_index++) { + int vert_index_to_update = subbuilder_index * verts_per_subbuilders + subbuilder_vert_index; + GPU_indexbuf_set_point_vert(&subbuilder, vert_index_to_update, vert_index_to_update); + } + } + + for (int subbuilder_index = 0; subbuilder_index < num_subbuilders; subbuilder_index++) { + EXPECT_EQ(builder.index_len, subbuilder_index * verts_per_subbuilders); + GPU_indexbuf_subbuilder_finish(&builder, &subbuilders[subbuilder_index]); + EXPECT_EQ(builder.index_len, (subbuilder_index + 1) * verts_per_subbuilders); + } + + GPUIndexBuf *index_buffer = GPU_indexbuf_build(&builder); + EXPECT_NE(index_buffer, nullptr); + GPU_INDEXBUF_DISCARD_SAFE(index_buffer); +} + +} // namespace blender::gpu::tests |