Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Bakker <jbakker>2021-06-08 17:35:33 +0300
committerJeroen Bakker <jeroen@blender.org>2021-06-08 17:36:06 +0300
commit259b9c73d067bb51a6e86ff8eadd3de30c74e5ac (patch)
tree14c4f41174763ac222bfd2bfca7e4992d858abb4
parent08b0de45f323ee30cea2322dc7d3bc492d6518ec (diff)
GPU: Thread safe index buffer builders.
Current index builder is designed to be used in a single thread. This makes all index buffer extractions single threaded. This patch adds a thread safe solution enabling multithreaded building of index buffers. To reduce locking the solution would provide a task/thread local index buffer builder (called sub builder). When a thread is finished this thread local index buffer builder can be joined with the initial index buffer builder. `GPU_indexbuf_subbuilder_init`: Initialized a sub builder. The index list is shared between the parent and sub buffer, but the counters are localized. Ensuring that updating counters would not need any locking. `GPU_indexbuf_subbuilder_finish`: merge the information of the sub builder back to the parent builder. Needs to be invoked outside the worker thread, or when sure that all worker threads have been finished. Internal the function is not thread safe. For testing purposes the extract_points extractor has been migrated to the new API. Herefore changes to the mesh extractor were needed. * When creating tasks, the task number of current task is stored in ExtractTaskData including the total number of tasks. * Adding two functions in `MeshExtract`. ** `task_init` will initialize the task specific userdata. ** `task_finish` should merge back the task specific userdata back. * adding task_id parameter to the iteration functions so they can access the correct task data without any need for locking. There is no noticeable change in end user performance. Reviewed By: mano-wii Differential Revision: https://developer.blender.org/D11499
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh.cc189
-rw-r--r--source/blender/draw/intern/draw_cache_extract_mesh_private.h6
-rw-r--r--source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc21
-rw-r--r--source/blender/gpu/CMakeLists.txt2
-rw-r--r--source/blender/gpu/GPU_index_buffer.h14
-rw-r--r--source/blender/gpu/intern/gpu_index_buffer.cc19
-rw-r--r--source/blender/gpu/tests/gpu_index_buffer_test.cc47
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, &params, extractors);
+ extract_iter_looptri_mesh(mr, &params, extractors, task_id);
}
else {
ExtractTriBMesh_Params params;
params.looptris = mr->edit_bmesh->looptris;
params.tri_range[0] = 0;
params.tri_range[1] = mr->tri_len;
- extract_iter_looptri_bm(mr, &params, extractors);
+ extract_iter_looptri_bm(mr, &params, 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, &params, extractors);
+ extract_iter_poly_mesh(mr, &params, extractors, task_id);
}
else {
ExtractPolyBMesh_Params params;
params.poly_range[0] = 0;
params.poly_range[1] = mr->poly_len;
- extract_iter_poly_bm(mr, &params, extractors);
+ extract_iter_poly_bm(mr, &params, 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, &params, extractors);
+ extract_iter_ledge_mesh(mr, &params, extractors, task_id);
}
else {
ExtractLEdgeBMesh_Params params;
params.ledge = mr->ledges;
params.ledge_range[0] = 0;
params.ledge_range[1] = mr->edge_loose_len;
- extract_iter_ledge_bm(mr, &params, extractors);
+ extract_iter_ledge_bm(mr, &params, 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, &params, extractors);
+ extract_iter_lvert_mesh(mr, &params, extractors, task_id);
}
else {
ExtractLVertBMesh_Params params;
params.lvert = mr->lverts;
params.lvert_range[0] = 0;
params.lvert_range[1] = mr->vert_loose_len;
- extract_iter_lvert_bm(mr, &params, extractors);
+ extract_iter_lvert_bm(mr, &params, 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, &params, extractors);
+ extract_iter_looptri_bm(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_POLY) {
ExtractPolyBMesh_Params params;
params.poly_range[0] = start;
params.poly_range[1] = min_ii(mr->poly_len, end);
- extract_iter_poly_bm(mr, &params, extractors);
+ extract_iter_poly_bm(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_LEDGE) {
ExtractLEdgeBMesh_Params params;
params.ledge = mr->ledges;
params.ledge_range[0] = start;
params.ledge_range[1] = min_ii(mr->edge_loose_len, end);
- extract_iter_ledge_bm(mr, &params, extractors);
+ extract_iter_ledge_bm(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_LVERT) {
ExtractLVertBMesh_Params params;
params.lvert = mr->lverts;
params.lvert_range[0] = start;
params.lvert_range[1] = min_ii(mr->vert_loose_len, end);
- extract_iter_lvert_bm(mr, &params, extractors);
+ extract_iter_lvert_bm(mr, &params, 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, &params, extractors);
+ extract_iter_looptri_mesh(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_POLY) {
ExtractPolyMesh_Params params;
params.poly_range[0] = start;
params.poly_range[1] = min_ii(mr->poly_len, end);
- extract_iter_poly_mesh(mr, &params, extractors);
+ extract_iter_poly_mesh(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_LEDGE) {
ExtractLEdgeMesh_Params params;
params.ledge = mr->ledges;
params.ledge_range[0] = start;
params.ledge_range[1] = min_ii(mr->edge_loose_len, end);
- extract_iter_ledge_mesh(mr, &params, extractors);
+ extract_iter_ledge_mesh(mr, &params, extractors, task_id);
}
if (iter_type & MR_ITER_LVERT) {
ExtractLVertMesh_Params params;
params.lvert = mr->lverts;
params.lvert_range[0] = start;
params.lvert_range[1] = min_ii(mr->vert_loose_len, end);
- extract_iter_lvert_mesh(mr, &params, extractors);
+ extract_iter_lvert_mesh(mr, &params, 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