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:
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user