Mesh: Draw: Replace extractor abstraction for edit data buffer

Part of #116901.
Due to the BMesh data format, there is less optimization possible here.
This commit is contained in:
Hans Goudey
2024-06-03 15:36:33 -04:00
committed by Hans Goudey
parent 5931c82238
commit 01b0096b5e
3 changed files with 171 additions and 119 deletions

View File

@@ -644,7 +644,6 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
} \
} while (0)
EXTRACT_ADD_REQUESTED(vbo, edituv_data);
EXTRACT_ADD_REQUESTED(vbo, fdots_edituv_data);
for (int i = 0; i < GPU_MAX_ATTR; i++) {
EXTRACT_ADD_REQUESTED(vbo, attr[i]);
@@ -670,6 +669,7 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
!DRW_vbo_requested(buffers.vbo.weights) && !DRW_vbo_requested(buffers.vbo.fdots_uv) &&
!DRW_vbo_requested(buffers.vbo.uv) && !DRW_vbo_requested(buffers.vbo.edituv_stretch_area) &&
!DRW_vbo_requested(buffers.vbo.edituv_stretch_angle) &&
!DRW_vbo_requested(buffers.vbo.edituv_data) &&
!DRW_ibo_requested(buffers.ibo.lines_paint_mask) &&
!DRW_ibo_requested(buffers.ibo.lines_adjacency) &&
!DRW_vbo_requested(buffers.vbo.skin_roots) && !DRW_vbo_requested(buffers.vbo.sculpt_data) &&
@@ -1009,6 +1009,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.edituv_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_edituv_data(data.mr, *data.buffers.vbo.edituv_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 (DRW_ibo_requested(buffers.ibo.lines_paint_mask)) {
struct TaskData {
MeshRenderData &mr;
@@ -1197,7 +1212,6 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
EXTRACT_ADD_REQUESTED(ibo, edituv_points);
EXTRACT_ADD_REQUESTED(ibo, edituv_tris);
EXTRACT_ADD_REQUESTED(ibo, edituv_lines);
EXTRACT_ADD_REQUESTED(vbo, edituv_data);
#undef EXTRACT_ADD_REQUESTED
@@ -1212,6 +1226,7 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
!DRW_vbo_requested(buffers.vbo.fdots_pos) && !DRW_ibo_requested(buffers.ibo.fdots) &&
!DRW_vbo_requested(buffers.vbo.uv) && !DRW_vbo_requested(buffers.vbo.edituv_stretch_area) &&
!DRW_vbo_requested(buffers.vbo.edituv_stretch_angle) &&
!DRW_vbo_requested(buffers.vbo.edituv_data) &&
!DRW_ibo_requested(buffers.ibo.lines_paint_mask) &&
!DRW_ibo_requested(buffers.ibo.lines_adjacency) &&
!DRW_vbo_requested(buffers.vbo.sculpt_data))
@@ -1289,6 +1304,9 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
extract_edituv_stretch_angle_subdiv(
mr, subdiv_cache, cache, *buffers.vbo.edituv_stretch_angle);
}
if (DRW_vbo_requested(buffers.vbo.edituv_data)) {
extract_edituv_data_subdiv(mr, subdiv_cache, *buffers.vbo.edituv_data);
}
void *data_stack = MEM_mallocN(extractors.data_size_total(), __func__);
uint32_t data_offset = 0;

View File

@@ -470,6 +470,10 @@ void extract_edituv_stretch_angle_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
const MeshBatchCache &cache,
gpu::VertBuf &vbo);
void extract_edituv_data(const MeshRenderData &mr, gpu::VertBuf &vbo);
void extract_edituv_data_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
gpu::VertBuf &vbo);
void extract_skin_roots(const MeshRenderData &mr, gpu::VertBuf &vbo);
@@ -486,7 +490,6 @@ extern const MeshExtract extract_edituv_tris;
extern const MeshExtract extract_edituv_lines;
extern const MeshExtract extract_edituv_points;
extern const MeshExtract extract_edituv_fdots;
extern const MeshExtract extract_edituv_data;
extern const MeshExtract extract_fdots_edituv_data;
extern const MeshExtract extract_attr[GPU_MAX_ATTR];
extern const MeshExtract extract_attr_viewer;

View File

@@ -20,15 +20,7 @@ namespace blender::draw {
/** \name Extract Edit UV Data / Flags
* \{ */
struct MeshExtract_EditUVData_Data {
EditLoopData *vbo_data;
BMUVOffsets offsets;
};
static void extract_edituv_data_init_common(const MeshRenderData &mr,
gpu::VertBuf *vbo,
MeshExtract_EditUVData_Data *data,
uint loop_len)
static const GPUVertFormat &edituv_data_format()
{
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
@@ -36,98 +28,96 @@ static void extract_edituv_data_init_common(const MeshRenderData &mr,
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);
GPU_vertbuf_data_alloc(vbo, loop_len);
data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo);
data->offsets = BM_uv_map_get_offsets(mr.bm);
return format;
}
static void extract_edituv_data_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void *tls_data)
static void extract_edituv_data_bm(const MeshRenderData &mr, MutableSpan<EditLoopData> vbo_data)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data);
extract_edituv_data_init_common(mr, vbo, data, mr.corners_num);
}
static void extract_edituv_data_iter_face_bm(const MeshRenderData &mr,
const BMFace *f,
const int /*f_index*/,
void *_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);
MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(_data);
EditLoopData *eldata = &data->vbo_data[l_index];
memset(eldata, 0x0, sizeof(*eldata));
mesh_render_data_loop_flag(mr, l_iter, data->offsets, *eldata);
mesh_render_data_face_flag(mr, f, data->offsets, *eldata);
mesh_render_data_loop_edge_flag(mr, l_iter, data->offsets, *eldata);
} while ((l_iter = l_iter->next) != l_first);
}
static void extract_edituv_data_iter_face_mesh(const MeshRenderData &mr,
const int face_index,
void *_data)
{
MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(_data);
const IndexRange face = mr.faces[face_index];
for (const int corner : face) {
EditLoopData *eldata = &data->vbo_data[corner];
memset(eldata, 0x0, sizeof(*eldata));
BMFace *efa = bm_original_face_get(mr, face_index);
if (efa) {
BMVert *eve = bm_original_vert_get(mr, mr.corner_verts[corner]);
BMEdge *eed = bm_original_edge_get(mr, mr.corner_edges[corner]);
if (eed && eve) {
/* Loop on an edge endpoint. */
BMLoop *l = BM_face_edge_share_loop(efa, eed);
mesh_render_data_loop_flag(mr, l, data->offsets, *eldata);
mesh_render_data_loop_edge_flag(mr, l, data->offsets, *eldata);
const BMesh &bm = *mr.bm;
const BMUVOffsets offsets = BM_uv_map_get_offsets(&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 = vbo_data[index];
value = {};
mesh_render_data_loop_flag(mr, loop, offsets, value);
mesh_render_data_face_flag(mr, &face, offsets, value);
mesh_render_data_loop_edge_flag(mr, loop, offsets, value);
loop = loop->next;
}
else {
if (eed == nullptr) {
/* Find if the loop's vert is not part of an edit edge.
* For this, we check if the previous loop was on an edge. */
const int corner_prev = bke::mesh::face_corner_prev(face, corner);
eed = bm_original_edge_get(mr, mr.corner_edges[corner_prev]);
}
});
}
static void extract_edituv_data_mesh(const MeshRenderData &mr, MutableSpan<EditLoopData> vbo_data)
{
const BMesh &bm = *mr.bm;
const BMUVOffsets offsets = BM_uv_map_get_offsets(&bm);
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_index : range) {
const IndexRange face = faces[face_index];
BMFace *face_orig = bm_original_face_get(mr, face_index);
if (!face_orig) {
vbo_data.slice(face).fill({});
continue;
}
for (const int corner : face) {
EditLoopData &value = vbo_data[corner];
value = {};
BMVert *vert = bm_original_vert_get(mr, corner_verts[corner]);
BMEdge *edge = bm_original_edge_get(mr, corner_edges[corner]);
if (edge && vert) {
/* Loop on an edge endpoint. */
BMLoop *l = BM_face_edge_share_loop(face_orig, edge);
mesh_render_data_loop_flag(mr, l, offsets, value);
mesh_render_data_loop_edge_flag(mr, l, offsets, value);
}
if (eed) {
/* Mapped points on an edge between two edit verts. */
BMLoop *l = BM_face_edge_share_loop(efa, eed);
mesh_render_data_loop_edge_flag(mr, l, data->offsets, *eldata);
else {
if (edge == nullptr) {
/* Find if the loop's vert is not part of an edit edge.
* For this, we check if the previous loop was on an edge. */
const int corner_prev = bke::mesh::face_corner_prev(face, corner);
edge = bm_original_edge_get(mr, corner_edges[corner_prev]);
}
if (edge) {
/* Mapped points on an edge between two edit verts. */
BMLoop *l = BM_face_edge_share_loop(face_orig, edge);
mesh_render_data_loop_edge_flag(mr, l, offsets, value);
}
}
}
}
});
}
void extract_edituv_data(const MeshRenderData &mr, gpu::VertBuf &vbo)
{
GPU_vertbuf_init_with_format(&vbo, &edituv_data_format());
GPU_vertbuf_data_alloc(&vbo, mr.corners_num);
MutableSpan vbo_data(static_cast<EditLoopData *>(GPU_vertbuf_get_data(&vbo)), mr.corners_num);
if (mr.extract_type == MR_EXTRACT_BMESH) {
extract_edituv_data_bm(mr, vbo_data);
}
else {
extract_edituv_data_mesh(mr, vbo_data);
}
}
static void extract_edituv_data_init_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void *tls_data)
static void extract_edituv_data_iter_subdiv_bm(const MeshRenderData &mr,
const BMUVOffsets offsets,
const Span<int> subdiv_loop_vert_index,
const Span<int> subdiv_loop_edge_index,
const int subdiv_quad_index,
const BMFace *coarse_quad,
MutableSpan<EditLoopData> vbo_data)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(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_bm(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
void *_data,
uint subdiv_quad_index,
const BMFace *coarse_quad)
{
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);
uint start_loop_idx = subdiv_quad_index * 4;
uint end_loop_idx = (subdiv_quad_index + 1) * 4;
@@ -135,15 +125,15 @@ static void extract_edituv_data_iter_subdiv_bm(const DRWSubdivCache &subdiv_cach
const int vert_origindex = subdiv_loop_vert_index[i];
int edge_origindex = subdiv_loop_edge_index[i];
EditLoopData *edit_loop_data = &data->vbo_data[i];
EditLoopData *edit_loop_data = &vbo_data[i];
memset(edit_loop_data, 0, sizeof(EditLoopData));
if (vert_origindex != -1 && edge_origindex != -1) {
BMEdge *eed = BM_edge_at_index(mr.bm, edge_origindex);
/* Loop on an edge endpoint. */
BMLoop *l = BM_face_edge_share_loop(const_cast<BMFace *>(coarse_quad), eed);
mesh_render_data_loop_flag(mr, l, data->offsets, *edit_loop_data);
mesh_render_data_loop_edge_flag(mr, l, data->offsets, *edit_loop_data);
mesh_render_data_loop_flag(mr, l, offsets, *edit_loop_data);
mesh_render_data_loop_edge_flag(mr, l, offsets, *edit_loop_data);
}
else {
if (edge_origindex == -1) {
@@ -156,42 +146,83 @@ static void extract_edituv_data_iter_subdiv_bm(const DRWSubdivCache &subdiv_cach
/* Mapped points on an edge between two edit verts. */
BMEdge *eed = BM_edge_at_index(mr.bm, edge_origindex);
BMLoop *l = BM_face_edge_share_loop(const_cast<BMFace *>(coarse_quad), eed);
mesh_render_data_loop_edge_flag(mr, l, data->offsets, *edit_loop_data);
mesh_render_data_loop_edge_flag(mr, l, offsets, *edit_loop_data);
}
}
mesh_render_data_face_flag(mr, coarse_quad, data->offsets, *edit_loop_data);
mesh_render_data_face_flag(mr, coarse_quad, offsets, *edit_loop_data);
}
}
static void extract_edituv_data_iter_subdiv_mesh(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
void *_data,
uint subdiv_quad_index,
const int coarse_quad_index)
static void extract_edituv_subdiv_data_bm(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
MutableSpan<EditLoopData> vbo_data)
{
BMFace *coarse_quad_bm = bm_original_face_get(mr, coarse_quad_index);
extract_edituv_data_iter_subdiv_bm(subdiv_cache, mr, _data, subdiv_quad_index, coarse_quad_bm);
const int corners_num = subdiv_cache.num_subdiv_loops;
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);
const BMUVOffsets offsets = BM_uv_map_get_offsets(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];
extract_edituv_data_iter_subdiv_bm(mr,
offsets,
subdiv_loop_vert_index,
subdiv_loop_edge_index,
subdiv_quad,
BM_face_at_index(mr.bm, coarse_face),
vbo_data);
}
});
}
constexpr MeshExtract create_extractor_edituv_data()
static void extract_edituv_subdiv_data_mesh(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
MutableSpan<EditLoopData> vbo_data)
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edituv_data_init;
extractor.iter_face_bm = extract_edituv_data_iter_face_bm;
extractor.iter_face_mesh = extract_edituv_data_iter_face_mesh;
extractor.init_subdiv = extract_edituv_data_init_subdiv;
extractor.iter_subdiv_bm = extract_edituv_data_iter_subdiv_bm;
extractor.iter_subdiv_mesh = extract_edituv_data_iter_subdiv_mesh;
extractor.data_type = MR_DATA_NONE;
extractor.data_size = sizeof(MeshExtract_EditUVData_Data);
extractor.use_threading = true;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edituv_data);
return extractor;
const int corners_num = subdiv_cache.num_subdiv_loops;
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);
const BMUVOffsets offsets = BM_uv_map_get_offsets(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];
extract_edituv_data_iter_subdiv_bm(mr,
offsets,
subdiv_loop_vert_index,
subdiv_loop_edge_index,
subdiv_quad,
bm_original_face_get(mr, coarse_face),
vbo_data);
}
});
}
/** \} */
void extract_edituv_data_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
gpu::VertBuf &vbo)
{
GPU_vertbuf_init_with_format(&vbo, &edituv_data_format());
const int size = subdiv_cache.num_subdiv_loops;
GPU_vertbuf_data_alloc(&vbo, size);
MutableSpan vbo_data(static_cast<EditLoopData *>(GPU_vertbuf_get_data(&vbo)), size);
const MeshExtract extract_edituv_data = create_extractor_edituv_data();
if (mr.extract_type == MR_EXTRACT_BMESH) {
extract_edituv_subdiv_data_bm(mr, subdiv_cache, vbo_data);
}
else {
extract_edituv_subdiv_data_mesh(mr, subdiv_cache, vbo_data);
}
}
} // namespace blender::draw