diff options
author | Jeroen Bakker <jbakker> | 2021-06-09 17:20:38 +0300 |
---|---|---|
committer | Jeroen Bakker <jeroen@blender.org> | 2021-06-09 17:20:53 +0300 |
commit | 6e999e08ab87712a9baca33ab691af2b83762b7e (patch) | |
tree | 3c747c277bd7090b87f5300986dcec782a7bb9ec /source/blender | |
parent | ec98bb318b938f829859ee7dfa1a96d1171c2a64 (diff) |
T88352: Use threaded ibo.tris extraction for single material meshes.
This patch adds a specific extraction method when the mesh has only
one material. This method is multi-threaded.
There is a trade-off in this patch as the ibo isn't compressed (it adds
restart indexes for hidden faces). So it depends if threading is faster
than the additional GPU buffer upload.
# Subdivided cube
I used a cube subdivided 7 times, modifiers applied. that gives around 400000 faces.
The test is selecting some vertices and move them. During this test the next buffers are updated on each frame:
* vbo.pos_nor
* vbo.lnor
* vbo.edit_data
* ibo.tris
* ibo.points
System info:
|platform| Linux-5.11.0-7614-generic-x86_64-with-glibc2.33|
| renderer| AMD SIENNA_CICHLID (DRM 3.40.0, 5.11.0-7614-generic, LLVM 11.0.1)|
|vendor| AMD|
|version| 4.6 (Core Profile) Mesa 21.0.1|
|cpu| Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz|
|compiler| gcc version 10.3.0|
Timing have been measured using DEBUG_TIME in `draw_cache_extract_mesh`.
master: `rdata 8ms iter 45ms (frame 153ms)`
this patch `rdata 6ms iter 36ms (frame 132ms)`
Reviewed By: mano-wii
Maniphest Tasks: T88352
Differential Revision: https://developer.blender.org/D11290
Diffstat (limited to 'source/blender')
5 files changed, 130 insertions, 5 deletions
diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index 0b6dffa9073..304cae1d2dc 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -90,7 +90,7 @@ ENUM_OPERATORS(eMRDataType, MR_DATA_TAN_LOOP_NOR) extern "C" { #endif -BLI_INLINE int mesh_render_mat_len_get(Mesh *me) +BLI_INLINE int mesh_render_mat_len_get(const Mesh *me) { /* In edit mode, the displayed mesh is stored in the edit-mesh. */ if (me->edit_mesh && me->edit_mesh->mesh_eval_final) { diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc index 7b2c0da4dd9..6b5877e6759 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -866,6 +866,7 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, */ const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 || GPU_use_hq_normals_workaround(); + const bool override_single_mat = mesh_render_mat_len_get(me) <= 1; /* Create an array containing all the extractors that needs to be executed. */ ExtractorRunDatas extractors; @@ -873,7 +874,8 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, #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); \ + const MeshExtract *extractor = mesh_extract_override_get( \ + &extract_##name, do_hq_normals, override_single_mat); \ extractors.append(extractor); \ } \ } while (0) diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c index b79f80866ec..3cac391c42d 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c @@ -94,12 +94,26 @@ static const MeshExtract *mesh_extract_override_hq_normals(const MeshExtract *ex return extractor; } +static const MeshExtract *mesh_extract_override_single_material(const MeshExtract *extractor) +{ + if (extractor == &extract_tris) { + return &extract_tris_single_mat; + } + return extractor; +} + const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, - const bool do_hq_normals) + const bool do_hq_normals, + const bool do_single_mat) { if (do_hq_normals) { extractor = mesh_extract_override_hq_normals(extractor); } + + if (do_single_mat) { + extractor = mesh_extract_override_single_material(extractor); + } + return extractor; } 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 e4ea3e44843..e2d97b73db2 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_private.h +++ b/source/blender/draw/intern/draw_cache_extract_mesh_private.h @@ -468,13 +468,15 @@ void mesh_render_data_update_looptris(MeshRenderData *mr, void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferCache *mbc); eMRIterType mesh_extract_iter_type(const MeshExtract *ext); const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, - const bool do_hq_normals); + const bool do_hq_normals, + const bool do_single_mat); /* * Total number of extractions types. */ #define M_EXTRACT_LEN 38 extern const MeshExtract extract_tris; +extern const MeshExtract extract_tris_single_mat; extern const MeshExtract extract_lines; extern const MeshExtract extract_lines_with_lines_loose; extern const MeshExtract extract_lines_loose_only; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc index aab9ae8c228..acfffdacb88 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc @@ -28,7 +28,7 @@ namespace blender::draw { /* ---------------------------------------------------------------------- */ -/** \name Extract Triangles Indices +/** \name Extract Triangles Indices (multi material) * \{ */ struct MeshExtract_Tri_Data { @@ -168,8 +168,115 @@ constexpr MeshExtract create_extractor_tris() /** \} */ +/** \name Extract Triangles Indices (single material) + * \{ */ + +static void *extract_tris_single_mat_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *UNUSED(ibo)) +{ + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(MEM_mallocN(sizeof(*elb), __func__)); + GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr->tri_len, mr->loop_len); + return elb; +} + +static void *extract_tris_single_mat_task_init(void *_userdata) +{ + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata); + GPUIndexBufBuilder *sub_builder = static_cast<GPUIndexBufBuilder *>( + MEM_mallocN(sizeof(*sub_builder), __func__)); + GPU_indexbuf_subbuilder_init(elb, sub_builder); + return sub_builder; +} + +static void extract_tris_single_mat_iter_looptri_bm(const MeshRenderData *UNUSED(mr), + BMLoop **elt, + const int elt_index, + void *_data) +{ + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data); + if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { + GPU_indexbuf_set_tri_verts(elb, + elt_index, + BM_elem_index_get(elt[0]), + BM_elem_index_get(elt[1]), + BM_elem_index_get(elt[2])); + } + else { + GPU_indexbuf_set_tri_restart(elb, elt_index); + } +} + +static void extract_tris_single_mat_iter_looptri_mesh(const MeshRenderData *mr, + const MLoopTri *mlt, + const int mlt_index, + void *_data) +{ + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data); + const MPoly *mp = &mr->mpoly[mlt->poly]; + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + GPU_indexbuf_set_tri_verts(elb, mlt_index, mlt->tri[0], mlt->tri[1], mlt->tri[2]); + } + else { + GPU_indexbuf_set_tri_restart(elb, mlt_index); + } +} + +static void extract_tris_single_mat_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_tris_single_mat_finish(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *_data) +{ + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data); + GPU_indexbuf_build_in_place(elb, ibo); + + /* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch + * is created before the surfaces-per-material. */ + if (mr->use_final_mesh && cache->final.tris_per_mat) { + MeshBufferCache *mbc = &cache->final; + for (int i = 0; i < mr->mat_len; i++) { + /* These IBOs have not been queried yet but we create them just in case they are needed + * later since they are not tracked by mesh_buffer_cache_create_requested(). */ + if (mbc->tris_per_mat[i] == NULL) { + mbc->tris_per_mat[i] = GPU_indexbuf_calloc(); + } + /* Multiply by 3 because these are triangle indices. */ + const int len = mr->tri_len * 3; + GPU_indexbuf_create_subrange_in_place(mbc->tris_per_mat[i], ibo, 0, len); + } + } + MEM_freeN(elb); +} + +constexpr MeshExtract create_extractor_tris_single_mat() +{ + MeshExtract extractor = {0}; + extractor.init = extract_tris_single_mat_init; + extractor.task_init = extract_tris_single_mat_task_init; + extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm; + extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh; + extractor.task_finish = extract_tris_single_mat_task_finish; + extractor.finish = extract_tris_single_mat_finish; + extractor.data_type = MR_DATA_NONE; + extractor.use_threading = true; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris); + return extractor; +} + +/** \} */ + } // namespace blender::draw extern "C" { const MeshExtract extract_tris = blender::draw::create_extractor_tris(); +const MeshExtract extract_tris_single_mat = blender::draw::create_extractor_tris_single_mat(); } |