Mesh: Edit data draw extraction improvement

Part of #116901.

Avoid the "extractor" abstraction for creation of edit mode overlay data
vertex buffers. Use threading::parallel_for loops instead. Also prefer
code duplication over linking things that are unrelated. This is the
last "extractor" loop that runs by default in edit mode so there is a
small performance improvement there. Besides that, the changes is the
same as the other similar refactors.

Pull Request: https://projects.blender.org/blender/blender/pulls/122386
This commit is contained in:
Hans Goudey 2024-05-28 18:06:08 +02:00 committed by Hans Goudey
parent 9d3e2de76e
commit 48cc79f52d
3 changed files with 276 additions and 234 deletions

@ -547,6 +547,7 @@ static void mesh_extract_render_data_node_exec(void *__restrict task_data)
const bool calc_loose_geom = DRW_ibo_requested(buffers.ibo.lines) ||
DRW_ibo_requested(buffers.ibo.lines_loose) ||
DRW_ibo_requested(buffers.ibo.points) ||
DRW_vbo_requested(buffers.vbo.edit_data) ||
(iter_type & (MR_ITER_LOOSE_EDGE | MR_ITER_LOOSE_VERT)) ||
(data_flag & MR_DATA_LOOSE_GEOM);
@ -645,7 +646,6 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
EXTRACT_ADD_REQUESTED(vbo, orco);
EXTRACT_ADD_REQUESTED(vbo, edge_fac);
EXTRACT_ADD_REQUESTED(vbo, weights);
EXTRACT_ADD_REQUESTED(vbo, edit_data);
EXTRACT_ADD_REQUESTED(vbo, edituv_data);
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_area);
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
@ -678,7 +678,7 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
if (extractors.is_empty() && !DRW_ibo_requested(buffers.ibo.lines) &&
!DRW_ibo_requested(buffers.ibo.lines_loose) && !DRW_ibo_requested(buffers.ibo.tris) &&
!DRW_ibo_requested(buffers.ibo.points) && !DRW_vbo_requested(buffers.vbo.pos) &&
!DRW_vbo_requested(buffers.vbo.nor))
!DRW_vbo_requested(buffers.vbo.nor) && !DRW_vbo_requested(buffers.vbo.edit_data))
{
return;
}
@ -797,6 +797,21 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
[](void *task_data) { delete static_cast<TaskData *>(task_data); });
BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
}
if (DRW_vbo_requested(buffers.vbo.edit_data)) {
struct TaskData {
MeshRenderData &mr;
MeshBufferList &buffers;
};
TaskNode *task_node = BLI_task_graph_node_create(
&task_graph,
[](void *__restrict task_data) {
const TaskData &data = *static_cast<TaskData *>(task_data);
extract_edit_data(data.mr, *data.buffers.vbo.edit_data);
},
new TaskData{*mr, buffers},
[](void *task_data) { delete static_cast<TaskData *>(task_data); });
BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
}
if (use_thread) {
/* First run the requested extractors that do not support asynchronous ranges. */
@ -904,7 +919,6 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
EXTRACT_ADD_REQUESTED(vbo, edge_idx);
EXTRACT_ADD_REQUESTED(vbo, face_idx);
EXTRACT_ADD_REQUESTED(vbo, edge_fac);
EXTRACT_ADD_REQUESTED(vbo, edit_data);
EXTRACT_ADD_REQUESTED(vbo, edituv_data);
/* Make sure UVs are computed before edituv stuffs. */
EXTRACT_ADD_REQUESTED(vbo, uv);
@ -921,7 +935,8 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
if (extractors.is_empty() && !DRW_ibo_requested(buffers.ibo.lines) &&
!DRW_ibo_requested(buffers.ibo.lines_loose) && !DRW_ibo_requested(buffers.ibo.tris) &&
!DRW_ibo_requested(buffers.ibo.points) && !DRW_vbo_requested(buffers.vbo.pos) &&
!DRW_vbo_requested(buffers.vbo.orco) && !DRW_vbo_requested(buffers.vbo.nor))
!DRW_vbo_requested(buffers.vbo.orco) && !DRW_vbo_requested(buffers.vbo.nor) &&
!DRW_vbo_requested(buffers.vbo.edit_data))
{
return;
}
@ -947,6 +962,9 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
if (DRW_ibo_requested(buffers.ibo.points)) {
extract_points_subdiv(mr, subdiv_cache, *buffers.ibo.points);
}
if (DRW_vbo_requested(buffers.vbo.edit_data)) {
extract_edit_data_subdiv(mr, subdiv_cache, *buffers.vbo.edit_data);
}
void *data_stack = MEM_mallocN(extractors.data_size_total(), __func__);
uint32_t data_offset = 0;

@ -377,6 +377,11 @@ void extract_points_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
gpu::IndexBuf &points);
void extract_edit_data(const MeshRenderData &mr, gpu::VertBuf &vbo);
void extract_edit_data_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
gpu::VertBuf &vbo);
extern const MeshExtract extract_fdots;
extern const MeshExtract extract_lines_paint_mask;
extern const MeshExtract extract_lines_adjacency;
@ -392,7 +397,6 @@ extern const MeshExtract extract_vcol;
extern const MeshExtract extract_orco;
extern const MeshExtract extract_edge_fac;
extern const MeshExtract extract_weights;
extern const MeshExtract extract_edit_data;
extern const MeshExtract extract_edituv_data;
extern const MeshExtract extract_edituv_stretch_area;
extern const MeshExtract extract_edituv_stretch_angle;

@ -16,10 +16,6 @@
namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Edit Mode Data / Flags
* \{ */
static void mesh_render_data_edge_flag(const MeshRenderData &mr,
const BMEdge *eed,
EditLoopData &eattr)
@ -115,267 +111,291 @@ static GPUVertFormat *get_edit_data_format()
return &format;
}
static void extract_edit_data_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void *tls_data)
static void extract_edit_data_mesh(const MeshRenderData &mr, MutableSpan<EditLoopData> vbo_data)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
GPUVertFormat *format = get_edit_data_format();
GPU_vertbuf_init_with_format(vbo, format);
GPU_vertbuf_data_alloc(vbo, mr.corners_num + mr.loose_indices_num);
EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
*(EditLoopData **)tls_data = vbo_data;
}
MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
MutableSpan loose_edge_data = vbo_data.slice(mr.corners_num, mr.loose_edges.size() * 2);
MutableSpan loose_vert_data = vbo_data.take_back(mr.loose_verts.size());
static void extract_edit_data_iter_face_bm(const MeshRenderData &mr,
const BMFace *f,
const int /*f_index*/,
void *_data)
{
EditLoopData *vbo_data = *(EditLoopData **)_data;
BMLoop *l_iter, *l_first;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
const int l_index = BM_elem_index_get(l_iter);
EditLoopData *data = vbo_data + l_index;
memset(data, 0x0, sizeof(*data));
mesh_render_data_face_flag(mr, f, {-1, -1, -1, -1}, *data);
mesh_render_data_edge_flag(mr, l_iter->e, *data);
mesh_render_data_vert_flag(mr, l_iter->v, *data);
} while ((l_iter = l_iter->next) != l_first);
}
static void extract_edit_data_iter_face_mesh(const MeshRenderData &mr,
const int face_index,
void *_data)
{
EditLoopData *vbo_data = *(EditLoopData **)_data;
for (const int corner : mr.faces[face_index]) {
EditLoopData *data = vbo_data + corner;
memset(data, 0x0, sizeof(*data));
BMFace *efa = bm_original_face_get(mr, face_index);
BMVert *eve = bm_original_vert_get(mr, mr.corner_verts[corner]);
BMEdge *eed = bm_original_edge_get(mr, mr.corner_edges[corner]);
if (efa) {
mesh_render_data_face_flag(mr, efa, {-1, -1, -1, -1}, *data);
const OffsetIndices faces = mr.faces;
const Span<int> corner_verts = mr.corner_verts;
const Span<int> corner_edges = mr.corner_edges;
threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
for (const int face : range) {
for (const int corner : faces[face]) {
EditLoopData &value = corners_data[corner];
value = {};
if (const BMFace *bm_face = bm_original_face_get(mr, face)) {
mesh_render_data_face_flag(mr, bm_face, {-1, -1, -1, -1}, value);
}
if (eed) {
mesh_render_data_edge_flag(mr, eed, *data);
if (const BMVert *bm_vert = bm_original_vert_get(mr, corner_verts[corner])) {
mesh_render_data_vert_flag(mr, bm_vert, value);
}
if (eve) {
mesh_render_data_vert_flag(mr, eve, *data);
if (const BMEdge *bm_edge = bm_original_edge_get(mr, corner_edges[corner])) {
mesh_render_data_edge_flag(mr, bm_edge, value);
}
}
}
static void extract_edit_data_iter_loose_edge_bm(const MeshRenderData &mr,
const BMEdge *eed,
const int loose_edge_i,
void *_data)
{
EditLoopData *vbo_data = *(EditLoopData **)_data;
EditLoopData *data = vbo_data + mr.corners_num + (loose_edge_i * 2);
memset(data, 0x0, sizeof(*data) * 2);
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]);
}
static void extract_edit_data_iter_loose_edge_mesh(const MeshRenderData &mr,
const int2 edge,
const int loose_edge_i,
void *_data)
{
EditLoopData *vbo_data = *(EditLoopData **)_data;
EditLoopData *data = vbo_data + mr.corners_num + loose_edge_i * 2;
memset(data, 0x0, sizeof(*data) * 2);
const int e_index = mr.loose_edges[loose_edge_i];
BMEdge *eed = bm_original_edge_get(mr, e_index);
BMVert *eve1 = bm_original_vert_get(mr, edge[0]);
BMVert *eve2 = bm_original_vert_get(mr, edge[1]);
if (eed) {
mesh_render_data_edge_flag(mr, eed, data[0]);
data[1] = data[0];
}
if (eve1) {
mesh_render_data_vert_flag(mr, eve1, data[0]);
}
if (eve2) {
mesh_render_data_vert_flag(mr, eve2, data[1]);
}
}
});
static void extract_edit_data_iter_loose_vert_bm(const MeshRenderData &mr,
const BMVert *eve,
const int loose_vert_i,
void *_data)
{
EditLoopData *vbo_data = *(EditLoopData **)_data;
const int offset = mr.corners_num + (mr.loose_edges_num * 2);
EditLoopData *data = vbo_data + offset + loose_vert_i;
memset(data, 0x0, sizeof(*data));
mesh_render_data_vert_flag(mr, eve, *data);
}
static void extract_edit_data_iter_loose_vert_mesh(const MeshRenderData &mr,
const int loose_vert_i,
void *_data)
{
EditLoopData *vbo_data = *(EditLoopData **)_data;
const int offset = mr.corners_num + (mr.loose_edges_num * 2);
EditLoopData *data = vbo_data + offset + loose_vert_i;
memset(data, 0x0, sizeof(*data));
const int v_index = mr.loose_verts[loose_vert_i];
BMVert *eve = bm_original_vert_get(mr, v_index);
if (eve) {
mesh_render_data_vert_flag(mr, eve, *data);
}
}
static void extract_edit_data_loose_geom_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
void *buffer,
void * /*data*/)
{
const Span<int> loose_verts = mr.loose_verts;
const Span<int2> edges = mr.edges;
const Span<int> loose_edges = mr.loose_edges;
if (loose_verts.is_empty() && loose_edges.is_empty()) {
return;
}
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buffer);
MutableSpan<EditLoopData> vbo_data(static_cast<EditLoopData *>(GPU_vertbuf_get_data(vbo)),
subdiv_full_vbo_size(mr, subdiv_cache));
const int verts_per_edge = subdiv_verts_per_coarse_edge(subdiv_cache);
MutableSpan<EditLoopData> edge_data = vbo_data.slice(subdiv_cache.num_subdiv_loops,
loose_edges.size() * verts_per_edge);
threading::parallel_for(loose_edges.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
MutableSpan<EditLoopData> data = edge_data.slice(i * verts_per_edge, verts_per_edge);
if (BMEdge *edge = mr.orig_index_edge ? bm_original_edge_get(mr, loose_edges[i]) :
BM_edge_at_index(mr.bm, loose_edges[i]))
{
EditLoopData &value_1 = loose_edge_data[i * 2 + 0];
EditLoopData &value_2 = loose_edge_data[i * 2 + 1];
if (const BMEdge *bm_edge = bm_original_edge_get(mr, loose_edges[i])) {
value_1 = {};
mesh_render_data_edge_flag(mr, bm_edge, value_1);
value_2 = value_1;
}
else {
value_2 = value_1 = {};
}
const int2 edge = edges[loose_edges[i]];
if (const BMVert *bm_vert = bm_original_vert_get(mr, edge[0])) {
mesh_render_data_vert_flag(mr, bm_vert, value_1);
}
if (const BMVert *bm_vert = bm_original_vert_get(mr, edge[1])) {
mesh_render_data_vert_flag(mr, bm_vert, value_2);
}
}
});
const Span<int> loose_verts = mr.loose_verts;
threading::parallel_for(loose_verts.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
loose_vert_data[i] = {};
if (const BMVert *eve = bm_original_vert_get(mr, loose_verts[i])) {
mesh_render_data_vert_flag(mr, eve, loose_vert_data[i]);
}
}
});
}
static void extract_edit_data_bm(const MeshRenderData &mr, MutableSpan<EditLoopData> vbo_data)
{
MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
MutableSpan loose_edge_data = vbo_data.slice(mr.corners_num, mr.loose_edges.size() * 2);
MutableSpan loose_vert_data = vbo_data.take_back(mr.loose_verts.size());
const BMesh &bm = *mr.bm;
threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
for (const int face_index : range) {
const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
for ([[maybe_unused]] const int i : IndexRange(face.len)) {
const int index = BM_elem_index_get(loop);
EditLoopData &value = corners_data[index];
value = {};
mesh_render_data_face_flag(mr, &face, {-1, -1, -1, -1}, corners_data[index]);
mesh_render_data_edge_flag(mr, loop->e, corners_data[index]);
mesh_render_data_vert_flag(mr, loop->v, corners_data[index]);
loop = loop->next;
}
}
});
const Span<int> loose_edges = mr.loose_edges;
threading::parallel_for(loose_edges.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
EditLoopData &value_1 = loose_edge_data[i * 2 + 0];
EditLoopData &value_2 = loose_edge_data[i * 2 + 1];
const BMEdge &edge = *BM_edge_at_index(&const_cast<BMesh &>(bm), loose_edges[i]);
value_1 = {};
mesh_render_data_edge_flag(mr, &edge, value_1);
value_2 = value_1;
mesh_render_data_vert_flag(mr, edge.v1, value_1);
mesh_render_data_vert_flag(mr, edge.v2, value_2);
}
});
const Span<int> loose_verts = mr.loose_verts;
threading::parallel_for(loose_verts.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
loose_vert_data[i] = {};
const BMVert &vert = *BM_vert_at_index(&const_cast<BMesh &>(bm), loose_verts[i]);
mesh_render_data_vert_flag(mr, &vert, loose_vert_data[i]);
}
});
}
void extract_edit_data(const MeshRenderData &mr, gpu::VertBuf &vbo)
{
GPUVertFormat *format = get_edit_data_format();
GPU_vertbuf_init_with_format(&vbo, format);
const int size = mr.corners_num + mr.loose_indices_num;
GPU_vertbuf_data_alloc(&vbo, size);
MutableSpan vbo_data(static_cast<EditLoopData *>(GPU_vertbuf_get_data(&vbo)), size);
if (mr.extract_type == MR_EXTRACT_MESH) {
extract_edit_data_mesh(mr, vbo_data);
}
else {
extract_edit_data_bm(mr, vbo_data);
}
}
static void extract_edit_subdiv_data_mesh(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
MutableSpan<EditLoopData> vbo_data)
{
const int corners_num = subdiv_cache.num_subdiv_loops;
const int loose_edges_num = mr.loose_edges.size();
const int verts_per_edge = subdiv_verts_per_coarse_edge(subdiv_cache);
const Span<int> subdiv_loop_face_index(subdiv_cache.subdiv_loop_face_index, corners_num);
const Span<int> subdiv_loop_vert_index(
static_cast<const int *>(GPU_vertbuf_get_data(subdiv_cache.verts_orig_index)), corners_num);
/* NOTE: #subdiv_loop_edge_index already has the origindex layer baked in. */
const Span<int> subdiv_loop_edge_index(
static_cast<const int *>(GPU_vertbuf_get_data(subdiv_cache.edges_orig_index)), corners_num);
MutableSpan corners_data = vbo_data.take_front(corners_num);
MutableSpan loose_edge_data = vbo_data.slice(corners_num, loose_edges_num * verts_per_edge);
MutableSpan loose_vert_data = vbo_data.take_back(mr.loose_verts.size());
threading::parallel_for(IndexRange(subdiv_cache.num_subdiv_quads), 2048, [&](IndexRange range) {
for (const int subdiv_quad : range) {
const int coarse_face = subdiv_loop_face_index[subdiv_quad * 4];
for (const int subdiv_corner : IndexRange(subdiv_quad * 4, 4)) {
EditLoopData &value = corners_data[subdiv_corner];
value = {};
if (const BMFace *bm_face = bm_original_face_get(mr, coarse_face)) {
mesh_render_data_face_flag(mr, bm_face, {-1, -1, -1, -1}, value);
}
const int vert_origindex = subdiv_loop_vert_index[subdiv_corner];
if (vert_origindex != -1) {
if (const BMVert *bm_vert = bm_original_vert_get(mr, vert_origindex)) {
mesh_render_data_vert_flag(mr, bm_vert, value);
}
}
const int edge_origindex = subdiv_loop_edge_index[subdiv_corner];
if (edge_origindex != -1) {
if (const BMEdge *bm_edge = BM_edge_at_index(mr.bm, edge_origindex)) {
mesh_render_data_edge_flag(mr, bm_edge, value);
}
}
}
}
});
const Span<int2> edges = mr.edges;
const Span<int> loose_edges = mr.loose_edges;
threading::parallel_for(loose_edges.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
MutableSpan<EditLoopData> data = loose_edge_data.slice(i * verts_per_edge, verts_per_edge);
if (const BMEdge *edge = bm_original_edge_get(mr, loose_edges[i])) {
EditLoopData value{};
mesh_render_data_edge_flag(mr, edge, value);
data.fill(value);
mesh_render_data_vert_flag(mr, edge->v1, data.first());
mesh_render_data_vert_flag(mr, edge->v2, data.last());
}
else {
data.fill({});
}
const int2 edge = edges[loose_edges[i]];
if (const BMVert *bm_vert = bm_original_vert_get(mr, edge[0])) {
mesh_render_data_vert_flag(mr, bm_vert, data.first());
}
if (const BMVert *bm_vert = bm_original_vert_get(mr, edge[1])) {
mesh_render_data_vert_flag(mr, bm_vert, data.last());
}
}
});
MutableSpan<EditLoopData> vert_data = vbo_data.take_back(loose_verts.size());
const Span<int> loose_verts = mr.loose_verts;
threading::parallel_for(loose_verts.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
EditLoopData value{};
if (BMVert *vert = mr.orig_index_vert ? bm_original_vert_get(mr, loose_verts[i]) :
BM_vert_at_index(mr.bm, loose_verts[i]))
{
mesh_render_data_vert_flag(mr, vert, value);
loose_vert_data[i] = {};
if (const BMVert *eve = bm_original_vert_get(mr, loose_verts[i])) {
mesh_render_data_vert_flag(mr, eve, loose_vert_data[i]);
}
vert_data[i] = value;
}
});
}
static void extract_edit_data_init_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void *data)
static void extract_edit_subdiv_data_bm(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
MutableSpan<EditLoopData> vbo_data)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
GPU_vertbuf_init_with_format(vbo, get_edit_data_format());
GPU_vertbuf_data_alloc(vbo, subdiv_full_vbo_size(mr, subdiv_cache));
EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
*(EditLoopData **)data = vbo_data;
}
const int corners_num = subdiv_cache.num_subdiv_loops;
const int loose_edges_num = mr.loose_edges.size();
const int verts_per_edge = subdiv_verts_per_coarse_edge(subdiv_cache);
const Span<int> subdiv_loop_face_index(subdiv_cache.subdiv_loop_face_index, corners_num);
const Span<int> subdiv_loop_vert_index(
static_cast<const int *>(GPU_vertbuf_get_data(subdiv_cache.verts_orig_index)), corners_num);
const Span<int> subdiv_loop_edge_index(
static_cast<const int *>(GPU_vertbuf_get_data(subdiv_cache.edges_orig_index)), corners_num);
static void extract_edit_data_iter_subdiv_bm(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
void *_data,
uint subdiv_quad_index,
const BMFace *coarse_quad)
{
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);
MutableSpan corners_data = vbo_data.take_front(corners_num);
MutableSpan loose_edge_data = vbo_data.slice(corners_num, loose_edges_num * verts_per_edge);
MutableSpan loose_vert_data = vbo_data.take_back(mr.loose_verts.size());
uint start_loop_idx = subdiv_quad_index * 4;
uint end_loop_idx = (subdiv_quad_index + 1) * 4;
for (uint i = start_loop_idx; i < end_loop_idx; i++) {
const int vert_origindex = subdiv_loop_vert_index[i];
const int edge_origindex = subdiv_loop_edge_index[i];
BMesh &bm = *mr.bm;
threading::parallel_for(IndexRange(subdiv_cache.num_subdiv_quads), 2048, [&](IndexRange range) {
for (const int subdiv_quad : range) {
const int coarse_face = subdiv_loop_face_index[subdiv_quad * 4];
const BMFace *bm_face = BM_face_at_index(&bm, coarse_face);
for (const int subdiv_corner : IndexRange(subdiv_quad * 4, 4)) {
EditLoopData &value = corners_data[subdiv_corner];
value = {};
EditLoopData *edit_loop_data = &vbo_data[i];
memset(edit_loop_data, 0, sizeof(EditLoopData));
mesh_render_data_face_flag(mr, bm_face, {-1, -1, -1, -1}, value);
const int vert_origindex = subdiv_loop_vert_index[subdiv_corner];
if (vert_origindex != -1) {
const BMVert *eve = mr.orig_index_vert ? bm_original_vert_get(mr, vert_origindex) :
BM_vert_at_index(mr.bm, vert_origindex);
if (eve) {
mesh_render_data_vert_flag(mr, eve, *edit_loop_data);
}
const BMVert *bm_vert = BM_vert_at_index(mr.bm, vert_origindex);
mesh_render_data_vert_flag(mr, bm_vert, value);
}
const int edge_origindex = subdiv_loop_edge_index[subdiv_corner];
if (edge_origindex != -1) {
/* NOTE: #subdiv_loop_edge_index already has the origindex layer baked in. */
const BMEdge *eed = BM_edge_at_index(mr.bm, edge_origindex);
mesh_render_data_edge_flag(mr, eed, *edit_loop_data);
const BMEdge *bm_edge = BM_edge_at_index(mr.bm, edge_origindex);
mesh_render_data_edge_flag(mr, bm_edge, value);
}
}
}
});
/* coarse_quad can be null when called by the mesh iteration below. */
if (coarse_quad) {
/* The -1 parameter is for edit_uvs, which we don't do here. */
mesh_render_data_face_flag(mr, coarse_quad, {-1, -1, -1, -1}, *edit_loop_data);
const Span<int> loose_edges = mr.loose_edges;
threading::parallel_for(loose_edges.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
MutableSpan<EditLoopData> data = loose_edge_data.slice(i * verts_per_edge, verts_per_edge);
const BMEdge *edge = BM_edge_at_index(&bm, loose_edges[i]);
EditLoopData value{};
mesh_render_data_edge_flag(mr, edge, value);
data.fill(value);
mesh_render_data_vert_flag(mr, edge->v1, data.first());
mesh_render_data_vert_flag(mr, edge->v2, data.last());
}
});
const Span<int> loose_verts = mr.loose_verts;
threading::parallel_for(loose_verts.index_range(), 2048, [&](const IndexRange range) {
for (const int i : range) {
loose_vert_data[i] = {};
const BMVert *vert = BM_vert_at_index(&bm, loose_verts[i]);
mesh_render_data_vert_flag(mr, vert, loose_vert_data[i]);
}
});
}
static void extract_edit_data_iter_subdiv_mesh(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
void *_data,
uint subdiv_quad_index,
const int coarse_quad_index)
void extract_edit_data_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
gpu::VertBuf &vbo)
{
BMFace *coarse_quad_bm = bm_original_face_get(mr, coarse_quad_index);
extract_edit_data_iter_subdiv_bm(subdiv_cache, mr, _data, subdiv_quad_index, coarse_quad_bm);
GPU_vertbuf_init_with_format(&vbo, get_edit_data_format());
const int size = subdiv_full_vbo_size(mr, subdiv_cache);
GPU_vertbuf_data_alloc(&vbo, size);
MutableSpan vbo_data(static_cast<EditLoopData *>(GPU_vertbuf_get_data(&vbo)), size);
if (mr.extract_type == MR_EXTRACT_MESH) {
extract_edit_subdiv_data_mesh(mr, subdiv_cache, vbo_data);
}
else {
extract_edit_subdiv_data_bm(mr, subdiv_cache, vbo_data);
}
}
constexpr MeshExtract create_extractor_edit_data()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edit_data_init;
extractor.iter_face_bm = extract_edit_data_iter_face_bm;
extractor.iter_face_mesh = extract_edit_data_iter_face_mesh;
extractor.iter_loose_edge_bm = extract_edit_data_iter_loose_edge_bm;
extractor.iter_loose_edge_mesh = extract_edit_data_iter_loose_edge_mesh;
extractor.iter_loose_vert_bm = extract_edit_data_iter_loose_vert_bm;
extractor.iter_loose_vert_mesh = extract_edit_data_iter_loose_vert_mesh;
extractor.init_subdiv = extract_edit_data_init_subdiv;
extractor.iter_subdiv_bm = extract_edit_data_iter_subdiv_bm;
extractor.iter_subdiv_mesh = extract_edit_data_iter_subdiv_mesh;
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;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edit_data);
return extractor;
}
/** \} */
const MeshExtract extract_edit_data = create_extractor_edit_data();
} // namespace blender::draw