Mesh: Draw triangle index buffer creation improvements #119130
|
@ -225,8 +225,9 @@ struct SortedFaceData {
|
|||
Array<int> tris_num_by_material;
|
||||
/**
|
||||
* The first triangle index for each face, sorted into slices by material.
|
||||
* May be empty if the mesh only has a single material.
|
||||
*/
|
||||
Array<int> face_tri_offsets;
|
||||
std::optional<Array<int>> face_tri_offsets;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -611,7 +611,6 @@ void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
|
|||
*/
|
||||
const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
|
||||
GPU_use_hq_normals_workaround();
|
||||
const bool override_single_mat = mesh_render_mat_len_get(object, mesh) <= 1;
|
||||
|
||||
/* Create an array containing all the extractors that needs to be executed. */
|
||||
ExtractorRunDatas extractors;
|
||||
|
@ -621,8 +620,7 @@ void mesh_buffer_cache_create_requested(TaskGraph *task_graph,
|
|||
#define EXTRACT_ADD_REQUESTED(type, name) \
|
||||
do { \
|
||||
if (DRW_##type##_requested(mbuflist->type.name)) { \
|
||||
const MeshExtract *extractor = mesh_extract_override_get( \
|
||||
&extract_##name, do_hq_normals, override_single_mat); \
|
||||
const MeshExtract *extractor = mesh_extract_override_get(&extract_##name, do_hq_normals); \
|
||||
extractors.append(extractor); \
|
||||
} \
|
||||
} while (0)
|
||||
|
|
|
@ -189,9 +189,10 @@ static void accumululate_material_counts_mesh(
|
|||
const MeshRenderData &mr, threading::EnumerableThreadSpecific<Array<int>> &all_tri_counts)
|
||||
{
|
||||
const OffsetIndices faces = mr.faces;
|
||||
if (mr.material_indices.is_empty()) {
|
||||
if (mr.use_hide && !mr.hide_poly.is_empty()) {
|
||||
const Span hide_poly = mr.hide_poly;
|
||||
const Span<bool> hide_poly = mr.hide_poly;
|
||||
const Span material_indices = mr.material_indices;
|
||||
if (material_indices.is_empty()) {
|
||||
if (!hide_poly.is_empty()) {
|
||||
all_tri_counts.local().first() = threading::parallel_reduce(
|
||||
faces.index_range(),
|
||||
4096,
|
||||
|
@ -212,13 +213,12 @@ static void accumululate_material_counts_mesh(
|
|||
return;
|
||||
}
|
||||
|
||||
const Span material_indices = mr.material_indices;
|
||||
threading::parallel_for(material_indices.index_range(), 1024, [&](const IndexRange range) {
|
||||
Array<int> &tri_counts = all_tri_counts.local();
|
||||
const int last_index = tri_counts.size() - 1;
|
||||
if (mr.use_hide && !mr.hide_poly.is_empty()) {
|
||||
if (!hide_poly.is_empty()) {
|
||||
for (const int i : range) {
|
||||
if (!mr.hide_poly[i]) {
|
||||
if (!hide_poly[i]) {
|
||||
const int mat = std::clamp(material_indices[i], 0, last_index);
|
||||
tri_counts[mat] += bke::mesh::face_triangles_num(faces[i].size());
|
||||
}
|
||||
|
@ -257,64 +257,109 @@ static Array<int> mesh_render_data_mat_tri_len_build(const MeshRenderData &mr)
|
|||
return std::move(tris_num_by_material);
|
||||
}
|
||||
|
||||
static void mesh_render_data_faces_sorted_build(MeshRenderData &mr, MeshBufferCache &cache)
|
||||
static Array<int> calc_face_tri_starts_bmesh(const MeshRenderData &mr,
|
||||
MutableSpan<int> material_tri_starts)
|
||||
{
|
||||
cache.face_sorted.tris_num_by_material = mesh_render_data_mat_tri_len_build(mr);
|
||||
const Span<int> tris_num_by_material = cache.face_sorted.tris_num_by_material;
|
||||
BMesh &bm = *mr.bm;
|
||||
Array<int> face_tri_offsets(bm.totface);
|
||||
#ifndef NDEBUG
|
||||
face_tri_offsets.fill(-1);
|
||||
#endif
|
||||
|
||||
/* Apply offset. */
|
||||
int visible_tris_num = 0;
|
||||
Array<int, 32> mat_tri_offs(mr.materials_num);
|
||||
{
|
||||
for (int i = 0; i < mr.materials_num; i++) {
|
||||
mat_tri_offs[i] = visible_tris_num;
|
||||
visible_tris_num += tris_num_by_material[i];
|
||||
const int mat_last = mr.materials_num - 1;
|
||||
BMIter iter;
|
||||
BMFace *face;
|
||||
int i;
|
||||
BM_ITER_MESH_INDEX (face, &iter, &bm, BM_FACES_OF_MESH, i) {
|
||||
if (BM_elem_flag_test(face, BM_ELEM_HIDDEN)) {
|
||||
continue;
|
||||
}
|
||||
const int mat = std::clamp(int(face->mat_nr), 0, mat_last);
|
||||
face_tri_offsets[i] = material_tri_starts[mat];
|
||||
material_tri_starts[mat] += face->len - 2;
|
||||
}
|
||||
cache.face_sorted.visible_tris_num = visible_tris_num;
|
||||
|
||||
cache.face_sorted.face_tri_offsets.reinitialize(mr.faces_num);
|
||||
MutableSpan<int> face_tri_offsets = cache.face_sorted.face_tri_offsets;
|
||||
return face_tri_offsets;
|
||||
}
|
||||
|
||||
static bool mesh_is_single_material(const OffsetIndices<int> material_tri_starts)
|
||||
{
|
||||
const int used_materials = std::count_if(
|
||||
material_tri_starts.index_range().begin(),
|
||||
material_tri_starts.index_range().end(),
|
||||
[&](const int i) { return material_tri_starts[i].size() > 0; });
|
||||
return used_materials == 1;
|
||||
}
|
||||
|
||||
static std::optional<Array<int>> calc_face_tri_starts_mesh(const MeshRenderData &mr,
|
||||
MutableSpan<int> material_tri_starts)
|
||||
{
|
||||
const bool single_material = mesh_is_single_material(material_tri_starts.as_span());
|
||||
if (single_material && mr.hide_poly.is_empty()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const OffsetIndices faces = mr.faces;
|
||||
const Span<bool> hide_poly = mr.hide_poly;
|
||||
|
||||
Array<int> face_tri_offsets(faces.size());
|
||||
#ifndef NDEBUG
|
||||
face_tri_offsets.fill(-1);
|
||||
#endif
|
||||
|
||||
if (single_material) {
|
||||
int offset = 0;
|
||||
for (const int face : faces.index_range()) {
|
||||
if (hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
face_tri_offsets[face] = offset;
|
||||
offset += bke::mesh::face_triangles_num(faces[face].size());
|
||||
}
|
||||
return face_tri_offsets;
|
||||
}
|
||||
|
||||
const Span<int> material_indices = mr.material_indices;
|
||||
const int mat_last = mr.materials_num - 1;
|
||||
for (const int face : faces.index_range()) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
const int mat = std::clamp(material_indices[face], 0, mat_last);
|
||||
face_tri_offsets[face] = material_tri_starts[mat];
|
||||
material_tri_starts[mat] += bke::mesh::face_triangles_num(faces[face].size());
|
||||
}
|
||||
|
||||
return face_tri_offsets;
|
||||
}
|
||||
|
||||
static SortedFaceData mesh_render_data_faces_sorted_build(const MeshRenderData &mr)
|
||||
{
|
||||
SortedFaceData cache;
|
||||
cache.tris_num_by_material = mesh_render_data_mat_tri_len_build(mr);
|
||||
const Span<int> tris_num_by_material = cache.tris_num_by_material;
|
||||
|
||||
Array<int, 32> material_tri_starts(mr.materials_num + 1);
|
||||
material_tri_starts.as_mutable_span().drop_back(1).copy_from(tris_num_by_material);
|
||||
offset_indices::accumulate_counts_to_offsets(material_tri_starts);
|
||||
cache.visible_tris_num = material_tri_starts.last();
|
||||
|
||||
/* Sort per material. */
|
||||
int mat_last = mr.materials_num - 1;
|
||||
if (mr.extract_type == MR_EXTRACT_BMESH) {
|
||||
BMIter iter;
|
||||
BMFace *f;
|
||||
int i;
|
||||
BM_ITER_MESH_INDEX (f, &iter, mr.bm, BM_FACES_OF_MESH, i) {
|
||||
if (!BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
|
||||
const int mat = clamp_i(f->mat_nr, 0, mat_last);
|
||||
face_tri_offsets[i] = mat_tri_offs[mat];
|
||||
mat_tri_offs[mat] += f->len - 2;
|
||||
}
|
||||
else {
|
||||
face_tri_offsets[i] = -1;
|
||||
}
|
||||
}
|
||||
cache.face_tri_offsets = calc_face_tri_starts_bmesh(mr, material_tri_starts);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < mr.faces_num; i++) {
|
||||
if (!(mr.use_hide && !mr.hide_poly.is_empty() && mr.hide_poly[i])) {
|
||||
const int mat = mr.material_indices.is_empty() ?
|
||||
0 :
|
||||
clamp_i(mr.material_indices[i], 0, mat_last);
|
||||
face_tri_offsets[i] = mat_tri_offs[mat];
|
||||
mat_tri_offs[mat] += mr.faces[i].size() - 2;
|
||||
}
|
||||
else {
|
||||
face_tri_offsets[i] = -1;
|
||||
}
|
||||
}
|
||||
cache.face_tri_offsets = calc_face_tri_starts_mesh(mr, material_tri_starts);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
static void mesh_render_data_faces_sorted_ensure(MeshRenderData &mr, MeshBufferCache &cache)
|
||||
{
|
||||
if (!cache.face_sorted.face_tri_offsets.is_empty()) {
|
||||
if (cache.face_sorted.visible_tris_num > 0) {
|
||||
return;
|
||||
}
|
||||
mesh_render_data_faces_sorted_build(mr, cache);
|
||||
cache.face_sorted = mesh_render_data_faces_sorted_build(mr);
|
||||
}
|
||||
|
||||
void mesh_render_data_update_faces_sorted(MeshRenderData &mr,
|
||||
|
|
|
@ -64,26 +64,13 @@ static const MeshExtract *mesh_extract_override_hq_normals(const MeshExtract *ex
|
|||
return extractor;
|
||||
}
|
||||
|
||||
static const MeshExtract *mesh_extract_override_single_material(const MeshExtract *extractor)
|
||||
{
|
||||
if (extractor == &extract_tris) {
|
||||
return &extract_tris_single_mat;
|
||||
}
|
||||
return extractor;
|
||||
}
|
||||
|
||||
const MeshExtract *mesh_extract_override_get(const MeshExtract *extractor,
|
||||
const bool do_hq_normals,
|
||||
const bool do_single_mat)
|
||||
const bool do_hq_normals)
|
||||
{
|
||||
if (do_hq_normals) {
|
||||
extractor = mesh_extract_override_hq_normals(extractor);
|
||||
}
|
||||
|
||||
if (do_single_mat) {
|
||||
extractor = mesh_extract_override_single_material(extractor);
|
||||
}
|
||||
|
||||
return extractor;
|
||||
}
|
||||
|
||||
|
|
|
@ -320,9 +320,7 @@ 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,
|
||||
bool do_single_mat);
|
||||
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,
|
||||
|
@ -340,7 +338,6 @@ template<typename GPUType>
|
|||
void extract_vert_normals(const MeshRenderData &mr, MutableSpan<GPUType> normals);
|
||||
|
||||
extern const MeshExtract extract_tris;
|
||||
extern const MeshExtract extract_tris_single_mat;
|
||||
extern const MeshExtract extract_lines;
|
||||
extern const MeshExtract extract_lines_with_lines_loose;
|
||||
extern const MeshExtract extract_lines_loose_only;
|
||||
|
|
|
@ -16,83 +16,84 @@
|
|||
|
||||
namespace blender::draw {
|
||||
|
||||
static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_from)
|
||||
{
|
||||
GPUIndexBufBuilder *elb_to = static_cast<GPUIndexBufBuilder *>(_userdata_to);
|
||||
GPUIndexBufBuilder *elb_from = static_cast<GPUIndexBufBuilder *>(_userdata_from);
|
||||
GPU_indexbuf_join(elb_to, elb_from);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/** \name Extract Triangles Indices (multi material)
|
||||
* \{ */
|
||||
|
||||
static void extract_tris_init(const MeshRenderData &mr,
|
||||
MeshBatchCache & /*cache*/,
|
||||
void * /*ibo*/,
|
||||
void *tls_data)
|
||||
static void extract_tris_mesh(const MeshRenderData &mr, gpu::IndexBuf &ibo)
|
||||
{
|
||||
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
|
||||
GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr.face_sorted->visible_tris_num, mr.corners_num);
|
||||
}
|
||||
|
||||
static void extract_tris_iter_face_bm(const MeshRenderData &mr,
|
||||
const BMFace *f,
|
||||
const int f_index,
|
||||
void *_data)
|
||||
{
|
||||
int tri_offset = mr.face_sorted->face_tri_offsets[f_index];
|
||||
if (tri_offset == -1) {
|
||||
const Span<int3> corner_tris = mr.corner_tris;
|
||||
if (!mr.face_sorted->face_tri_offsets) {
|
||||
/* There are no hidden faces and no reordering is necessary to group triangles with the same
|
||||
* material. The corner indices from #Mesh::corner_tris() can be copied directly to the GPU. */
|
||||
BLI_assert(mr.face_sorted->visible_tris_num == corner_tris.size());
|
||||
GPU_indexbuf_build_in_place_from_memory(&ibo,
|
||||
GPU_PRIM_TRIS,
|
||||
corner_tris.cast<uint32_t>().data(),
|
||||
corner_tris.size(),
|
||||
0,
|
||||
mr.corners_num,
|
||||
false);
|
||||
return;
|
||||
}
|
||||
|
||||
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
|
||||
int tri_first_index_real = poly_to_tri_count(f_index, BM_elem_index_get(f->l_first));
|
||||
const OffsetIndices faces = mr.faces;
|
||||
const Span<bool> hide_poly = mr.hide_poly;
|
||||
|
||||
Span<std::array<BMLoop *, 3>> looptris = mr.edit_bmesh->looptris;
|
||||
int tri_len = f->len - 2;
|
||||
for (int offs = 0; offs < tri_len; offs++) {
|
||||
const std::array<BMLoop *, 3> &elt = looptris[tri_first_index_real + offs];
|
||||
int tri_index = tri_offset + offs;
|
||||
GPU_indexbuf_set_tri_verts(elb,
|
||||
tri_index,
|
||||
BM_elem_index_get(elt[0]),
|
||||
BM_elem_index_get(elt[1]),
|
||||
BM_elem_index_get(elt[2]));
|
||||
}
|
||||
GPUIndexBufBuilder builder;
|
||||
GPU_indexbuf_init(&builder, GPU_PRIM_TRIS, mr.face_sorted->visible_tris_num, mr.corners_num);
|
||||
MutableSpan<uint3> data = GPU_indexbuf_get_data(&builder).cast<uint3>();
|
||||
|
||||
const Span<int> face_tri_offsets = mr.face_sorted->face_tri_offsets->as_span();
|
||||
threading::parallel_for(faces.index_range(), 2048, [&](const IndexRange range) {
|
||||
for (const int face : range) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
const IndexRange mesh_range = bke::mesh::face_triangles_range(faces, face);
|
||||
const Span<uint3> mesh_tris = corner_tris.slice(mesh_range).cast<uint3>();
|
||||
MutableSpan<uint3> ibo_tris = data.slice(face_tri_offsets[face], mesh_tris.size());
|
||||
ibo_tris.copy_from(mesh_tris);
|
||||
}
|
||||
});
|
||||
|
||||
GPU_indexbuf_build_in_place_ex(&builder, 0, mr.face_sorted->visible_tris_num, false, &ibo);
|
||||
}
|
||||
|
||||
static void extract_tris_iter_face_mesh(const MeshRenderData &mr,
|
||||
const int face_index,
|
||||
void *_data)
|
||||
static void extract_tris_bmesh(const MeshRenderData &mr, gpu::IndexBuf &ibo)
|
||||
{
|
||||
int tri_offset = mr.face_sorted->face_tri_offsets[face_index];
|
||||
if (tri_offset == -1) {
|
||||
return;
|
||||
}
|
||||
GPUIndexBufBuilder builder;
|
||||
GPU_indexbuf_init(&builder, GPU_PRIM_TRIS, mr.face_sorted->visible_tris_num, mr.corners_num);
|
||||
MutableSpan<uint3> data = GPU_indexbuf_get_data(&builder).cast<uint3>();
|
||||
|
||||
const IndexRange face = mr.faces[face_index];
|
||||
BMesh &bm = *mr.bm;
|
||||
const Span<std::array<BMLoop *, 3>> looptris = mr.edit_bmesh->looptris;
|
||||
const Span<int> face_tri_offsets = *mr.face_sorted->face_tri_offsets;
|
||||
threading::parallel_for(IndexRange(bm.totface), 1024, [&](const IndexRange range) {
|
||||
for (const int face_index : range) {
|
||||
const BMFace &face = *BM_face_at_index(&bm, face_index);
|
||||
if (BM_elem_flag_test(&face, BM_ELEM_HIDDEN)) {
|
||||
continue;
|
||||
}
|
||||
const int loop_index = BM_elem_index_get(BM_FACE_FIRST_LOOP(&face));
|
||||
const IndexRange bm_tris(poly_to_tri_count(face_index, loop_index),
|
||||
bke::mesh::face_triangles_num(face.len));
|
||||
const IndexRange ibo_tris(face_tri_offsets[face_index], bm_tris.size());
|
||||
for (const int i : bm_tris.index_range()) {
|
||||
data[ibo_tris[i]] = uint3(BM_elem_index_get(looptris[bm_tris[i]][0]),
|
||||
BM_elem_index_get(looptris[bm_tris[i]][1]),
|
||||
BM_elem_index_get(looptris[bm_tris[i]][2]));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
|
||||
int tri_first_index_real = poly_to_tri_count(face_index, face.start());
|
||||
|
||||
int tri_len = face.size() - 2;
|
||||
for (int offs = 0; offs < tri_len; offs++) {
|
||||
const int3 &tri = mr.corner_tris[tri_first_index_real + offs];
|
||||
int tri_index = tri_offset + offs;
|
||||
GPU_indexbuf_set_tri_verts(elb, tri_index, tri[0], tri[1], tri[2]);
|
||||
}
|
||||
GPU_indexbuf_build_in_place_ex(&builder, 0, mr.face_sorted->visible_tris_num, false, &ibo);
|
||||
}
|
||||
|
||||
static void extract_tris_finish(const MeshRenderData &mr,
|
||||
MeshBatchCache &cache,
|
||||
void *buf,
|
||||
void *_data)
|
||||
gpu::IndexBuf &ibo)
|
||||
{
|
||||
gpu::IndexBuf *ibo = static_cast<gpu::IndexBuf *>(buf);
|
||||
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
|
||||
GPU_indexbuf_build_in_place(elb, ibo);
|
||||
|
||||
/* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch
|
||||
* is created before the surfaces-per-material. */
|
||||
if (mr.use_final_mesh && cache.tris_per_mat) {
|
||||
|
@ -107,12 +108,29 @@ static void extract_tris_finish(const MeshRenderData &mr,
|
|||
/* Multiply by 3 because these are triangle indices. */
|
||||
const int start = mat_start * 3;
|
||||
const int len = mat_tri_len * 3;
|
||||
GPU_indexbuf_create_subrange_in_place(cache.tris_per_mat[i], ibo, start, len);
|
||||
GPU_indexbuf_create_subrange_in_place(cache.tris_per_mat[i], &ibo, start, len);
|
||||
mat_start += mat_tri_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void extract_tris_init(const MeshRenderData &mr,
|
||||
MeshBatchCache &cache,
|
||||
void *ibo_v,
|
||||
void * /*tls_data*/)
|
||||
{
|
||||
gpu::IndexBuf &ibo = *static_cast<gpu::IndexBuf *>(ibo_v);
|
||||
|
||||
if (mr.extract_type == MR_EXTRACT_MESH) {
|
||||
extract_tris_mesh(mr, ibo);
|
||||
}
|
||||
else {
|
||||
extract_tris_bmesh(mr, ibo);
|
||||
}
|
||||
|
||||
extract_tris_finish(mr, cache, ibo);
|
||||
}
|
||||
|
||||
static void extract_tris_init_subdiv(const DRWSubdivCache &subdiv_cache,
|
||||
const MeshRenderData & /*mr*/,
|
||||
MeshBatchCache &cache,
|
||||
|
@ -144,101 +162,7 @@ constexpr MeshExtract create_extractor_tris()
|
|||
MeshExtract extractor = {nullptr};
|
||||
extractor.init = extract_tris_init;
|
||||
extractor.init_subdiv = extract_tris_init_subdiv;
|
||||
extractor.iter_face_bm = extract_tris_iter_face_bm;
|
||||
extractor.iter_face_mesh = extract_tris_iter_face_mesh;
|
||||
extractor.task_reduce = extract_tris_mat_task_reduce;
|
||||
extractor.finish = extract_tris_finish;
|
||||
extractor.data_type = MR_DATA_CORNER_TRI | MR_DATA_POLYS_SORTED;
|
||||
extractor.data_size = sizeof(GPUIndexBufBuilder);
|
||||
extractor.use_threading = true;
|
||||
extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.tris);
|
||||
return extractor;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/** \name Extract Triangles Indices (single material)
|
||||
* \{ */
|
||||
|
||||
static void extract_tris_single_mat_init(const MeshRenderData &mr,
|
||||
MeshBatchCache & /*cache*/,
|
||||
void * /*ibo*/,
|
||||
void *tls_data)
|
||||
{
|
||||
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(tls_data);
|
||||
GPU_indexbuf_init(elb, GPU_PRIM_TRIS, mr.corner_tris_num, mr.corners_num);
|
||||
}
|
||||
|
||||
static void extract_tris_single_mat_iter_looptri_bm(const MeshRenderData & /*mr*/,
|
||||
BMLoop **elt,
|
||||
const int elt_index,
|
||||
void *_data)
|
||||
{
|
||||
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
|
||||
if (!BM_elem_flag_test(elt[0]->f, BM_ELEM_HIDDEN)) {
|
||||
GPU_indexbuf_set_tri_verts(elb,
|
||||
elt_index,
|
||||
BM_elem_index_get(elt[0]),
|
||||
BM_elem_index_get(elt[1]),
|
||||
BM_elem_index_get(elt[2]));
|
||||
}
|
||||
else {
|
||||
GPU_indexbuf_set_tri_restart(elb, elt_index);
|
||||
}
|
||||
}
|
||||
|
||||
static void extract_tris_single_mat_iter_corner_tri_mesh(const MeshRenderData &mr,
|
||||
const int3 &tri,
|
||||
const int tri_index,
|
||||
void *_data)
|
||||
{
|
||||
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
|
||||
const int face_i = mr.corner_tri_faces[tri_index];
|
||||
const bool hidden = mr.use_hide && !mr.hide_poly.is_empty() && mr.hide_poly[face_i];
|
||||
if (hidden) {
|
||||
GPU_indexbuf_set_tri_restart(elb, tri_index);
|
||||
}
|
||||
else {
|
||||
GPU_indexbuf_set_tri_verts(elb, tri_index, tri[0], tri[1], tri[2]);
|
||||
}
|
||||
}
|
||||
|
||||
static void extract_tris_single_mat_finish(const MeshRenderData &mr,
|
||||
MeshBatchCache &cache,
|
||||
void *buf,
|
||||
void *_data)
|
||||
{
|
||||
gpu::IndexBuf *ibo = static_cast<gpu::IndexBuf *>(buf);
|
||||
GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_data);
|
||||
GPU_indexbuf_build_in_place(elb, ibo);
|
||||
|
||||
/* Create ibo sub-ranges. Always do this to avoid error when the standard surface batch
|
||||
* is created before the surfaces-per-material. */
|
||||
if (mr.use_final_mesh && cache.tris_per_mat) {
|
||||
for (int i = 0; i < mr.materials_num; i++) {
|
||||
/* These IBOs have not been queried yet but we create them just in case they are needed
|
||||
* later since they are not tracked by mesh_buffer_cache_create_requested(). */
|
||||
if (cache.tris_per_mat[i] == nullptr) {
|
||||
cache.tris_per_mat[i] = GPU_indexbuf_calloc();
|
||||
}
|
||||
/* Multiply by 3 because these are triangle indices. */
|
||||
const int len = mr.corner_tris_num * 3;
|
||||
GPU_indexbuf_create_subrange_in_place(cache.tris_per_mat[i], ibo, 0, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr MeshExtract create_extractor_tris_single_mat()
|
||||
{
|
||||
MeshExtract extractor = {nullptr};
|
||||
extractor.init = extract_tris_single_mat_init;
|
||||
extractor.init_subdiv = extract_tris_init_subdiv;
|
||||
extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm;
|
||||
extractor.iter_corner_tri_mesh = extract_tris_single_mat_iter_corner_tri_mesh;
|
||||
extractor.task_reduce = extract_tris_mat_task_reduce;
|
||||
extractor.finish = extract_tris_single_mat_finish;
|
||||
extractor.data_type = MR_DATA_NONE;
|
||||
extractor.data_size = sizeof(GPUIndexBufBuilder);
|
||||
extractor.use_threading = true;
|
||||
extractor.mesh_buffer_offset = offsetof(MeshBufferList, ibo.tris);
|
||||
return extractor;
|
||||
|
@ -247,6 +171,5 @@ constexpr MeshExtract create_extractor_tris_single_mat()
|
|||
/** \} */
|
||||
|
||||
const MeshExtract extract_tris = create_extractor_tris();
|
||||
const MeshExtract extract_tris_single_mat = create_extractor_tris_single_mat();
|
||||
|
||||
} // namespace blender::draw
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_span.hh"
|
||||
|
||||
#include "GPU_primitive.hh"
|
||||
|
||||
#define GPU_TRACK_INDEX_RANGE 1
|
||||
|
@ -154,6 +156,8 @@ blender::gpu::IndexBuf *GPU_indexbuf_build_on_device(uint index_len);
|
|||
|
||||
void GPU_indexbuf_init_build_on_device(blender::gpu::IndexBuf *elem, uint index_len);
|
||||
|
||||
blender::MutableSpan<uint32_t> GPU_indexbuf_get_data(GPUIndexBufBuilder *);
|
||||
|
||||
/*
|
||||
* Thread safe.
|
||||
*
|
||||
|
@ -180,6 +184,26 @@ void GPU_indexbuf_set_tri_restart(GPUIndexBufBuilder *builder, uint elem);
|
|||
|
||||
blender::gpu::IndexBuf *GPU_indexbuf_build(GPUIndexBufBuilder *);
|
||||
void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, blender::gpu::IndexBuf *);
|
||||
void GPU_indexbuf_build_in_place_ex(GPUIndexBufBuilder *builder,
|
||||
uint index_min,
|
||||
uint index_max,
|
||||
bool uses_restart_indices,
|
||||
blender::gpu::IndexBuf *elem);
|
||||
|
||||
/**
|
||||
HooglyBoogly marked this conversation as resolved
Outdated
|
||||
* Fill an IBO by uploading the referenced data directly to the GPU, bypassing the separate storage
|
||||
* in the IBO. This should be used whenever the equivalent indices already exist in a contiguous
|
||||
* array on the CPU.
|
||||
*
|
||||
* \todo The optimization to avoid the local copy currently isn't implemented.
|
||||
*/
|
||||
void GPU_indexbuf_build_in_place_from_memory(blender::gpu::IndexBuf *ibo,
|
||||
GPUPrimType prim_type,
|
||||
const uint32_t *data,
|
||||
int32_t data_len,
|
||||
int32_t index_min,
|
||||
int32_t index_max,
|
||||
bool uses_restart_indices);
|
||||
|
||||
void GPU_indexbuf_bind_as_ssbo(blender::gpu::IndexBuf *elem, int binding);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
|
@ -96,6 +97,11 @@ void GPU_indexbuf_init_build_on_device(IndexBuf *elem, uint index_len)
|
|||
elem_->init_build_on_device(index_len);
|
||||
}
|
||||
|
||||
blender::MutableSpan<uint32_t> GPU_indexbuf_get_data(GPUIndexBufBuilder *builder)
|
||||
{
|
||||
return {builder->data, builder->max_index_len};
|
||||
}
|
||||
|
||||
void GPU_indexbuf_join(GPUIndexBufBuilder *builder_to, const GPUIndexBufBuilder *builder_from)
|
||||
{
|
||||
BLI_assert(builder_to->data == builder_from->data);
|
||||
|
@ -492,6 +498,43 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *builder, IndexBuf *elem)
|
|||
builder->data = nullptr;
|
||||
}
|
||||
|
||||
void GPU_indexbuf_build_in_place_ex(GPUIndexBufBuilder *builder,
|
||||
const uint index_min,
|
||||
const uint index_max,
|
||||
const bool uses_restart_indices,
|
||||
IndexBuf *elem)
|
||||
{
|
||||
BLI_assert(builder->data != nullptr);
|
||||
/* Transfer data ownership to IndexBuf.
|
||||
* It will be uploaded upon first use. */
|
||||
elem->init(builder->max_index_len,
|
||||
builder->data,
|
||||
index_min,
|
||||
index_max,
|
||||
builder->prim_type,
|
||||
uses_restart_indices);
|
||||
builder->data = nullptr;
|
||||
}
|
||||
|
||||
void GPU_indexbuf_build_in_place_from_memory(IndexBuf *ibo,
|
||||
const GPUPrimType prim_type,
|
||||
const uint32_t *data,
|
||||
const int32_t data_len,
|
||||
const int32_t index_min,
|
||||
const int32_t index_max,
|
||||
const bool uses_restart_indices)
|
||||
{
|
||||
const uint32_t indices_num = data_len * indices_per_primitive(prim_type);
|
||||
/* TODO: The need for this copy is meant to be temporary. The data should be uploaded directly to
|
||||
* the GPU here rather than copied to an array owned by the IBO first. */
|
||||
uint32_t *copy = static_cast<uint32_t *>(
|
||||
MEM_malloc_arrayN(indices_num, sizeof(uint32_t), __func__));
|
||||
threading::memory_bandwidth_bound_task(sizeof(uint32_t) * indices_num * 2, [&]() {
|
||||
array_utils::copy(Span(data, indices_num), MutableSpan(copy, indices_num));
|
||||
});
|
||||
ibo->init(indices_num, copy, index_min, index_max, prim_type, uses_restart_indices);
|
||||
}
|
||||
|
||||
void GPU_indexbuf_create_subrange_in_place(IndexBuf *elem,
|
||||
IndexBuf *elem_src,
|
||||
uint start,
|
||||
|
|
Loading…
Reference in New Issue
Please add documentation on the function and explain when to use it.