diff options
Diffstat (limited to 'source/blender/draw/intern/mesh_extractors')
20 files changed, 1418 insertions, 82 deletions
diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h index 7d21804c08f..35cc2cf986e 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h @@ -39,6 +39,8 @@ extern "C" { #endif +struct DRWSubdivCache; + #define MIN_RANGE_LEN 1024 /* ---------------------------------------------------------------------- */ @@ -203,6 +205,11 @@ typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr, const MVert *mv, const int lvert_index, void *data); +typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *data); typedef void(ExtractInitFn)(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buffer, @@ -213,6 +220,18 @@ typedef void(ExtractFinishFn)(const MeshRenderData *mr, void *data); typedef void(ExtractTaskReduceFn)(void *userdata, void *task_userdata); +typedef void(ExtractInitSubdivFn)(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *data); +typedef void(ExtractIterSubdivFn)(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *data); +typedef void(ExtractFinishSubdivFn)(const struct DRWSubdivCache *subdiv_cache, + void *buf, + void *data); + typedef struct MeshExtract { /** Executed on main thread and return user data for iteration functions. */ ExtractInitFn *init; @@ -225,9 +244,14 @@ typedef struct MeshExtract { ExtractLEdgeMeshFn *iter_ledge_mesh; ExtractLVertBMeshFn *iter_lvert_bm; ExtractLVertMeshFn *iter_lvert_mesh; + ExtractLooseGeomSubdivFn *iter_loose_geom_subdiv; /** Executed on one worker thread after all elements iterations. */ ExtractTaskReduceFn *task_reduce; ExtractFinishFn *finish; + /** Executed on main thread for subdivision evaluation. */ + ExtractInitSubdivFn *init_subdiv; + ExtractIterSubdivFn *iter_subdiv; + ExtractFinishSubdivFn *finish_subdiv; /** Used to request common data. */ eMRDataType data_type; size_t data_size; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc index 4cc9a875f79..6a1691e8634 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc @@ -27,6 +27,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ /** \name Extract Edit UV Triangles Indices @@ -94,6 +96,57 @@ static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(&data->elb, ibo); } +static void extract_edituv_tris_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *tls_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data); + GPU_indexbuf_init(&data->elb, + GPU_PRIM_TRIS, + subdiv_cache->num_subdiv_triangles, + subdiv_cache->num_subdiv_loops); + data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; +} + +static void extract_edituv_tris_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + + for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) { + const uint loop_idx = i * 4; + const int poly_origindex = subdiv_loop_poly_index[loop_idx]; + BMFace *efa = bm_original_face_get(mr, poly_origindex); + + edituv_tri_add(data, + BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0, + BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0, + loop_idx, + loop_idx + 1, + loop_idx + 2); + + edituv_tri_add(data, + BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0, + BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0, + loop_idx, + loop_idx + 2, + loop_idx + 3); + } +} + +static void extract_edituv_tris_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), + void *buf, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(&data->elb, ibo); +} + constexpr MeshExtract create_extractor_edituv_tris() { MeshExtract extractor = {nullptr}; @@ -101,6 +154,9 @@ constexpr MeshExtract create_extractor_edituv_tris() extractor.iter_looptri_bm = extract_edituv_tris_iter_looptri_bm; extractor.iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh; extractor.finish = extract_edituv_tris_finish; + extractor.init_subdiv = extract_edituv_tris_init_subdiv; + extractor.iter_subdiv = extract_edituv_tris_iter_subdiv; + extractor.finish_subdiv = extract_edituv_tris_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; @@ -184,6 +240,56 @@ static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(&data->elb, ibo); } +static void extract_edituv_lines_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *tls_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data); + GPU_indexbuf_init( + &data->elb, GPU_PRIM_LINES, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops); + data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; +} + +static void extract_edituv_lines_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + + for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) { + + uint start_loop_idx = i * 4; + uint end_loop_idx = (i + 1) * 4; + + const int poly_origindex = subdiv_loop_poly_index[start_loop_idx]; + BMFace *efa = bm_original_face_get(mr, poly_origindex); + + for (uint loop_idx = start_loop_idx; loop_idx < end_loop_idx; loop_idx++) { + const int edge_origindex = subdiv_loop_edge_index[loop_idx]; + const bool real_edge = (edge_origindex != -1 && + mr->e_origindex[edge_origindex] != ORIGINDEX_NONE); + edituv_edge_add(data, + BM_elem_flag_test_bool(efa, BM_ELEM_HIDDEN) != 0 || !real_edge, + BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) != 0, + loop_idx, + (loop_idx + 1 == end_loop_idx) ? start_loop_idx : (loop_idx + 1)); + } + } +} + +static void extract_edituv_lines_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), + void *buf, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(&data->elb, ibo); +} + constexpr MeshExtract create_extractor_edituv_lines() { MeshExtract extractor = {nullptr}; @@ -191,6 +297,9 @@ constexpr MeshExtract create_extractor_edituv_lines() extractor.iter_poly_bm = extract_edituv_lines_iter_poly_bm; extractor.iter_poly_mesh = extract_edituv_lines_iter_poly_mesh; extractor.finish = extract_edituv_lines_finish; + extractor.init_subdiv = extract_edituv_lines_init_subdiv; + extractor.iter_subdiv = extract_edituv_lines_iter_subdiv; + extractor.finish_subdiv = extract_edituv_lines_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; @@ -268,6 +377,50 @@ static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(&data->elb, ibo); } +static void extract_edituv_points_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *tls_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data); + GPU_indexbuf_init( + &data->elb, GPU_PRIM_POINTS, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops); + data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; +} + +static void extract_edituv_points_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + + for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) { + const int vert_origindex = subdiv_loop_vert_index[i]; + const int poly_origindex = subdiv_loop_poly_index[i]; + BMFace *efa = bm_original_face_get(mr, poly_origindex); + + const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && + vert_origindex != -1 && + mr->v_origindex[vert_origindex] != ORIGINDEX_NONE); + edituv_point_add(data, + (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !real_vert, + BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0, + i); + } +} + +static void extract_edituv_points_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), + void *buf, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(&data->elb, ibo); +} + constexpr MeshExtract create_extractor_edituv_points() { MeshExtract extractor = {nullptr}; @@ -275,6 +428,9 @@ constexpr MeshExtract create_extractor_edituv_points() extractor.iter_poly_bm = extract_edituv_points_iter_poly_bm; extractor.iter_poly_mesh = extract_edituv_points_iter_poly_mesh; extractor.finish = extract_edituv_points_finish; + extractor.init_subdiv = extract_edituv_points_init_subdiv; + extractor.iter_subdiv = extract_edituv_points_iter_subdiv; + extractor.finish_subdiv = extract_edituv_points_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc index 54f5611106f..3d9729dea56 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc @@ -25,6 +25,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -155,6 +157,33 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(elb, ibo); } +static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buffer, + void *UNUSED(data)) +{ + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer); + GPU_indexbuf_init_build_on_device(ibo, + subdiv_cache->num_subdiv_loops * 2 + mr->edge_loose_len * 2); + + draw_subdiv_build_lines_buffer(subdiv_cache, ibo); +} + +static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + if (loose_geom->edge_len == 0) { + return; + } + + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer); + draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom->edge_len)); +} + constexpr MeshExtract create_extractor_lines() { MeshExtract extractor = {nullptr}; @@ -163,6 +192,8 @@ constexpr MeshExtract create_extractor_lines() extractor.iter_poly_mesh = extract_lines_iter_poly_mesh; extractor.iter_ledge_bm = extract_lines_iter_ledge_bm; extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh; + extractor.init_subdiv = extract_lines_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_lines_loose_geom_subdiv; extractor.task_reduce = extract_lines_task_reduce; extractor.finish = extract_lines_finish; extractor.data_type = MR_DATA_NONE; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc index e7dabfa9ee2..6855feb51ed 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -44,6 +45,18 @@ struct MeshExtract_LineAdjacency_Data { uint *vert_to_loop; }; +static void line_adjacency_data_init(MeshExtract_LineAdjacency_Data *data, + uint vert_len, + uint loop_len, + uint tess_edge_len) +{ + data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * vert_len, __func__)); + + GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, loop_len); + data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len); + data->is_manifold = true; +} + static void extract_lines_adjacency_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf), @@ -55,11 +68,7 @@ static void extract_lines_adjacency_init(const MeshRenderData *mr, uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len; MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(tls_data); - data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * mr->vert_len, __func__)); - - GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len); - data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len); - data->is_manifold = true; + line_adjacency_data_init(data, mr->vert_len, mr->loop_len, tess_edge_len); } BLI_INLINE void lines_adjacency_triangle( @@ -171,6 +180,56 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data->vert_to_loop); } +static void extract_lines_adjacency_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *_data) +{ + MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data); + + /* For each polygon there is (loop + triangle - 1) edges. Since we only have quads, and a quad + * is split into 2 triangles, we have (loop + 2 - 1) = (loop + 1) edges for each quad, or in + * total: (number_of_loops + number_of_quads). */ + const uint tess_len = subdiv_cache->num_subdiv_loops + subdiv_cache->num_subdiv_quads; + line_adjacency_data_init( + data, tess_len, subdiv_cache->num_subdiv_verts, subdiv_cache->num_subdiv_loops); +} + +static void extract_lines_adjacency_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + void *_data) +{ + MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data); + + for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) { + const uint loop_index = i * 4; + const uint l0 = loop_index + 0; + const uint l1 = loop_index + 1; + const uint l2 = loop_index + 2; + const uint l3 = loop_index + 3; + + const uint v0 = subdiv_cache->subdiv_loop_subdiv_vert_index[l0]; + const uint v1 = subdiv_cache->subdiv_loop_subdiv_vert_index[l1]; + const uint v2 = subdiv_cache->subdiv_loop_subdiv_vert_index[l2]; + const uint v3 = subdiv_cache->subdiv_loop_subdiv_vert_index[l3]; + + lines_adjacency_triangle(v0, v1, v2, l0, l1, l2, data); + lines_adjacency_triangle(v0, v2, v3, l0, l2, l3, data); + } +} + +static void extract_lines_adjacency_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache), + void *buf, + void *_data) +{ + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data); + GPU_indexbuf_build_in_place(&data->elb, ibo); + BLI_edgehash_free(data->eh, nullptr); + MEM_freeN(data->vert_to_loop); +} + #undef NO_EDGE constexpr MeshExtract create_extractor_lines_adjacency() @@ -180,6 +239,9 @@ constexpr MeshExtract create_extractor_lines_adjacency() extractor.iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm; extractor.iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh; extractor.finish = extract_lines_adjacency_finish; + extractor.init_subdiv = extract_lines_adjacency_init_subdiv; + extractor.iter_subdiv = extract_lines_adjacency_iter_subdiv; + extractor.finish_subdiv = extract_lines_adjacency_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_LineAdjacency_Data); extractor.use_threading = false; 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 01e14a004ed..19167772a42 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 @@ -25,6 +25,7 @@ #include "MEM_guardedalloc.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -155,6 +156,74 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(elb, ibo); } +static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *UNUSED(cache), + void *UNUSED(buffer), + void *data) +{ + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data); + /* Copy the points as the data upload will free them. */ + elb->data = (uint *)MEM_dupallocN(subdiv_cache->point_indices); + elb->index_len = subdiv_cache->num_subdiv_verts; + elb->index_min = 0; + elb->index_max = subdiv_cache->num_subdiv_loops - 1; + elb->prim_type = GPU_PRIM_POINTS; +} + +static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *UNUSED(buffer), + void *data) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data); + + elb->data = static_cast<uint32_t *>( + MEM_reallocN(elb->data, sizeof(uint) * (subdiv_cache->num_subdiv_loops + loop_loose_len))); + + const Mesh *coarse_mesh = subdiv_cache->mesh; + const MEdge *coarse_edges = coarse_mesh->medge; + + uint offset = subdiv_cache->num_subdiv_loops; + + for (int i = 0; i < loose_geom->edge_len; i++) { + const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]]; + if (elb->data[loose_edge->v1] == -1u) { + elb->data[loose_edge->v1] = offset; + } + if (elb->data[loose_edge->v2] == -1u) { + elb->data[loose_edge->v2] = offset + 1; + } + elb->index_max += 2; + elb->index_len += 2; + offset += 2; + } + + for (int i = 0; i < loose_geom->vert_len; i++) { + if (elb->data[loose_geom->verts[i]] == -1u) { + elb->data[loose_geom->verts[i]] = offset; + } + elb->index_max += 1; + elb->index_len += 1; + offset += 1; + } +} + +static void extract_points_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache), + void *buf, + void *_userdata) +{ + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(elb, ibo); +} + constexpr MeshExtract create_extractor_points() { MeshExtract extractor = {nullptr}; @@ -167,6 +236,9 @@ constexpr MeshExtract create_extractor_points() extractor.iter_lvert_mesh = extract_points_iter_lvert_mesh; extractor.task_reduce = extract_points_task_reduce; extractor.finish = extract_points_finish; + extractor.init_subdiv = extract_points_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_points_loose_geom_subdiv; + extractor.finish_subdiv = extract_points_finish_subdiv; extractor.use_threading = true; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(GPUIndexBufBuilder); 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 54e733d3d86..b1ace8bc6c9 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 @@ -25,6 +25,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_from) @@ -123,10 +125,37 @@ static void extract_tris_finish(const MeshRenderData *mr, } } +static void extract_tris_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer); + /* Initialize the index buffer, it was already allocated, it will be filled on the device. */ + GPU_indexbuf_init_build_on_device(ibo, subdiv_cache->num_subdiv_triangles * 3); + + if (cache->tris_per_mat) { + for (int i = 0; i < cache->mat_len; i++) { + if (cache->tris_per_mat[i] == nullptr) { + cache->tris_per_mat[i] = GPU_indexbuf_calloc(); + } + + /* Multiply by 6 since we have 2 triangles per quad. */ + const int start = subdiv_cache->mat_start[i] * 6; + const int len = (subdiv_cache->mat_end[i] - subdiv_cache->mat_start[i]) * 6; + GPU_indexbuf_create_subrange_in_place(cache->tris_per_mat[i], ibo, start, len); + } + } + + draw_subdiv_build_tris_buffer(subdiv_cache, ibo, cache->mat_len); +} + constexpr MeshExtract create_extractor_tris() { MeshExtract extractor = {nullptr}; extractor.init = extract_tris_init; + extractor.init_subdiv = extract_tris_init_subdiv; extractor.iter_poly_bm = extract_tris_iter_poly_bm; extractor.iter_poly_mesh = extract_tris_iter_poly_mesh; extractor.task_reduce = extract_tris_mat_task_reduce; @@ -214,6 +243,7 @@ constexpr MeshExtract create_extractor_tris_single_mat() { MeshExtract extractor = {nullptr}; extractor.init = extract_tris_single_mat_init; + extractor.init_subdiv = extract_tris_init_subdiv; extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm; extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh; extractor.task_reduce = extract_tris_mat_task_reduce; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc index 8a5a8134ca7..ea702e5efdd 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc @@ -32,6 +32,7 @@ #include "BKE_attribute.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -153,7 +154,9 @@ static GPUVertCompType get_comp_type_for_type(CustomDataType type) static void init_vbo_for_attribute(const MeshRenderData *mr, GPUVertBuf *vbo, - const DRW_AttributeRequest &request) + const DRW_AttributeRequest &request, + bool build_on_device, + uint32_t len) { GPUVertCompType comp_type = get_comp_type_for_type(request.cd_type); GPUVertFetchMode fetch_mode = get_fetch_mode_for_type(request.cd_type); @@ -184,8 +187,13 @@ static void init_vbo_for_attribute(const MeshRenderData *mr, } } - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, static_cast<uint32_t>(mr->loop_len)); + if (build_on_device) { + GPU_vertbuf_init_build_on_device(vbo, &format, len); + } + else { + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, len); + } } template<typename AttributeType, typename VBOType> @@ -309,7 +317,7 @@ static void extract_attr_init(const MeshRenderData *mr, GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); - init_vbo_for_attribute(mr, vbo, request); + init_vbo_for_attribute(mr, vbo, request, false, static_cast<uint32_t>(mr->loop_len)); /* TODO(kevindietrich) : float3 is used for scalar attributes as the implicit conversion done by * OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following the @@ -346,6 +354,68 @@ static void extract_attr_init(const MeshRenderData *mr, } } +static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *cache, + void *buffer, + void *UNUSED(tls_data), + int index) +{ + const DRW_MeshAttributes *attrs_used = &cache->attr_used; + const DRW_AttributeRequest &request = attrs_used->requests[index]; + + Mesh *coarse_mesh = subdiv_cache->mesh; + + const uint32_t dimensions = gpu_component_size_for_attribute_type(request.cd_type); + + /* Prepare VBO for coarse data. The compute shader only expects floats. */ + GPUVertBuf *src_data = GPU_vertbuf_calloc(); + static GPUVertFormat coarse_format = {0}; + GPU_vertformat_attr_add(&coarse_format, "data", GPU_COMP_F32, dimensions, GPU_FETCH_FLOAT); + GPU_vertbuf_init_with_format_ex(src_data, &coarse_format, GPU_USAGE_STATIC); + GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop)); + + switch (request.cd_type) { + case CD_PROP_BOOL: { + extract_attr_generic<bool, float3>(mr, src_data, request); + break; + } + case CD_PROP_INT32: { + extract_attr_generic<int32_t, float3>(mr, src_data, request); + break; + } + case CD_PROP_FLOAT: { + extract_attr_generic<float, float3>(mr, src_data, request); + break; + } + case CD_PROP_FLOAT2: { + extract_attr_generic<float2>(mr, src_data, request); + break; + } + case CD_PROP_FLOAT3: { + extract_attr_generic<float3>(mr, src_data, request); + break; + } + case CD_PROP_COLOR: { + extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request); + break; + } + default: { + BLI_assert(false); + } + } + + GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer); + init_vbo_for_attribute(mr, dst_buffer, request, true, subdiv_cache->num_subdiv_loops); + + /* Ensure data is uploaded properly. */ + GPU_vertbuf_tag_dirty(src_data); + draw_subdiv_interp_custom_data( + subdiv_cache, src_data, dst_buffer, static_cast<int>(dimensions), 0); + + GPU_vertbuf_discard(src_data); +} + /* Wrappers around extract_attr_init so we can pass the index of the attribute that we want to * extract. The overall API does not allow us to pass this in a convenient way. */ #define EXTRACT_INIT_WRAPPER(index) \ @@ -353,6 +423,14 @@ static void extract_attr_init(const MeshRenderData *mr, const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *tls_data) \ { \ extract_attr_init(mr, cache, buf, tls_data, index); \ + } \ + static void extract_attr_init_subdiv##index(const DRWSubdivCache *subdiv_cache, \ + const MeshRenderData *mr, \ + struct MeshBatchCache *cache, \ + void *buf, \ + void *tls_data) \ + { \ + extract_attr_init_subdiv(subdiv_cache, mr, cache, buf, tls_data, index); \ } EXTRACT_INIT_WRAPPER(0) @@ -371,10 +449,12 @@ EXTRACT_INIT_WRAPPER(12) EXTRACT_INIT_WRAPPER(13) EXTRACT_INIT_WRAPPER(14) -template<int index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn) +template<int index> +constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn) { MeshExtract extractor = {nullptr}; extractor.init = fn; + extractor.init_subdiv = subdiv_fn; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; @@ -388,7 +468,8 @@ template<int index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn extern "C" { #define CREATE_EXTRACTOR_ATTR(index) \ - blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index) + blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index, \ + blender::draw::extract_attr_init_subdiv##index) const MeshExtract extract_attr[GPU_MAX_ATTR] = { CREATE_EXTRACTOR_ATTR(0), diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc index 2e2444a8e3d..5ee34d7fdb2 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc @@ -25,6 +25,7 @@ #include "GPU_capabilities.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -216,6 +217,86 @@ static void extract_edge_fac_finish(const MeshRenderData *mr, MEM_SAFE_FREE(data->edge_loop_count); } +/* Different function than the one used for the non-subdivision case, as we directly take care of + * the buggy AMD driver case. */ +static GPUVertFormat *get_subdiv_edge_fac_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + if (GPU_crappy_amd_driver()) { + GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + else { + GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + } + return &format; +} + +static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *edge_idx = cache->final.buff.vbo.edge_idx; + GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor; + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + GPU_vertbuf_init_build_on_device( + vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len); + + /* Create a temporary buffer for the edge original indices if it was not requested. */ + const bool has_edge_idx = edge_idx != nullptr; + GPUVertBuf *loop_edge_idx = nullptr; + if (has_edge_idx) { + loop_edge_idx = edge_idx; + } + else { + loop_edge_idx = GPU_vertbuf_calloc(); + draw_subdiv_init_origindex_buffer( + loop_edge_idx, + static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)), + subdiv_cache->num_subdiv_loops, + 0); + } + + draw_subdiv_build_edge_fac_buffer(subdiv_cache, pos_nor, loop_edge_idx, vbo); + + if (!has_edge_idx) { + GPU_vertbuf_discard(loop_edge_idx); + } +} + +static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + if (loose_geom->edge_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + + /* Make sure buffer is active for sending loose data. */ + GPU_vertbuf_use(vbo); + + uint offset = subdiv_cache->num_subdiv_loops; + for (int i = 0; i < loose_geom->edge_len; i++) { + if (GPU_crappy_amd_driver()) { + float loose_edge_fac[2] = {1.0f, 1.0f}; + GPU_vertbuf_update_sub(vbo, offset * sizeof(float), sizeof(loose_edge_fac), loose_edge_fac); + } + else { + char loose_edge_fac[2] = {255, 255}; + GPU_vertbuf_update_sub(vbo, offset * sizeof(char), sizeof(loose_edge_fac), loose_edge_fac); + } + + offset += 2; + } +} + constexpr MeshExtract create_extractor_edge_fac() { MeshExtract extractor = {nullptr}; @@ -224,6 +305,8 @@ constexpr MeshExtract create_extractor_edge_fac() extractor.iter_poly_mesh = extract_edge_fac_iter_poly_mesh; extractor.iter_ledge_bm = extract_edge_fac_iter_ledge_bm; extractor.iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh; + extractor.init_subdiv = extract_edge_fac_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_edge_fac_loose_geom_subdiv; extractor.finish = extract_edge_fac_finish; extractor.data_type = MR_DATA_POLY_NOR; extractor.data_size = sizeof(MeshExtract_EdgeFac_Data); diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc index 5232346e51e..eef64085c95 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc @@ -25,6 +25,8 @@ #include "draw_cache_impl.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -107,19 +109,25 @@ static void mesh_render_data_vert_flag(const MeshRenderData *mr, } } -static void extract_edit_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) +static GPUVertFormat *get_edit_data_format(void) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* WARNING: Adjust #EditLoopData struct accordingly. */ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); GPU_vertformat_alias_add(&format, "flag"); } - GPU_vertbuf_init_with_format(vbo, &format); + return &format; +} + +static void extract_edit_data_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat *format = get_edit_data_format(); + GPU_vertbuf_init_with_format(vbo, format); GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); *(EditLoopData **)tls_data = vbo_data; @@ -240,6 +248,80 @@ static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr, } } +static void extract_edit_data_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPU_vertbuf_init_with_format(vbo, get_edit_data_format()); + GPU_vertbuf_data_alloc(vbo, subdiv_cache->num_subdiv_loops + mr->loop_loose_len); + EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); + *(EditLoopData **)data = vbo_data; +} + +static void extract_edit_data_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data) +{ + EditLoopData *vbo_data = *(EditLoopData **)_data; + int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index); + int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + + for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) { + const int vert_origindex = subdiv_loop_vert_index[i]; + const int edge_origindex = subdiv_loop_edge_index[i]; + const int poly_origindex = subdiv_loop_poly_index[i]; + + EditLoopData *edit_loop_data = &vbo_data[i]; + memset(edit_loop_data, 0, sizeof(EditLoopData)); + + if (vert_origindex != -1) { + const BMVert *eve = bm_original_vert_get(mr, vert_origindex); + if (eve) { + mesh_render_data_vert_flag(mr, eve, edit_loop_data); + } + } + + if (edge_origindex != -1) { + const BMEdge *eed = bm_original_edge_get(mr, edge_origindex); + if (eed) { + mesh_render_data_edge_flag(mr, eed, edit_loop_data); + } + } + + BMFace *efa = bm_original_face_get(mr, poly_origindex); + /* The -1 parameter is for edit_uvs, which we don't do here. */ + mesh_render_data_face_flag(mr, efa, -1, edit_loop_data); + } +} + +static void extract_edit_data_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + const MeshExtractLooseGeom *loose_geom, + void *UNUSED(buffer), + void *_data) +{ + if (loose_geom->edge_len == 0) { + return; + } + + EditLoopData *vbo_data = *(EditLoopData **)_data; + + for (int ledge_index = 0; ledge_index < loose_geom->edge_len; ledge_index++) { + const int offset = subdiv_cache->num_subdiv_loops + ledge_index * 2; + EditLoopData *data = &vbo_data[offset]; + memset(data, 0, sizeof(EditLoopData)); + BMEdge *eed = bm_original_edge_get(mr, loose_geom->edges[ledge_index]); + mesh_render_data_edge_flag(mr, eed, &data[0]); + data[1] = data[0]; + mesh_render_data_vert_flag(mr, eed->v1, &data[0]); + mesh_render_data_vert_flag(mr, eed->v2, &data[1]); + } +} + constexpr MeshExtract create_extractor_edit_data() { MeshExtract extractor = {nullptr}; @@ -250,6 +332,9 @@ constexpr MeshExtract create_extractor_edit_data() extractor.iter_ledge_mesh = extract_edit_data_iter_ledge_mesh; extractor.iter_lvert_bm = extract_edit_data_iter_lvert_bm; extractor.iter_lvert_mesh = extract_edit_data_iter_lvert_mesh; + extractor.init_subdiv = extract_edit_data_init_subdiv; + extractor.iter_subdiv = extract_edit_data_iter_subdiv; + extractor.iter_loose_geom_subdiv = extract_edit_data_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(EditLoopData *); extractor.use_threading = true; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc index b8494428eed..067d482bc2b 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc @@ -25,6 +25,8 @@ #include "draw_cache_impl.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -36,12 +38,11 @@ struct MeshExtract_EditUVData_Data { int cd_ofs; }; -static void extract_edituv_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) +static void extract_edituv_data_init_common(const MeshRenderData *mr, + GPUVertBuf *vbo, + MeshExtract_EditUVData_Data *data, + uint loop_len) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* WARNING: Adjust #EditLoopData struct accordingly. */ @@ -50,15 +51,23 @@ static void extract_edituv_data_init(const MeshRenderData *mr, } GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); + GPU_vertbuf_data_alloc(vbo, loop_len); CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; - - MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data); data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV); } +static void extract_edituv_data_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data); + extract_edituv_data_init_common(mr, vbo, data, mr->loop_len); +} + static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr, const BMFace *f, const int UNUSED(f_index), @@ -119,12 +128,54 @@ static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr, } } +static void extract_edituv_data_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data); + extract_edituv_data_init_common(mr, vbo, data, subdiv_cache->num_subdiv_loops); +} + +static void extract_edituv_data_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data) +{ + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(_data); + int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index); + int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + + for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) { + const int vert_origindex = subdiv_loop_vert_index[i]; + const int edge_origindex = subdiv_loop_edge_index[i]; + const int poly_origindex = subdiv_loop_poly_index[i]; + + EditLoopData *edit_loop_data = &data->vbo_data[i]; + memset(edit_loop_data, 0, sizeof(EditLoopData)); + + BMFace *efa = bm_original_face_get(mr, poly_origindex); + + if (vert_origindex != -1 && edge_origindex != -1) { + BMEdge *eed = bm_original_edge_get(mr, edge_origindex); + /* Loop on an edge endpoint. */ + BMLoop *l = BM_face_edge_share_loop(efa, eed); + mesh_render_data_loop_flag(mr, l, data->cd_ofs, edit_loop_data); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, edit_loop_data); + } + } +} + constexpr MeshExtract create_extractor_edituv_data() { MeshExtract extractor = {nullptr}; extractor.init = extract_edituv_data_init; extractor.iter_poly_bm = extract_edituv_data_iter_poly_bm; extractor.iter_poly_mesh = extract_edituv_data_iter_poly_mesh; + extractor.init_subdiv = extract_edituv_data_init_subdiv; + extractor.iter_subdiv = extract_edituv_data_iter_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUVData_Data); extractor.use_threading = true; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc index a947d98f955..0ea4ef5d5db 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc @@ -27,6 +27,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -213,12 +215,69 @@ static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr } } +static GPUVertFormat *get_edituv_stretch_angle_format_subdiv() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* Waning: adjust #UVStretchAngle struct accordingly. */ + GPU_vertformat_attr_add(&format, "angle", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + return &format; +} + +static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(tls_data)) +{ + GPUVertBuf *refined_vbo = static_cast<GPUVertBuf *>(buffer); + + GPU_vertbuf_init_build_on_device( + refined_vbo, get_edituv_stretch_angle_format_subdiv(), subdiv_cache->num_subdiv_loops); + + GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor; + GPUVertBuf *uvs = cache->final.buff.vbo.uv; + + /* UVs are stored contiguouly so we need to compute the offset in the UVs buffer for the active + * UV layer. */ + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_MESH) ? &mr->me->ldata : &mr->bm->ldata; + + uint32_t uv_layers = cache->cd_used.uv; + /* HACK to fix T68857 */ + if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) { + int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); + if (layer != -1) { + uv_layers |= (1 << layer); + } + } + + int uvs_offset = 0; + for (int i = 0; i < MAX_MTFACE; i++) { + if (uv_layers & (1 << i)) { + if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { + break; + } + + uvs_offset += 1; + } + } + + /* The data is at `offset * num loops`, and we have 2 values per index. */ + uvs_offset *= subdiv_cache->num_subdiv_loops * 2; + + draw_subdiv_build_edituv_stretch_angle_buffer( + subdiv_cache, pos_nor, uvs, uvs_offset, refined_vbo); +} + constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle() { MeshExtract extractor = {nullptr}; extractor.init = extract_edituv_stretch_angle_init; extractor.iter_poly_bm = extract_edituv_stretch_angle_iter_poly_bm; extractor.iter_poly_mesh = extract_edituv_stretch_angle_iter_poly_mesh; + extractor.init_subdiv = extract_edituv_stretch_angle_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_StretchAngle_Data); extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc index 3db8cd79af5..3b40b3115f5 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc @@ -27,6 +27,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -63,14 +65,12 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_t return (ratio > 1.0f) ? (1.0f / ratio) : ratio; } -static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(data)) +static void compute_area_ratio(const MeshRenderData *mr, + float *r_area_ratio, + float &r_tot_area, + float &r_tot_uv_area) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); float tot_area = 0.0f, tot_uv_area = 0.0f; - float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__)); if (mr->extract_type == MR_EXTRACT_BMESH) { CustomData *cd_ldata = &mr->bm->ldata; @@ -84,7 +84,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, float uvarea = BM_face_calc_area_uv(efa, uv_ofs); tot_area += area; tot_uv_area += uvarea; - area_ratio[f] = area_ratio_get(area, uvarea); + r_area_ratio[f] = area_ratio_get(area, uvarea); } } else { @@ -96,12 +96,22 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, float uvarea = BKE_mesh_calc_poly_uv_area(mp, uv_data); tot_area += area; tot_uv_area += uvarea; - area_ratio[mp_index] = area_ratio_get(area, uvarea); + r_area_ratio[mp_index] = area_ratio_get(area, uvarea); } } - cache->tot_area = tot_area; - cache->tot_uv_area = tot_uv_area; + r_tot_area = tot_area; + r_tot_uv_area = tot_uv_area; +} + +static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__)); + compute_area_ratio(mr, area_ratio, cache->tot_area, cache->tot_uv_area); /* Convert in place to avoid an extra allocation */ uint16_t *poly_stretch = (uint16_t *)area_ratio; @@ -135,11 +145,46 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, MEM_freeN(area_ratio); } +static void extract_edituv_stretch_area_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + + /* Initialise final buffer. */ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + + GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops); + + /* Initialize coarse data buffer. */ + + GPUVertBuf *coarse_data = GPU_vertbuf_calloc(); + + /* We use the same format as we just copy data around. */ + GPU_vertbuf_init_with_format(coarse_data, &format); + GPU_vertbuf_data_alloc(coarse_data, mr->loop_len); + + compute_area_ratio(mr, + static_cast<float *>(GPU_vertbuf_get_data(coarse_data)), + cache->tot_area, + cache->tot_uv_area); + + draw_subdiv_build_edituv_stretch_area_buffer(subdiv_cache, coarse_data, vbo); + + GPU_vertbuf_discard(coarse_data); +} + constexpr MeshExtract create_extractor_edituv_stretch_area() { MeshExtract extractor = {nullptr}; extractor.init = extract_edituv_stretch_area_init; extractor.finish = extract_edituv_stretch_area_finish; + extractor.init_subdiv = extract_edituv_stretch_area_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc index 33f9180e122..f65159f9b95 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc @@ -23,24 +23,40 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ /** \name Extract Face-dots positions * \{ */ -static void extract_fdots_pos_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) +static GPUVertFormat *get_fdots_pos_format() { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); } + return &format; +} + +static GPUVertFormat *get_fdots_nor_format_subdiv() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + return &format; +} - GPU_vertbuf_init_with_format(vbo, &format); +static void extract_fdots_pos_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat *format = get_fdots_pos_format(); + GPU_vertbuf_init_with_format(vbo, format); GPU_vertbuf_data_alloc(vbo, mr->poly_len); void *vbo_data = GPU_vertbuf_get_data(vbo); *(float(**)[3])tls_data = static_cast<float(*)[3]>(vbo_data); @@ -97,10 +113,30 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, } } +static void extract_fdots_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + /* We "extract" positions, normals, and indices at once. */ + GPUVertBuf *fdots_pos_vbo = static_cast<GPUVertBuf *>(buffer); + GPUVertBuf *fdots_nor_vbo = cache->final.buff.vbo.fdots_nor; + GPUIndexBuf *fdots_pos_ibo = cache->final.buff.ibo.fdots; + + GPU_vertbuf_init_build_on_device( + fdots_nor_vbo, get_fdots_nor_format_subdiv(), subdiv_cache->num_coarse_poly); + GPU_vertbuf_init_build_on_device( + fdots_pos_vbo, get_fdots_pos_format(), subdiv_cache->num_coarse_poly); + GPU_indexbuf_init_build_on_device(fdots_pos_ibo, subdiv_cache->num_coarse_poly); + draw_subdiv_build_fdots_buffers(subdiv_cache, fdots_pos_vbo, fdots_nor_vbo, fdots_pos_ibo); +} + constexpr MeshExtract create_extractor_fdots_pos() { MeshExtract extractor = {nullptr}; extractor.init = extract_fdots_pos_init; + extractor.init_subdiv = extract_fdots_init_subdiv; extractor.iter_poly_bm = extract_fdots_pos_iter_poly_bm; extractor.iter_poly_mesh = extract_fdots_pos_iter_poly_mesh; extractor.data_type = MR_DATA_NONE; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc index 3c3ac7a7a0a..d30c38ef050 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc @@ -23,6 +23,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -107,10 +109,34 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, } } +static GPUVertFormat *get_subdiv_lnor_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "lnor"); + } + return &format; +} + +static void extract_lnor_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor; + BLI_assert(pos_nor); + GPU_vertbuf_init_build_on_device(vbo, get_subdiv_lnor_format(), subdiv_cache->num_subdiv_loops); + draw_subdiv_build_lnor_buffer(subdiv_cache, pos_nor, vbo); +} + constexpr MeshExtract create_extractor_lnor() { MeshExtract extractor = {nullptr}; extractor.init = extract_lnor_init; + extractor.init_subdiv = extract_lnor_init_subdiv; extractor.iter_poly_bm = extract_lnor_iter_poly_bm; extractor.iter_poly_mesh = extract_lnor_iter_poly_mesh; extractor.data_type = MR_DATA_LOOP_NOR; @@ -210,6 +236,7 @@ constexpr MeshExtract create_extractor_lnor_hq() { MeshExtract extractor = {nullptr}; extractor.init = extract_lnor_hq_init; + extractor.init_subdiv = extract_lnor_init_subdiv; extractor.iter_poly_bm = extract_lnor_hq_iter_poly_bm; extractor.iter_poly_mesh = extract_lnor_hq_iter_poly_mesh; extractor.data_type = MR_DATA_LOOP_NOR; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc index eb9a138590c..00ed4ca6359 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc @@ -25,6 +25,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -194,6 +196,123 @@ static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data->normals); } +static GPUVertFormat *get_pos_nor_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "vnor"); + } + return &format; +} + +static GPUVertFormat *get_normals_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "lnor"); + } + return &format; +} + +static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + const bool do_limit_normals = subdiv_cache->do_limit_normals; + + /* Initialize the vertex buffer, it was already allocated. */ + GPU_vertbuf_init_build_on_device( + vbo, get_pos_nor_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len); + + draw_subdiv_extract_pos_nor(subdiv_cache, vbo, do_limit_normals); + + if (!do_limit_normals) { + /* We cannot evaluate vertex normals using the limit surface, so compute them manually. */ + GPUVertBuf *subdiv_loop_subdiv_vert_index = draw_subdiv_build_origindex_buffer( + subdiv_cache->subdiv_loop_subdiv_vert_index, subdiv_cache->num_subdiv_loops); + + GPUVertBuf *vertex_normals = GPU_vertbuf_calloc(); + GPU_vertbuf_init_build_on_device( + vertex_normals, get_normals_format(), subdiv_cache->num_subdiv_verts); + + draw_subdiv_accumulate_normals(subdiv_cache, + vbo, + subdiv_cache->subdiv_vertex_face_adjacency_offsets, + subdiv_cache->subdiv_vertex_face_adjacency, + vertex_normals); + + draw_subdiv_finalize_normals(subdiv_cache, vertex_normals, subdiv_loop_subdiv_vert_index, vbo); + + GPU_vertbuf_discard(vertex_normals); + GPU_vertbuf_discard(subdiv_loop_subdiv_vert_index); + } +} + +static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + const Mesh *coarse_mesh = subdiv_cache->mesh; + const MEdge *coarse_edges = coarse_mesh->medge; + const MVert *coarse_verts = coarse_mesh->mvert; + uint offset = subdiv_cache->num_subdiv_loops; + + /* TODO(kevindietrich) : replace this when compressed normals are supported. */ + struct SubdivPosNorLoop { + float pos[3]; + float nor[3]; + float flag; + }; + + SubdivPosNorLoop edge_data[2]; + for (int i = 0; i < loose_geom->edge_len; i++) { + const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]]; + const MVert *loose_vert1 = &coarse_verts[loose_edge->v1]; + const MVert *loose_vert2 = &coarse_verts[loose_edge->v2]; + + copy_v3_v3(edge_data[0].pos, loose_vert1->co); + normal_short_to_float_v3(edge_data[0].nor, loose_vert1->no); + edge_data[0].flag = 0.0f; + + copy_v3_v3(edge_data[1].pos, loose_vert2->co); + normal_short_to_float_v3(edge_data[1].nor, loose_vert2->no); + edge_data[1].flag = 0.0f; + + GPU_vertbuf_update_sub( + vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data); + + offset += 2; + } + + SubdivPosNorLoop vert_data; + vert_data.flag = 0.0f; + for (int i = 0; i < loose_geom->vert_len; i++) { + const MVert *loose_vertex = &coarse_verts[loose_geom->verts[i]]; + + copy_v3_v3(vert_data.pos, loose_vertex->co); + normal_short_to_float_v3(vert_data.nor, loose_vertex->no); + + GPU_vertbuf_update_sub( + vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data); + + offset += 1; + } +} + constexpr MeshExtract create_extractor_pos_nor() { MeshExtract extractor = {nullptr}; @@ -205,6 +324,8 @@ constexpr MeshExtract create_extractor_pos_nor() extractor.iter_lvert_bm = extract_pos_nor_iter_lvert_bm; extractor.iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh; extractor.finish = extract_pos_nor_finish; + extractor.init_subdiv = extract_pos_nor_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_pos_nor_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_PosNor_Data); extractor.use_threading = true; @@ -391,6 +512,7 @@ constexpr MeshExtract create_extractor_pos_nor_hq() { MeshExtract extractor = {nullptr}; extractor.init = extract_pos_nor_hq_init; + extractor.init_subdiv = extract_pos_nor_init_subdiv; extractor.iter_poly_bm = extract_pos_nor_hq_iter_poly_bm; extractor.iter_poly_mesh = extract_pos_nor_hq_iter_poly_mesh; extractor.iter_ledge_bm = extract_pos_nor_hq_iter_ledge_bm; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc index fd91bc5258f..753fbe7e0e2 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc @@ -27,6 +27,7 @@ #include "BKE_paint.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -35,13 +36,23 @@ namespace blender::draw { /** \name Extract Sculpt Data * \{ */ +static GPUVertFormat *get_sculpt_data_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + return &format; +} + static void extract_sculpt_data_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(tls_data)) { GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); - GPUVertFormat format = {0}; + GPUVertFormat *format = get_sculpt_data_format(); CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; @@ -50,12 +61,7 @@ static void extract_sculpt_data_init(const MeshRenderData *mr, float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK); int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS); - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - } - - GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_init_with_format(vbo, format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); struct gpuSculptData { @@ -121,10 +127,99 @@ static void extract_sculpt_data_init(const MeshRenderData *mr, } } +static void extract_sculpt_data_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + + Mesh *coarse_mesh = mr->me; + CustomData *cd_vdata = &coarse_mesh->vdata; + CustomData *cd_pdata = &coarse_mesh->pdata; + + /* First, interpolate mask if available. */ + GPUVertBuf *mask_vbo = nullptr; + GPUVertBuf *subdiv_mask_vbo = nullptr; + float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK); + + if (cd_mask) { + GPUVertFormat mask_format = {0}; + GPU_vertformat_attr_add(&mask_format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + + mask_vbo = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format(mask_vbo, &mask_format); + GPU_vertbuf_data_alloc(mask_vbo, coarse_mesh->totloop); + float *v_mask = static_cast<float *>(GPU_vertbuf_get_data(mask_vbo)); + + for (int i = 0; i < coarse_mesh->totpoly; i++) { + const MPoly *mpoly = &coarse_mesh->mpoly[i]; + + for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop; + loop_index++) { + const MLoop *ml = &coarse_mesh->mloop[loop_index]; + *v_mask++ = cd_mask[ml->v]; + } + } + + subdiv_mask_vbo = GPU_vertbuf_calloc(); + GPU_vertbuf_init_build_on_device( + subdiv_mask_vbo, &mask_format, subdiv_cache->num_subdiv_loops); + + draw_subdiv_interp_custom_data(subdiv_cache, mask_vbo, subdiv_mask_vbo, 1, 0); + } + + /* Then, gather face sets. */ + GPUVertFormat face_set_format = {0}; + GPU_vertformat_attr_add(&face_set_format, "msk", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + + GPUVertBuf *face_set_vbo = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format(face_set_vbo, &face_set_format); + GPU_vertbuf_data_alloc(face_set_vbo, subdiv_cache->num_subdiv_loops); + + struct gpuFaceSet { + uint8_t color[4]; + }; + + gpuFaceSet *face_sets = (gpuFaceSet *)GPU_vertbuf_get_data(face_set_vbo); + int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS); + + GPUVertFormat *format = get_sculpt_data_format(); + GPU_vertbuf_init_build_on_device(vbo, format, subdiv_cache->num_subdiv_loops); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + + for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) { + const int mp_index = subdiv_loop_poly_index[i]; + + uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; + if (cd_face_set) { + const int face_set_id = cd_face_set[mp_index]; + /* Skip for the default color Face Set to render it white. */ + if (face_set_id != coarse_mesh->face_sets_color_default) { + BKE_paint_face_set_overlay_color_get( + face_set_id, coarse_mesh->face_sets_color_seed, face_set_color); + } + } + copy_v3_v3_uchar(face_sets->color, face_set_color); + face_sets++; + } + + /* Finally, interleave mask and face sets. */ + draw_subdiv_build_sculpt_data_buffer(subdiv_cache, subdiv_mask_vbo, face_set_vbo, vbo); + + if (mask_vbo) { + GPU_vertbuf_discard(mask_vbo); + GPU_vertbuf_discard(subdiv_mask_vbo); + } + GPU_vertbuf_discard(face_set_vbo); +} + constexpr MeshExtract create_extractor_sculpt_data() { MeshExtract extractor = {nullptr}; extractor.init = extract_sculpt_data_init; + extractor.init_subdiv = extract_sculpt_data_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc index 5ac30dd3be9..33c27b45627 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc @@ -21,6 +21,7 @@ * \ingroup draw */ +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -196,12 +197,104 @@ static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr, (*(uint32_t **)data)[offset + lvert_index] = v_orig; } +static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + /* Each element points to an element in the ibo.points. */ + draw_subdiv_init_origindex_buffer(vbo, + subdiv_cache->subdiv_loop_subdiv_vert_index, + subdiv_cache->num_subdiv_loops, + mr->loop_loose_len); +} + +static void extract_vert_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo); + const Mesh *coarse_mesh = subdiv_cache->mesh; + const MEdge *coarse_edges = coarse_mesh->medge; + uint offset = subdiv_cache->num_subdiv_loops; + + for (int i = 0; i < loose_geom->edge_len; i++) { + const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]]; + vert_idx_data[offset] = loose_edge->v1; + vert_idx_data[offset + 1] = loose_edge->v2; + offset += 2; + } + + for (int i = 0; i < loose_geom->vert_len; i++) { + vert_idx_data[offset] = loose_geom->verts[i]; + offset += 1; + } +} + +static void extract_edge_idx_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + draw_subdiv_init_origindex_buffer( + vbo, + static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)), + subdiv_cache->num_subdiv_loops, + mr->edge_loose_len * 2); +} + +static void extract_edge_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo); + uint offset = subdiv_cache->num_subdiv_loops; + + for (int i = 0; i < loose_geom->edge_len; i++) { + vert_idx_data[offset] = loose_geom->edges[i]; + vert_idx_data[offset + 1] = loose_geom->edges[i]; + offset += 2; + } +} + +static void extract_poly_idx_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + draw_subdiv_init_origindex_buffer( + vbo, subdiv_cache->subdiv_loop_poly_index, subdiv_cache->num_subdiv_loops, 0); +} + constexpr MeshExtract create_extractor_poly_idx() { MeshExtract extractor = {nullptr}; extractor.init = extract_select_idx_init; extractor.iter_poly_bm = extract_poly_idx_iter_poly_bm; extractor.iter_poly_mesh = extract_poly_idx_iter_poly_mesh; + extractor.init_subdiv = extract_poly_idx_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; @@ -217,6 +310,8 @@ constexpr MeshExtract create_extractor_edge_idx() extractor.iter_poly_mesh = extract_edge_idx_iter_poly_mesh; extractor.iter_ledge_bm = extract_edge_idx_iter_ledge_bm; extractor.iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh; + extractor.init_subdiv = extract_edge_idx_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_edge_idx_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; @@ -234,6 +329,8 @@ constexpr MeshExtract create_extractor_vert_idx() extractor.iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh; extractor.iter_lvert_bm = extract_vert_idx_iter_lvert_bm; extractor.iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh; + extractor.init_subdiv = extract_vert_idx_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_vert_idx_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc index af279b08a59..6e9d8ef6926 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc @@ -23,6 +23,7 @@ #include "BLI_string.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -31,25 +32,27 @@ namespace blender::draw { /** \name Extract UV layers * \{ */ -static void extract_uv_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(tls_data)) +/* Initialize the vertex format to be used for UVs. Return true if any UV layer is + * found, false otherwise. */ +static bool mesh_extract_uv_format_init(GPUVertFormat *format, + struct MeshBatchCache *cache, + CustomData *cd_ldata, + eMRExtractType extract_type, + uint32_t &r_uv_layers) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); - GPUVertFormat format = {0}; - GPU_vertformat_deinterleave(&format); + GPU_vertformat_deinterleave(format); - CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; uint32_t uv_layers = cache->cd_used.uv; /* HACK to fix T68857 */ - if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) { + if (extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) { int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { uv_layers |= (1 << layer); } } + r_uv_layers = uv_layers; + for (int i = 0; i < MAX_MTFACE; i++) { if (uv_layers & (1 << i)) { char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; @@ -58,30 +61,47 @@ static void extract_uv_init(const MeshRenderData *mr, GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); /* UV layer name. */ BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name); - GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); /* Auto layer name. */ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); - GPU_vertformat_alias_add(&format, attr_name); + GPU_vertformat_alias_add(format, attr_name); /* Active render layer name. */ if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) { - GPU_vertformat_alias_add(&format, "u"); + GPU_vertformat_alias_add(format, "u"); } /* Active display layer name. */ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { - GPU_vertformat_alias_add(&format, "au"); + GPU_vertformat_alias_add(format, "au"); /* Alias to `pos` for edit uvs. */ - GPU_vertformat_alias_add(&format, "pos"); + GPU_vertformat_alias_add(format, "pos"); } /* Stencil mask uv layer name. */ if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) { - GPU_vertformat_alias_add(&format, "mu"); + GPU_vertformat_alias_add(format, "mu"); } } } + if (format->attr_len == 0) { + GPU_vertformat_attr_add(format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + return false; + } + + return true; +} + +static void extract_uv_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat format = {0}; + + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; int v_len = mr->loop_len; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + uint32_t uv_layers = cache->cd_used.uv; + if (!mesh_extract_uv_format_init(&format, cache, cd_ldata, mr->extract_type, uv_layers)) { /* VBO will not be used, only allocate minimum of memory. */ v_len = 1; } @@ -116,10 +136,45 @@ static void extract_uv_init(const MeshRenderData *mr, } } +static void extract_uv_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + Mesh *coarse_mesh = subdiv_cache->mesh; + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + GPUVertFormat format = {0}; + + uint v_len = subdiv_cache->num_subdiv_loops; + uint uv_layers; + if (!mesh_extract_uv_format_init( + &format, cache, &coarse_mesh->ldata, MR_EXTRACT_MESH, uv_layers)) { + // TODO(kevindietrich): handle this more gracefully. + v_len = 1; + } + + GPU_vertbuf_init_build_on_device(vbo, &format, v_len); + + if (uv_layers == 0) { + return; + } + + /* Index of the UV layer in the compact buffer. Used UV layers are stored in a single buffer. */ + int pack_layer_index = 0; + for (int i = 0; i < MAX_MTFACE; i++) { + if (uv_layers & (1 << i)) { + const int offset = (int)subdiv_cache->num_subdiv_loops * pack_layer_index++; + draw_subdiv_extract_uvs(subdiv_cache, vbo, i, offset); + } + } +} + constexpr MeshExtract create_extractor_uv() { MeshExtract extractor = {nullptr}; extractor.init = extract_uv_init; + extractor.init_subdiv = extract_uv_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc index f8878eb2617..ea7810bcf6b 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc @@ -25,6 +25,7 @@ #include "BLI_string.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -33,17 +34,14 @@ namespace blender::draw { /** \name Extract VCol * \{ */ -static void extract_vcol_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(tls_data)) +/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */ +static void init_vcol_format(GPUVertFormat *format, + const MeshBatchCache *cache, + CustomData *cd_ldata) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); - GPUVertFormat format = {0}; - GPU_vertformat_deinterleave(&format); + GPU_vertformat_deinterleave(format); - CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; - uint32_t vcol_layers = cache->cd_used.vcol; + const uint32_t vcol_layers = cache->cd_used.vcol; for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { @@ -52,31 +50,56 @@ static void extract_vcol_init(const MeshRenderData *mr, GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name); - GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_attr_add(format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) { - GPU_vertformat_alias_add(&format, "c"); + GPU_vertformat_alias_add(format, "c"); } if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) { - GPU_vertformat_alias_add(&format, "ac"); + GPU_vertformat_alias_add(format, "ac"); } /* Gather number of auto layers. */ /* We only do `vcols` that are not overridden by `uvs`. */ if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) { BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); - GPU_vertformat_alias_add(&format, attr_name); + GPU_vertformat_alias_add(format, attr_name); } } } +} + +/* Vertex format for vertex colors, only used during the coarse data upload for the subdivision + * case. */ +static GPUVertFormat *get_coarse_vcol_format(void) +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "cCol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "c"); + GPU_vertformat_alias_add(&format, "ac"); + } + return &format; +} + +using gpuMeshVcol = struct gpuMeshVcol { + ushort r, g, b, a; +}; + +static void extract_vcol_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat format = {0}; + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + const uint32_t vcol_layers = cache->cd_used.vcol; + init_vcol_format(&format, cache, cd_ldata); GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); - using gpuMeshVcol = struct gpuMeshVcol { - ushort r, g, b, a; - }; - gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo); for (int i = 0; i < MAX_MCOL; i++) { @@ -111,10 +134,64 @@ static void extract_vcol_init(const MeshRenderData *mr, } } +static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer); + Mesh *coarse_mesh = subdiv_cache->mesh; + + GPUVertFormat format = {0}; + init_vcol_format(&format, cache, &coarse_mesh->ldata); + + GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops); + + GPUVertBuf *src_data = GPU_vertbuf_calloc(); + /* Dynamic as we upload and interpolate layers one at a time. */ + GPU_vertbuf_init_with_format_ex(src_data, get_coarse_vcol_format(), GPU_USAGE_DYNAMIC); + + GPU_vertbuf_data_alloc(src_data, coarse_mesh->totloop); + + gpuMeshVcol *mesh_vcol = (gpuMeshVcol *)GPU_vertbuf_get_data(src_data); + + const CustomData *cd_ldata = &coarse_mesh->ldata; + + const uint vcol_layers = cache->cd_used.vcol; + + /* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in + * a single buffer. */ + int pack_layer_index = 0; + for (int i = 0; i < MAX_MTFACE; i++) { + if (vcol_layers & (1 << i)) { + /* Include stride in offset, we use a stride of 2 since colors are packed into 2 uints. */ + const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++; + const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); + + gpuMeshVcol *vcol = mesh_vcol; + + for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, mloopcol++) { + vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); + vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); + vcol->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); + vcol->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); + } + + /* Ensure data is uploaded properly. */ + GPU_vertbuf_tag_dirty(src_data); + draw_subdiv_interp_custom_data(subdiv_cache, src_data, dst_buffer, 4, dst_offset); + } + } + + GPU_vertbuf_discard(src_data); +} + constexpr MeshExtract create_extractor_vcol() { MeshExtract extractor = {nullptr}; extractor.init = extract_vcol_init; + extractor.init_subdiv = extract_vcol_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc index bdb1410a755..bb8853b8154 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc @@ -25,6 +25,7 @@ #include "BKE_deform.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -167,10 +168,57 @@ static void extract_weights_iter_poly_mesh(const MeshRenderData *mr, } } +static void extract_weights_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + Mesh *coarse_mesh = subdiv_cache->mesh; + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops); + + GPUVertBuf *coarse_weights = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format(coarse_weights, &format); + GPU_vertbuf_data_alloc(coarse_weights, coarse_mesh->totloop); + float *coarse_weights_data = static_cast<float *>(GPU_vertbuf_get_data(coarse_weights)); + + const DRW_MeshWeightState *wstate = &cache->weight_state; + const MDeformVert *dverts = static_cast<const MDeformVert *>( + CustomData_get_layer(&coarse_mesh->vdata, CD_MDEFORMVERT)); + + for (int i = 0; i < coarse_mesh->totpoly; i++) { + const MPoly *mpoly = &coarse_mesh->mpoly[i]; + + for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop; + loop_index++) { + const MLoop *ml = &coarse_mesh->mloop[loop_index]; + + if (dverts != nullptr) { + const MDeformVert *dvert = &dverts[ml->v]; + coarse_weights_data[loop_index] = evaluate_vertex_weight(dvert, wstate); + } + else { + coarse_weights_data[loop_index] = evaluate_vertex_weight(nullptr, wstate); + } + } + } + + draw_subdiv_interp_custom_data(subdiv_cache, coarse_weights, vbo, 1, 0); + + GPU_vertbuf_discard(coarse_weights); +} + constexpr MeshExtract create_extractor_weights() { MeshExtract extractor = {nullptr}; extractor.init = extract_weights_init; + extractor.init_subdiv = extract_weights_init_subdiv; extractor.iter_poly_bm = extract_weights_iter_poly_bm; extractor.iter_poly_mesh = extract_weights_iter_poly_mesh; extractor.data_type = MR_DATA_NONE; |