diff options
3 files changed, 176 insertions, 135 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index b8dc6b775e3..5144218e1ec 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -55,6 +55,7 @@ set(SRC intern/draw_cache_extract_mesh_render_data.c intern/draw_cache_extract_mesh.cc intern/mesh_extractors/extract_mesh_ibo_points.cc + intern/mesh_extractors/extract_mesh_ibo_tris.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_mesh_extractors.c b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c index 1d44f9f911b..a56e22e6132 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c +++ b/source/blender/draw/intern/draw_cache_extract_mesh_extractors.c @@ -105,142 +105,7 @@ const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, /** \} */ -/* ---------------------------------------------------------------------- */ -/** \name Extract Triangles Indices - * \{ */ - -typedef struct MeshExtract_Tri_Data { - GPUIndexBufBuilder elb; - int *tri_mat_start; - int *tri_mat_end; -} MeshExtract_Tri_Data; - -static void *extract_tris_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *UNUSED(ibo)) -{ - MeshExtract_Tri_Data *data = MEM_callocN(sizeof(*data), __func__); - - size_t mat_tri_idx_size = sizeof(int) * mr->mat_len; - data->tri_mat_start = MEM_callocN(mat_tri_idx_size, __func__); - data->tri_mat_end = MEM_callocN(mat_tri_idx_size, __func__); - int *mat_tri_len = data->tri_mat_start; - /* Count how many triangle for each material. */ - if (mr->extract_type == MR_EXTRACT_BMESH) { - BMIter iter; - BMFace *efa; - BM_ITER_MESH (efa, &iter, mr->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - int mat = min_ii(efa->mat_nr, mr->mat_len - 1); - mat_tri_len[mat] += efa->len - 2; - } - } - } - else { - const MPoly *mp = mr->mpoly; - for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { - if (!(mr->use_hide && (mp->flag & ME_HIDE))) { - int mat = min_ii(mp->mat_nr, mr->mat_len - 1); - mat_tri_len[mat] += mp->totloop - 2; - } - } - } - /* Accumulate triangle lengths per material to have correct offsets. */ - int ofs = mat_tri_len[0]; - mat_tri_len[0] = 0; - for (int i = 1; i < mr->mat_len; i++) { - int tmp = mat_tri_len[i]; - mat_tri_len[i] = ofs; - ofs += tmp; - } - - memcpy(data->tri_mat_end, mat_tri_len, mat_tri_idx_size); - - int visible_tri_tot = ofs; - GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, visible_tri_tot, mr->loop_len); - - return data; -} - -static void extract_tris_iter_looptri_bm(const MeshRenderData *mr, - BMLoop **elt, - const int UNUSED(elt_index), - void *_data) -{ - MeshExtract_Tri_Data *data = _data; - const int mat_last = mr->mat_len - 1; - - if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { - int *mat_tri_ofs = data->tri_mat_end; - const int mat = min_ii(elt[0]->f->mat_nr, mat_last); - GPU_indexbuf_set_tri_verts(&data->elb, - mat_tri_ofs[mat]++, - BM_elem_index_get(elt[0]), - BM_elem_index_get(elt[1]), - BM_elem_index_get(elt[2])); - } -} - -static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr, - const MLoopTri *mlt, - const int UNUSED(elt_index), - void *_data) -{ - MeshExtract_Tri_Data *data = _data; - const int mat_last = mr->mat_len - 1; - const MPoly *mp = &mr->mpoly[mlt->poly]; - if (!(mr->use_hide && (mp->flag & ME_HIDE))) { - int *mat_tri_ofs = data->tri_mat_end; - const int mat = min_ii(mp->mat_nr, mat_last); - GPU_indexbuf_set_tri_verts( - &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]); - } -} - -static void extract_tris_finish(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *_data) -{ - GPUIndexBuf *ibo = buf; - MeshExtract_Tri_Data *data = _data; - GPU_indexbuf_build_in_place(&data->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_final = &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_final->tris_per_mat[i] == NULL) { - mbc_final->tris_per_mat[i] = GPU_indexbuf_calloc(); - } - /* Multiply by 3 because these are triangle indices. */ - const int mat_start = data->tri_mat_start[i]; - const int mat_end = data->tri_mat_end[i]; - const int start = mat_start * 3; - const int len = (mat_end - mat_start) * 3; - GPU_indexbuf_create_subrange_in_place(mbc_final->tris_per_mat[i], ibo, start, len); - } - } - MEM_freeN(data->tri_mat_start); - MEM_freeN(data->tri_mat_end); - MEM_freeN(data); -} - -const MeshExtract extract_tris = { - .init = extract_tris_init, - .iter_looptri_bm = extract_tris_iter_looptri_bm, - .iter_looptri_mesh = extract_tris_iter_looptri_mesh, - .finish = extract_tris_finish, - .data_type = 0, - .use_threading = false, - .mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris), -}; - -/** \} */ /* ---------------------------------------------------------------------- */ /** \name Extract Edges Indices 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 new file mode 100644 index 00000000000..688f04450e9 --- /dev/null +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc @@ -0,0 +1,175 @@ +/* + * 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) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#include "draw_cache_extract_mesh_private.h" + +#include "MEM_guardedalloc.h" + +namespace blender::draw { + +/* ---------------------------------------------------------------------- */ +/** \name Extract Triangles Indices + * \{ */ + +struct MeshExtract_Tri_Data { + GPUIndexBufBuilder elb; + int *tri_mat_start; + int *tri_mat_end; +}; + +static void *extract_tris_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *UNUSED(ibo)) +{ + MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>( + MEM_callocN(sizeof(*data), __func__)); + + size_t mat_tri_idx_size = sizeof(int) * mr->mat_len; + data->tri_mat_start = static_cast<int *>(MEM_callocN(mat_tri_idx_size, __func__)); + data->tri_mat_end = static_cast<int *>(MEM_callocN(mat_tri_idx_size, __func__)); + + int *mat_tri_len = data->tri_mat_start; + /* Count how many triangle for each material. */ + if (mr->extract_type == MR_EXTRACT_BMESH) { + BMIter iter; + BMFace *efa; + BM_ITER_MESH (efa, &iter, mr->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + int mat = min_ii(efa->mat_nr, mr->mat_len - 1); + mat_tri_len[mat] += efa->len - 2; + } + } + } + else { + const MPoly *mp = mr->mpoly; + for (int mp_index = 0; mp_index < mr->poly_len; mp_index++, mp++) { + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + int mat = min_ii(mp->mat_nr, mr->mat_len - 1); + mat_tri_len[mat] += mp->totloop - 2; + } + } + } + /* Accumulate triangle lengths per material to have correct offsets. */ + int ofs = mat_tri_len[0]; + mat_tri_len[0] = 0; + for (int i = 1; i < mr->mat_len; i++) { + int tmp = mat_tri_len[i]; + mat_tri_len[i] = ofs; + ofs += tmp; + } + + memcpy(data->tri_mat_end, mat_tri_len, mat_tri_idx_size); + + int visible_tri_tot = ofs; + GPU_indexbuf_init(&data->elb, GPU_PRIM_TRIS, visible_tri_tot, mr->loop_len); + + return data; +} + +static void extract_tris_iter_looptri_bm(const MeshRenderData *mr, + BMLoop **elt, + const int UNUSED(elt_index), + void *_data) +{ + MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(_data); + const int mat_last = mr->mat_len - 1; + + if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) { + int *mat_tri_ofs = data->tri_mat_end; + const int mat = min_ii(elt[0]->f->mat_nr, mat_last); + GPU_indexbuf_set_tri_verts(&data->elb, + mat_tri_ofs[mat]++, + BM_elem_index_get(elt[0]), + BM_elem_index_get(elt[1]), + BM_elem_index_get(elt[2])); + } +} + +static void extract_tris_iter_looptri_mesh(const MeshRenderData *mr, + const MLoopTri *mlt, + const int UNUSED(elt_index), + void *_data) +{ + MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(_data); + const int mat_last = mr->mat_len - 1; + const MPoly *mp = &mr->mpoly[mlt->poly]; + if (!(mr->use_hide && (mp->flag & ME_HIDE))) { + int *mat_tri_ofs = data->tri_mat_end; + const int mat = min_ii(mp->mat_nr, mat_last); + GPU_indexbuf_set_tri_verts( + &data->elb, mat_tri_ofs[mat]++, mlt->tri[0], mlt->tri[1], mlt->tri[2]); + } +} + +static void extract_tris_finish(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *_data) +{ + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + MeshExtract_Tri_Data *data = static_cast<MeshExtract_Tri_Data *>(_data); + GPU_indexbuf_build_in_place(&data->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_final = &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_final->tris_per_mat[i] == NULL) { + mbc_final->tris_per_mat[i] = GPU_indexbuf_calloc(); + } + /* Multiply by 3 because these are triangle indices. */ + const int mat_start = data->tri_mat_start[i]; + const int mat_end = data->tri_mat_end[i]; + const int start = mat_start * 3; + const int len = (mat_end - mat_start) * 3; + GPU_indexbuf_create_subrange_in_place(mbc_final->tris_per_mat[i], ibo, start, len); + } + } + MEM_freeN(data->tri_mat_start); + MEM_freeN(data->tri_mat_end); + MEM_freeN(data); +} + +constexpr MeshExtract create_extractor_tris() +{ + MeshExtract extractor = {0}; + extractor.init = extract_tris_init; + extractor.iter_looptri_bm = extract_tris_iter_looptri_bm; + extractor.iter_looptri_mesh = extract_tris_iter_looptri_mesh; + extractor.finish = extract_tris_finish; + extractor.data_type = MR_DATA_NONE; + extractor.use_threading = false; + extractor.mesh_buffer_offset = offsetof(MeshBufferCache, ibo.tris); + return extractor; +} + +/** \} */ + +} // namespace blender::draw + +extern "C" { +const MeshExtract extract_tris = blender::draw::create_extractor_tris(); +} |