Mesh: Draw: Replace extractor abstraction for facedot normals buffer

Part of #116901.
Also allows removing the "extractor overrides" code and deduplicating
the handling of high quality normals with templates.
This commit is contained in:
Hans Goudey
2024-05-29 21:47:53 -04:00
committed by Hans Goudey
parent 2eaab5bbb0
commit 070ffeea22
5 changed files with 97 additions and 195 deletions

View File

@@ -531,7 +531,7 @@ static void mesh_extract_render_data_node_exec(void *__restrict task_data)
MeshBufferList &buffers = update_task_data->cache->buff;
const bool request_face_normals = DRW_vbo_requested(buffers.vbo.nor) ||
DRW_vbo_requested(buffers.vbo.tan) ||
DRW_vbo_requested(buffers.vbo.fdots_nor) ||
(data_flag & (MR_DATA_POLY_NOR | MR_DATA_LOOP_NOR)) != 0;
const bool request_corner_normals = DRW_vbo_requested(buffers.vbo.nor) ||
(data_flag & MR_DATA_LOOP_NOR) != 0;
@@ -636,8 +636,7 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
#define EXTRACT_ADD_REQUESTED(type, name) \
do { \
if (DRW_##type##_requested(buffers.type.name)) { \
const MeshExtract *extractor = mesh_extract_override_get(&extract_##name, do_hq_normals); \
extractors.append(extractor); \
extractors.append(&extract_##name); \
} \
} while (0)
@@ -651,7 +650,6 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
EXTRACT_ADD_REQUESTED(vbo, mesh_analysis);
EXTRACT_ADD_REQUESTED(vbo, fdots_pos);
EXTRACT_ADD_REQUESTED(vbo, fdots_nor);
EXTRACT_ADD_REQUESTED(vbo, fdots_uv);
EXTRACT_ADD_REQUESTED(vbo, fdots_edituv_data);
EXTRACT_ADD_REQUESTED(vbo, face_idx);
@@ -678,7 +676,8 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
!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.vnor) &&
!DRW_vbo_requested(buffers.vbo.tan) && !DRW_vbo_requested(buffers.vbo.edit_data))
!DRW_vbo_requested(buffers.vbo.fdots_nor) && !DRW_vbo_requested(buffers.vbo.tan) &&
!DRW_vbo_requested(buffers.vbo.edit_data))
{
return;
}
@@ -760,6 +759,22 @@ 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.fdots_nor)) {
struct TaskData {
MeshRenderData &mr;
MeshBufferCache &mbc;
bool do_hq_normals;
};
TaskNode *task_node = BLI_task_graph_node_create(
&task_graph,
[](void *__restrict task_data) {
const TaskData &data = *static_cast<TaskData *>(task_data);
extract_face_dot_normals(data.mr, data.do_hq_normals, *data.mbc.buff.vbo.fdots_nor);
},
new TaskData{*mr, mbc, do_hq_normals},
[](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.tris)) {
struct TaskData {
MeshRenderData &mr;

View File

@@ -44,30 +44,6 @@ eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
return type;
}
/* ---------------------------------------------------------------------- */
/** \name Override extractors
* Extractors can be overridden. When overridden a specialized version is used. The next functions
* would check for any needed overrides and usage of the specialized version.
* \{ */
static const MeshExtract *mesh_extract_override_hq_normals(const MeshExtract *extractor)
{
if (extractor == &extract_fdots_nor) {
return &extract_fdots_nor_hq;
}
return extractor;
}
const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor,
const bool do_hq_normals)
{
if (do_hq_normals) {
extractor = mesh_extract_override_hq_normals(extractor);
}
return extractor;
}
/** \} */
/* ---------------------------------------------------------------------- */

View File

@@ -312,7 +312,6 @@ struct EditLoopData {
void *mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist);
eMRIterType mesh_extract_iter_type(const MeshExtract *ext);
const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor, bool do_hq_normals);
void mesh_render_data_face_flag(const MeshRenderData &mr,
const BMFace *efa,
BMUVOffsets offsets,
@@ -326,6 +325,20 @@ void mesh_render_data_loop_edge_flag(const MeshRenderData &mr,
BMUVOffsets offsets,
EditLoopData &eattr);
template<typename GPUType> inline GPUType convert_normal(const float3 &src);
template<> inline GPUPackedNormal convert_normal(const float3 &src)
{
return GPU_normal_convert_i10_v3(src);
}
template<> inline short4 convert_normal(const float3 &src)
{
short4 dst;
normal_float_to_short_v3(dst, src);
return dst;
}
template<typename GPUType> void convert_normals(Span<float3> src, MutableSpan<GPUType> dst);
template<typename T>
@@ -354,6 +367,7 @@ void extract_normals_subdiv(const DRWSubdivCache &subdiv_cache,
gpu::VertBuf &pos_nor,
gpu::VertBuf &lnor);
void extract_vert_normals(const MeshRenderData &mr, gpu::VertBuf &vbo);
void extract_face_dot_normals(const MeshRenderData &mr, const bool use_hq, gpu::VertBuf &vbo);
void extract_tris(const MeshRenderData &mr,
const SortedFaceData &face_sorted,
@@ -409,8 +423,6 @@ extern const MeshExtract extract_edituv_stretch_area;
extern const MeshExtract extract_edituv_stretch_angle;
extern const MeshExtract extract_mesh_analysis;
extern const MeshExtract extract_fdots_pos;
extern const MeshExtract extract_fdots_nor;
extern const MeshExtract extract_fdots_nor_hq;
extern const MeshExtract extract_fdots_uv;
extern const MeshExtract extract_fdots_edituv_data;
extern const MeshExtract extract_skin_roots;

View File

@@ -10,172 +10,85 @@
namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots Normal and edit flag
* \{ */
#define NOR_AND_FLAG_DEFAULT 0
#define NOR_AND_FLAG_SELECT 1
#define NOR_AND_FLAG_ACTIVE -1
#define NOR_AND_FLAG_HIDDEN -2
static void extract_fdots_nor_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void * /*tls_data*/)
template<typename GPUType>
static void extract_face_dot_normals_mesh(const MeshRenderData &mr, MutableSpan<GPUType> normals)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr.faces_num);
convert_normals(mr.face_normals, normals);
const GPUType invalid_normal = convert_normal<GPUType>(float3(0));
threading::parallel_for(IndexRange(mr.faces_num), 4096, [&](const IndexRange range) {
for (const int i : range) {
const BMFace *face = bm_original_face_get(mr, i);
if (!face || BM_elem_flag_test(face, BM_ELEM_HIDDEN)) {
normals[i] = invalid_normal;
normals[i].w = NOR_AND_FLAG_HIDDEN;
}
else if (BM_elem_flag_test(face, BM_ELEM_SELECT)) {
normals[i].w = (face == mr.efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT;
}
}
});
}
static void extract_fdots_nor_finish(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void * /*data*/)
template<typename GPUType>
void extract_face_dot_normals_bm(const MeshRenderData &mr, MutableSpan<GPUType> normals)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
static float invalid_normal[3] = {0.0f, 0.0f, 0.0f};
GPUPackedNormal *nor = (GPUPackedNormal *)GPU_vertbuf_get_data(vbo);
BMFace *efa;
/* Quicker than doing it for each loop. */
if (mr.extract_type == MR_EXTRACT_BMESH) {
for (int f = 0; f < mr.faces_num; f++) {
efa = BM_face_at_index(mr.bm, f);
const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
if (is_face_hidden || (mr.orig_index_face && mr.orig_index_face[f] == ORIGINDEX_NONE)) {
nor[f] = GPU_normal_convert_i10_v3(invalid_normal);
nor[f].w = NOR_AND_FLAG_HIDDEN;
const GPUType invalid_normal = convert_normal<GPUType>(float3(0));
threading::parallel_for(IndexRange(mr.faces_num), 4096, [&](const IndexRange range) {
for (const int i : range) {
BMFace *face = BM_face_at_index(mr.bm, i);
if (BM_elem_flag_test(face, BM_ELEM_HIDDEN)) {
normals[i] = invalid_normal;
normals[i].w = NOR_AND_FLAG_HIDDEN;
}
else {
nor[f] = GPU_normal_convert_i10_v3(bm_face_no_get(mr, efa));
/* Select / Active Flag. */
nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
((efa == mr.efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
NOR_AND_FLAG_DEFAULT);
normals[i] = convert_normal<GPUType>(bm_face_no_get(mr, face));
normals[i].w = (BM_elem_flag_test(face, BM_ELEM_SELECT) ?
((face == mr.efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
NOR_AND_FLAG_DEFAULT);
}
}
});
}
void extract_face_dot_normals(const MeshRenderData &mr, const bool use_hq, gpu::VertBuf &vbo)
{
if (use_hq) {
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
GPU_vertbuf_init_with_format(&vbo, &format);
GPU_vertbuf_data_alloc(&vbo, mr.faces_num);
MutableSpan vbo_data(static_cast<short4 *>(GPU_vertbuf_get_data(&vbo)), mr.faces_num);
if (mr.extract_type == MR_EXTRACT_MESH) {
extract_face_dot_normals_mesh(mr, vbo_data);
}
else {
extract_face_dot_normals_bm(mr, vbo_data);
}
}
else {
for (int f = 0; f < mr.faces_num; f++) {
efa = bm_original_face_get(mr, f);
const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
if (is_face_hidden || (mr.orig_index_face && mr.orig_index_face[f] == ORIGINDEX_NONE)) {
nor[f] = GPU_normal_convert_i10_v3(invalid_normal);
nor[f].w = NOR_AND_FLAG_HIDDEN;
}
else {
nor[f] = GPU_normal_convert_i10_v3(mr.face_normals[f]);
/* Select / Active Flag. */
nor[f].w = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
((efa == mr.efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
NOR_AND_FLAG_DEFAULT);
}
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_I10, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
GPU_vertbuf_init_with_format(&vbo, &format);
GPU_vertbuf_data_alloc(&vbo, mr.faces_num);
MutableSpan vbo_data(static_cast<GPUPackedNormal *>(GPU_vertbuf_get_data(&vbo)), mr.faces_num);
if (mr.extract_type == MR_EXTRACT_MESH) {
extract_face_dot_normals_mesh(mr, vbo_data);
}
else {
extract_face_dot_normals_bm(mr, vbo_data);
}
}
}
constexpr MeshExtract create_extractor_fdots_nor()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_fdots_nor_init;
extractor.finish = extract_fdots_nor_finish;
extractor.data_type = MR_DATA_LOOP_NOR;
extractor.data_size = 0;
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.fdots_nor);
return extractor;
}
/** \} */
/* ---------------------------------------------------------------------- */
/** \name Extract Face-dots High Quality Normal and edit flag
* \{ */
static void extract_fdots_nor_hq_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, "norAndFlag", GPU_COMP_I16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr.faces_num);
}
static void extract_fdots_nor_hq_finish(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void * /*data*/)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
static float invalid_normal[3] = {0.0f, 0.0f, 0.0f};
short *nor = (short *)GPU_vertbuf_get_data(vbo);
BMFace *efa;
/* Quicker than doing it for each loop. */
if (mr.extract_type == MR_EXTRACT_BMESH) {
for (int f = 0; f < mr.faces_num; f++) {
efa = BM_face_at_index(mr.bm, f);
const bool is_face_hidden = BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
if (is_face_hidden || (mr.orig_index_face && mr.orig_index_face[f] == ORIGINDEX_NONE)) {
normal_float_to_short_v3(&nor[f * 4], invalid_normal);
nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN;
}
else {
normal_float_to_short_v3(&nor[f * 4], bm_face_no_get(mr, efa));
/* Select / Active Flag. */
nor[f * 4 + 3] = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
((efa == mr.efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
NOR_AND_FLAG_DEFAULT);
}
}
}
else {
for (int f = 0; f < mr.faces_num; f++) {
efa = bm_original_face_get(mr, f);
const bool is_face_hidden = efa && BM_elem_flag_test(efa, BM_ELEM_HIDDEN);
if (is_face_hidden || (mr.orig_index_face && mr.orig_index_face[f] == ORIGINDEX_NONE)) {
normal_float_to_short_v3(&nor[f * 4], invalid_normal);
nor[f * 4 + 3] = NOR_AND_FLAG_HIDDEN;
}
else {
normal_float_to_short_v3(&nor[f * 4], bm_face_no_get(mr, efa));
/* Select / Active Flag. */
nor[f * 4 + 3] = (BM_elem_flag_test(efa, BM_ELEM_SELECT) ?
((efa == mr.efa_act) ? NOR_AND_FLAG_ACTIVE : NOR_AND_FLAG_SELECT) :
NOR_AND_FLAG_DEFAULT);
}
}
}
}
constexpr MeshExtract create_extractor_fdots_nor_hq()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_fdots_nor_hq_init;
extractor.finish = extract_fdots_nor_hq_finish;
extractor.data_type = MR_DATA_LOOP_NOR;
extractor.data_size = 0;
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.fdots_nor);
return extractor;
}
/** \} */
const MeshExtract extract_fdots_nor = create_extractor_fdots_nor();
const MeshExtract extract_fdots_nor_hq = create_extractor_fdots_nor_hq();
} // namespace blender::draw

View File

@@ -14,20 +14,6 @@
namespace blender::draw {
template<typename GPUType> inline GPUType convert_normal(const float3 &src);
template<> inline GPUPackedNormal convert_normal(const float3 &src)
{
return GPU_normal_convert_i10_v3(src);
}
template<> inline short4 convert_normal(const float3 &src)
{
short4 dst;
normal_float_to_short_v3(dst, src);
return dst;
}
template<typename GPUType>
static void convert_normals_impl(const Span<float3> src, MutableSpan<GPUType> dst)
{