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
This commit is contained in:
parent
ec98bb318b
commit
6e999e08ab
Notes:
blender-bot
2023-02-14 05:51:15 +01:00
Referenced by issue #88352, DrawManager: Threading for ibo.tris
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue