Mesh: Draw: Replace extractor abstraction for UV area stretch buffer

Part of #116901.
Besides the typical changes from past similar refactors, the loops are
now multithreaded.
This commit is contained in:
Hans Goudey
2024-06-03 13:51:41 -04:00
committed by Hans Goudey
parent 498f4ba284
commit 4a852cdaa7
3 changed files with 146 additions and 132 deletions

View File

@@ -645,7 +645,6 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
} while (0)
EXTRACT_ADD_REQUESTED(vbo, edituv_data);
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_area);
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
EXTRACT_ADD_REQUESTED(vbo, fdots_edituv_data);
for (int i = 0; i < GPU_MAX_ATTR; i++) {
@@ -670,7 +669,8 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
!DRW_vbo_requested(buffers.vbo.face_idx) && !DRW_vbo_requested(buffers.vbo.edge_idx) &&
!DRW_vbo_requested(buffers.vbo.vert_idx) && !DRW_vbo_requested(buffers.vbo.fdot_idx) &&
!DRW_vbo_requested(buffers.vbo.weights) && !DRW_vbo_requested(buffers.vbo.fdots_uv) &&
!DRW_vbo_requested(buffers.vbo.uv) && !DRW_ibo_requested(buffers.ibo.lines_paint_mask) &&
!DRW_vbo_requested(buffers.vbo.uv) && !DRW_vbo_requested(buffers.vbo.edituv_stretch_area) &&
!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) &&
!DRW_vbo_requested(buffers.vbo.orco) && !DRW_vbo_requested(buffers.vbo.mesh_analysis))
@@ -975,6 +975,25 @@ 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_stretch_area)) {
struct TaskData {
MeshRenderData &mr;
MeshBufferList &buffers;
MeshBatchCache &cache;
};
TaskNode *task_node = BLI_task_graph_node_create(
&task_graph,
[](void *__restrict task_data) {
const TaskData &data = *static_cast<TaskData *>(task_data);
extract_edituv_stretch_area(data.mr,
*data.buffers.vbo.edituv_stretch_area,
data.cache.tot_area,
data.cache.tot_uv_area);
},
new TaskData{*mr, buffers, cache},
[](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;
@@ -1164,7 +1183,6 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
EXTRACT_ADD_REQUESTED(ibo, edituv_tris);
EXTRACT_ADD_REQUESTED(ibo, edituv_lines);
EXTRACT_ADD_REQUESTED(vbo, edituv_data);
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_area);
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
#undef EXTRACT_ADD_REQUESTED
@@ -1178,7 +1196,8 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
!DRW_vbo_requested(buffers.vbo.edge_idx) && !DRW_vbo_requested(buffers.vbo.vert_idx) &&
!DRW_vbo_requested(buffers.vbo.weights) && !DRW_vbo_requested(buffers.vbo.fdots_nor) &&
!DRW_vbo_requested(buffers.vbo.fdots_pos) && !DRW_ibo_requested(buffers.ibo.fdots) &&
!DRW_vbo_requested(buffers.vbo.uv) && !DRW_ibo_requested(buffers.ibo.lines_paint_mask) &&
!DRW_vbo_requested(buffers.vbo.uv) && !DRW_vbo_requested(buffers.vbo.edituv_stretch_area) &&
!DRW_ibo_requested(buffers.ibo.lines_paint_mask) &&
!DRW_ibo_requested(buffers.ibo.lines_adjacency) &&
!DRW_vbo_requested(buffers.vbo.sculpt_data))
{
@@ -1247,6 +1266,10 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
/* Make sure UVs are computed before edituv stuffs. */
extract_uv_maps_subdiv(subdiv_cache, cache, *buffers.vbo.uv);
}
if (DRW_vbo_requested(buffers.vbo.edituv_stretch_area)) {
extract_edituv_stretch_area_subdiv(
mr, subdiv_cache, *buffers.vbo.edituv_stretch_area, cache.tot_area, cache.tot_uv_area);
}
void *data_stack = MEM_mallocN(extractors.data_size_total(), __func__);
uint32_t data_offset = 0;

View File

@@ -456,6 +456,15 @@ void extract_uv_maps(const MeshRenderData &mr, const MeshBatchCache &cache, gpu:
void extract_uv_maps_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshBatchCache &cache,
gpu::VertBuf &vbo);
void extract_edituv_stretch_area(const MeshRenderData &mr,
gpu::VertBuf &vbo,
float &tot_area,
float &tot_uv_area);
void extract_edituv_stretch_area_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
gpu::VertBuf &vbo,
float &tot_area,
float &tot_uv_area);
void extract_skin_roots(const MeshRenderData &mr, gpu::VertBuf &vbo);
@@ -473,7 +482,6 @@ 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_edituv_stretch_area;
extern const MeshExtract extract_edituv_stretch_angle;
extern const MeshExtract extract_fdots_edituv_data;
extern const MeshExtract extract_attr[GPU_MAX_ATTR];

View File

@@ -10,6 +10,7 @@
#include "MEM_guardedalloc.h"
#include "BKE_attribute.hh"
#include "BKE_mesh.hh"
#include "extract_mesh.hh"
@@ -18,25 +19,6 @@
namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Edit UV area stretch
* \{ */
static void extract_edituv_stretch_area_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void * /*tls_data*/)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
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_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr.corners_num);
}
BLI_INLINE float area_ratio_get(float area, float uvarea)
{
if (area >= FLT_EPSILON && uvarea >= FLT_EPSILON) {
@@ -51,130 +33,131 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio)
return (ratio > 1.0f) ? (1.0f / ratio) : ratio;
}
static void compute_area_ratio(const MeshRenderData &mr,
float *r_area_ratio,
float &r_tot_area,
float &r_tot_uv_area)
struct AreaInfo {
float tot_area = 0.0f;
float tot_uv_area = 0.0f;
};
static AreaInfo compute_area_ratio(const MeshRenderData &mr, MutableSpan<float> r_area_ratio)
{
float tot_area = 0.0f, tot_uv_area = 0.0f;
if (mr.extract_type == MR_EXTRACT_BMESH) {
CustomData *cd_ldata = &mr.bm->ldata;
int uv_ofs = CustomData_get_offset(cd_ldata, CD_PROP_FLOAT2);
BMFace *efa;
BMIter f_iter;
int f;
BM_ITER_MESH_INDEX (efa, &f_iter, mr.bm, BM_FACES_OF_MESH, f) {
float area = BM_face_calc_area(efa);
float uvarea = BM_face_calc_area_uv(efa, uv_ofs);
tot_area += area;
tot_uv_area += uvarea;
r_area_ratio[f] = area_ratio_get(area, uvarea);
}
}
else {
BLI_assert(mr.extract_type == MR_EXTRACT_MESH);
const float2 *uv_data = (const float2 *)CustomData_get_layer(&mr.mesh->corner_data,
CD_PROP_FLOAT2);
for (int face_index = 0; face_index < mr.faces_num; face_index++) {
const IndexRange face = mr.faces[face_index];
const float area = bke::mesh::face_area_calc(mr.vert_positions, mr.corner_verts.slice(face));
float uvarea = area_poly_v2(reinterpret_cast<const float(*)[2]>(&uv_data[face.start()]),
face.size());
tot_area += area;
tot_uv_area += uvarea;
r_area_ratio[face_index] = area_ratio_get(area, uvarea);
}
const BMesh &bm = *mr.bm;
const int uv_offset = CustomData_get_offset(&bm.ldata, CD_PROP_FLOAT2);
return threading::parallel_reduce(
IndexRange(bm.totface),
1024,
AreaInfo{},
[&](const IndexRange range, AreaInfo info) {
for (const int face_index : range) {
const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
const float area = BM_face_calc_area(&face);
const float uvarea = BM_face_calc_area_uv(&face, uv_offset);
info.tot_area += area;
info.tot_uv_area += uvarea;
r_area_ratio[face_index] = area_ratio_get(area, uvarea);
}
return info;
},
[](const AreaInfo &a, const AreaInfo &b) {
return AreaInfo{a.tot_area + b.tot_area, a.tot_uv_area + b.tot_uv_area};
});
}
r_tot_area = tot_area;
r_tot_uv_area = tot_uv_area;
const Span<float3> positions = mr.vert_positions;
const OffsetIndices<int> faces = mr.faces;
const Span<int> corner_verts = mr.corner_verts;
const Mesh &mesh = *mr.mesh;
const bke::AttributeAccessor attributes = mesh.attributes();
const StringRef name = CustomData_get_active_layer_name(&mesh.corner_data, CD_PROP_FLOAT2);
const VArraySpan uv_map = *attributes.lookup<float2>(name, bke::AttrDomain::Corner);
return threading::parallel_reduce(
faces.index_range(),
1024,
AreaInfo{},
[&](const IndexRange range, AreaInfo info) {
for (const int face_index : range) {
const IndexRange face = faces[face_index];
const float area = bke::mesh::face_area_calc(positions, corner_verts.slice(face));
float uvarea = area_poly_v2(reinterpret_cast<const float(*)[2]>(&uv_map[face.start()]),
face.size());
info.tot_area += area;
info.tot_uv_area += uvarea;
r_area_ratio[face_index] = area_ratio_get(area, uvarea);
}
return info;
},
[](const AreaInfo &a, const AreaInfo &b) {
return AreaInfo{a.tot_area + b.tot_area, a.tot_uv_area + b.tot_uv_area};
});
}
static void extract_edituv_stretch_area_finish(const MeshRenderData &mr,
MeshBatchCache &cache,
void *buf,
void * /*data*/)
void extract_edituv_stretch_area(const MeshRenderData &mr,
gpu::VertBuf &vbo,
float &tot_area,
float &tot_uv_area)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr.faces_num, __func__));
compute_area_ratio(mr, area_ratio, cache.tot_area, cache.tot_uv_area);
Array<float> area_ratio(mr.faces_num);
const AreaInfo info = compute_area_ratio(mr, area_ratio);
tot_area = info.tot_area;
tot_uv_area = info.tot_uv_area;
/* Copy face data for each loop. */
float *loop_stretch = (float *)GPU_vertbuf_get_data(vbo);
if (mr.extract_type == MR_EXTRACT_BMESH) {
BMFace *efa;
BMIter f_iter;
int f, l_index = 0;
BM_ITER_MESH_INDEX (efa, &f_iter, mr.bm, BM_FACES_OF_MESH, f) {
for (int i = 0; i < efa->len; i++, l_index++) {
loop_stretch[l_index] = area_ratio[f];
}
}
}
else {
BLI_assert(mr.extract_type == MR_EXTRACT_MESH);
for (int face_index = 0; face_index < mr.faces_num; face_index++) {
for (const int l_index : mr.faces[face_index]) {
loop_stretch[l_index] = area_ratio[face_index];
}
}
}
MEM_freeN(area_ratio);
}
static void extract_edituv_stretch_area_init_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
MeshBatchCache &cache,
void *buffer,
void * /*data*/)
{
/* Initialize final buffer. */
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(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_with_format(&vbo, &format);
GPU_vertbuf_data_alloc(&vbo, mr.corners_num);
MutableSpan<float> vbo_data(static_cast<float *>(GPU_vertbuf_get_data(&vbo)), mr.corners_num);
GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache.num_subdiv_loops);
/* Initialize coarse data buffer. */
gpu::VertBuf *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.corners_num);
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);
const int64_t bytes = area_ratio.as_span().size_in_bytes() + vbo_data.size_in_bytes();
threading::memory_bandwidth_bound_task(bytes, [&]() {
if (mr.extract_type == MR_EXTRACT_BMESH) {
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 IndexRange face_range(BM_elem_index_get(BM_FACE_FIRST_LOOP(&face)), face.len);
vbo_data.slice(face_range).fill(area_ratio[face_index]);
}
});
}
else {
BLI_assert(mr.extract_type == MR_EXTRACT_MESH);
const OffsetIndices<int> faces = mr.faces;
threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
for (const int face : range) {
vbo_data.slice(faces[face]).fill(area_ratio[face]);
}
});
}
});
}
constexpr MeshExtract create_extractor_edituv_stretch_area()
void extract_edituv_stretch_area_subdiv(const MeshRenderData &mr,
const DRWSubdivCache &subdiv_cache,
gpu::VertBuf &vbo,
float &tot_area,
float &tot_uv_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;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edituv_stretch_area);
return extractor;
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);
gpu::VertBuf *coarse_vbo = GPU_vertbuf_calloc();
GPU_vertbuf_init_with_format(coarse_vbo, &format);
GPU_vertbuf_data_alloc(coarse_vbo, mr.faces_num);
MutableSpan coarse_vbo_data(static_cast<float *>(GPU_vertbuf_get_data(coarse_vbo)),
mr.faces_num);
const AreaInfo info = compute_area_ratio(mr, coarse_vbo_data);
tot_area = info.tot_area;
tot_uv_area = info.tot_uv_area;
GPU_vertbuf_init_build_on_device(&vbo, &format, subdiv_cache.num_subdiv_loops);
draw_subdiv_build_edituv_stretch_area_buffer(subdiv_cache, coarse_vbo, &vbo);
GPU_vertbuf_discard(coarse_vbo);
}
/** \} */
const MeshExtract extract_edituv_stretch_area = create_extractor_edituv_stretch_area();
} // namespace blender::draw