Mesh: Draw: Replace extractor abstraction for edge factor buffer

Part of #116901.
The BMesh version of the algorithm was parallelized because BMesh has
edge to face topology lookup available.

This also allows removing `GPU_vertbuf_steal_data`, by just generating
the correct data type in the first place. Removing that should help dealing
with improvements to VBO data ownership in the future.
This commit is contained in:
Hans Goudey
2024-06-02 07:15:48 -04:00
committed by Hans Goudey
parent 18e76b5938
commit d1049f6082
5 changed files with 129 additions and 213 deletions

View File

@@ -532,6 +532,7 @@ static void mesh_extract_render_data_node_exec(void *__restrict task_data)
const bool request_face_normals = DRW_vbo_requested(buffers.vbo.nor) ||
DRW_vbo_requested(buffers.vbo.fdots_nor) ||
DRW_vbo_requested(buffers.vbo.edge_fac) ||
(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;
@@ -645,7 +646,6 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
EXTRACT_ADD_REQUESTED(vbo, uv);
EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
EXTRACT_ADD_REQUESTED(vbo, orco);
EXTRACT_ADD_REQUESTED(vbo, edge_fac);
EXTRACT_ADD_REQUESTED(vbo, edituv_data);
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_area);
EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
@@ -671,11 +671,11 @@ void mesh_buffer_cache_create_requested(TaskGraph &task_graph,
!DRW_ibo_requested(buffers.ibo.points) && !DRW_ibo_requested(buffers.ibo.fdots) &&
!DRW_vbo_requested(buffers.vbo.pos) && !DRW_vbo_requested(buffers.vbo.fdots_pos) &&
!DRW_vbo_requested(buffers.vbo.nor) && !DRW_vbo_requested(buffers.vbo.vnor) &&
!DRW_vbo_requested(buffers.vbo.fdots_nor) && !DRW_vbo_requested(buffers.vbo.tan) &&
!DRW_vbo_requested(buffers.vbo.edit_data) && !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.fdots_nor) && !DRW_vbo_requested(buffers.vbo.edge_fac) &&
!DRW_vbo_requested(buffers.vbo.tan) && !DRW_vbo_requested(buffers.vbo.edit_data) &&
!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))
{
return;
}
@@ -788,6 +788,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.edge_fac)) {
struct TaskData {
MeshRenderData &mr;
MeshBufferCache &mbc;
};
TaskNode *task_node = BLI_task_graph_node_create(
&task_graph,
[](void *__restrict task_data) {
const TaskData &data = *static_cast<TaskData *>(task_data);
extract_edge_factor(data.mr, *data.mbc.buff.vbo.edge_fac);
},
new TaskData{*mr, mbc},
[](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;
@@ -1042,7 +1057,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, edge_fac);
EXTRACT_ADD_REQUESTED(vbo, edituv_data);
/* Make sure UVs are computed before edituv stuffs. */
EXTRACT_ADD_REQUESTED(vbo, uv);
@@ -1058,11 +1072,11 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
!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.orco) && !DRW_vbo_requested(buffers.vbo.nor) &&
!DRW_vbo_requested(buffers.vbo.tan) && !DRW_vbo_requested(buffers.vbo.edit_data) &&
!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.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.edge_fac) && !DRW_vbo_requested(buffers.vbo.tan) &&
!DRW_vbo_requested(buffers.vbo.edit_data) && !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.weights) && !DRW_vbo_requested(buffers.vbo.fdots_nor) &&
!DRW_vbo_requested(buffers.vbo.fdots_pos) && !DRW_ibo_requested(buffers.ibo.fdots))
{
return;
}
@@ -1078,6 +1092,9 @@ void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache &cache,
/* The corner normals calculation uses positions and normals stored in the `pos` VBO. */
extract_normals_subdiv(subdiv_cache, *buffers.vbo.pos, *buffers.vbo.nor);
}
if (DRW_vbo_requested(buffers.vbo.edge_fac)) {
extract_edge_factor_subdiv(subdiv_cache, mr, *buffers.vbo.pos, *buffers.vbo.edge_fac);
}
if (DRW_ibo_requested(buffers.ibo.lines) || DRW_ibo_requested(buffers.ibo.lines_loose)) {
extract_lines_subdiv(
subdiv_cache, mr, buffers.ibo.lines, buffers.ibo.lines_loose, cache.no_loose_wire);

View File

@@ -374,6 +374,11 @@ void extract_normals_subdiv(const DRWSubdivCache &subdiv_cache,
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_edge_factor(const MeshRenderData &mr, gpu::VertBuf &vbo);
void extract_edge_factor_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
gpu::VertBuf &pos_nor,
gpu::VertBuf &vbo);
void extract_tris(const MeshRenderData &mr,
const SortedFaceData &face_sorted,
@@ -446,7 +451,6 @@ extern const MeshExtract extract_edituv_fdots;
extern const MeshExtract extract_uv;
extern const MeshExtract extract_sculpt_data;
extern const MeshExtract extract_orco;
extern const MeshExtract extract_edge_fac;
extern const MeshExtract extract_edituv_data;
extern const MeshExtract extract_edituv_stretch_area;
extern const MeshExtract extract_edituv_stretch_angle;

View File

@@ -6,8 +6,6 @@
* \ingroup draw
*/
#include "MEM_guardedalloc.h"
#include "BLI_math_vector.hh"
#include "GPU_capabilities.hh"
@@ -18,11 +16,6 @@
#define FORCE_HIDE 255
namespace blender::draw {
/* ---------------------------------------------------------------------- */
/** \name Extract Edge Factor
* Defines how much an edge is visible.
* \{ */
struct MEdgeDataPrev {
int corner_a;
@@ -32,115 +25,63 @@ struct MEdgeDataPrev {
int data;
};
struct MeshExtract_EdgeFac_Data {
uint8_t *vbo_data;
bool use_edge_render;
/* Number of loop per edge. */
uint8_t *edge_loop_count;
MEdgeDataPrev *edge_pdata;
};
/**
* Calculates a factor that is used to identify the minimum angle in the shader to display an edge.
* NOTE: Keep in sync with `common_subdiv_vbo_edge_fac_comp.glsl`.
*/
BLI_INLINE uint8_t loop_edge_factor_get(const float3 &fa_no, const float3 &fb_no)
template<typename T> T edge_factor_calc(const float3 &a, const float3 &b);
template<> inline float edge_factor_calc<float>(const float3 &a, const float3 &b)
{
const float cosine = math::dot(fa_no, fb_no);
const float cosine = math::dot(a, b);
/* Re-scale to the slider range. */
float fac = (200 * (cosine - 1.0f)) + 1.0f;
CLAMP(fac, 0.0f, 1.0f);
return fac;
}
template<> inline uint8_t edge_factor_calc<uint8_t>(const float3 &a, const float3 &b)
{
/* 255 is a reserved value to force hide the wire. */
return uint8_t(fac * 254);
return uint8_t(edge_factor_calc<float>(a, b) * 254);
}
static void extract_edge_fac_init(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void *tls_data)
template<typename T>
static void extract_edge_factor_mesh(const MeshRenderData &mr, MutableSpan<T> vbo_data)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, mr.corners_num + mr.loose_indices_num);
MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(tls_data);
if (mr.extract_type == MR_EXTRACT_MESH) {
data->use_edge_render = !mr.mesh->runtime->subsurf_optimal_display_edges.is_empty();
data->edge_loop_count = MEM_cnew_array<uint8_t>(mr.edges_num, __func__);
data->edge_pdata = (MEdgeDataPrev *)MEM_malloc_arrayN(
mr.edges_num, sizeof(MEdgeDataPrev), __func__);
}
else {
/* HACK to bypass non-manifold check in mesh_edge_fac_finish(). */
data->use_edge_render = true;
}
data->vbo_data = static_cast<uchar *>(GPU_vertbuf_get_data(vbo));
}
static void extract_edge_fac_iter_face_bm(const MeshRenderData &mr,
const BMFace *f,
const int /*f_index*/,
void *_data)
{
MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_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);
if (BM_edge_is_manifold(l_iter->e)) {
BMFace *fb = l_iter->f != f ? l_iter->f : l_iter->radial_next->f;
data->vbo_data[l_index] = loop_edge_factor_get(float3(bm_face_no_get(mr, f)),
float3(bm_face_no_get(mr, fb)));
}
else {
data->vbo_data[l_index] = 0;
}
} while ((l_iter = l_iter->next) != l_first);
}
static void extract_edge_fac_iter_face_mesh(const MeshRenderData &mr,
const int face_index,
void *_data)
{
MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data);
const IndexRange face = mr.faces[face_index];
const OffsetIndices faces = mr.faces;
const Span<int> corner_edges = mr.corner_edges;
const Span<float3> face_normals = mr.face_normals;
const BitSpan optimal_display_edges = mr.mesh->runtime->subsurf_optimal_display_edges;
for (const int corner : face) {
const int edge = mr.corner_edges[corner];
Array<int8_t> edge_face_count(mr.edges_num, 0);
Array<MEdgeDataPrev> edge_data(mr.edges_num);
if (data->use_edge_render && !optimal_display_edges[edge]) {
data->vbo_data[corner] = FORCE_HIDE;
}
else {
MEdgeDataPrev *medata = &data->edge_pdata[edge];
for (const int face : faces.index_range()) {
for (const int corner : faces[face]) {
const int edge = corner_edges[corner];
if (!optimal_display_edges.is_empty() && !optimal_display_edges[edge]) {
vbo_data[corner] = FORCE_HIDE;
continue;
}
uint8_t corner_count = data->edge_loop_count[edge];
data->vbo_data[corner] = 0;
if (corner_count < 4) {
if (corner_count == 0) {
MEdgeDataPrev *medata = &edge_data[edge];
const int8_t face_count = edge_face_count[edge];
vbo_data[corner] = 0;
if (face_count < 4) {
if (face_count == 0) {
/* Prepare to calculate the factor. */
medata->corner_a = corner;
medata->data = face_index;
medata->data = face;
}
else if (corner_count == 1) {
else if (face_count == 1) {
/* Calculate the factor for both corners. */
const int face_index_a = medata->data;
uint8_t fac = loop_edge_factor_get(float3(mr.face_normals[face_index_a]),
float3(mr.face_normals[face_index]));
data->vbo_data[medata->corner_a] = fac;
data->vbo_data[corner] = fac;
const int other_face = medata->data;
const T factor = edge_factor_calc<T>(face_normals[other_face], face_normals[face]);
vbo_data[medata->corner_a] = factor;
vbo_data[corner] = factor;
/* If the count still changes, use this `data` member to inform the corner. */
medata->data = corner;
@@ -149,71 +90,74 @@ static void extract_edge_fac_iter_face_mesh(const MeshRenderData &mr,
/* Non-manifold edge. Always visible. */
const int corner_a = medata->corner_a;
const int corner_b = medata->data;
data->vbo_data[corner_a] = 0;
data->vbo_data[corner_b] = 0;
vbo_data[corner_a] = 0;
vbo_data[corner_b] = 0;
}
/* Increment the corner_count count. */
data->edge_loop_count[edge] = corner_count + 1;
edge_face_count[edge]++;
}
}
}
}
static void extract_edge_fac_iter_loose_edge_bm(const MeshRenderData &mr,
const BMEdge * /*eed*/,
const int loose_edge_i,
void *_data)
template<typename T>
static void extract_edge_factor_bm(const MeshRenderData &mr, MutableSpan<T> vbo_data)
{
MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data);
data->vbo_data[mr.corners_num + (loose_edge_i * 2) + 0] = 0;
data->vbo_data[mr.corners_num + (loose_edge_i * 2) + 1] = 0;
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 BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
for ([[maybe_unused]] const int i : IndexRange(face.len)) {
const int index = BM_elem_index_get(loop);
if (BM_edge_is_manifold(loop->e)) {
const BMFace *other_face = loop->radial_next->f;
vbo_data[index] = edge_factor_calc<T>(float3(bm_face_no_get(mr, &face)),
float3(bm_face_no_get(mr, other_face)));
}
else {
vbo_data[index] = T(0);
}
loop = loop->next;
}
}
});
}
static void extract_edge_fac_iter_loose_edge_mesh(const MeshRenderData &mr,
const int2 /*edge*/,
const int loose_edge_i,
void *_data)
void extract_edge_factor(const MeshRenderData &mr, gpu::VertBuf &vbo)
{
MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data);
data->vbo_data[mr.corners_num + loose_edge_i * 2 + 0] = 0;
data->vbo_data[mr.corners_num + loose_edge_i * 2 + 1] = 0;
}
static void extract_edge_fac_finish(const MeshRenderData &mr,
MeshBatchCache & /*cache*/,
void *buf,
void *_data)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buf);
MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data);
if (GPU_crappy_amd_driver() || GPU_minimum_per_vertex_stride() > 1) {
/* Some AMD drivers strangely crash with VBO's with a one byte format.
* To workaround we reinitialize the VBO with another format and convert
* all bytes to floats. */
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT);
}
/* We keep the data reference in data->vbo_data. */
data->vbo_data = static_cast<uchar *>(GPU_vertbuf_steal_data(vbo));
GPU_vertbuf_clear(vbo);
int buf_len = mr.corners_num + mr.loose_indices_num;
GPU_vertbuf_init_with_format(vbo, &format);
GPU_vertbuf_data_alloc(vbo, buf_len);
float *fdata_legacy = (float *)GPU_vertbuf_get_data(vbo);
for (int corner = 0; corner < buf_len; corner++, fdata_legacy++) {
*fdata_legacy = data->vbo_data[corner] / 255.0f;
GPU_vertbuf_init_with_format(&vbo, &format);
GPU_vertbuf_data_alloc(&vbo, mr.corners_num + mr.loose_indices_num);
MutableSpan vbo_data(static_cast<float *>(GPU_vertbuf_get_data(&vbo)), mr.corners_num);
if (mr.extract_type == MR_EXTRACT_MESH) {
extract_edge_factor_mesh(mr, vbo_data);
}
/* Free old byte data. */
MEM_freeN(data->vbo_data);
else {
extract_edge_factor_bm(mr, vbo_data);
}
vbo_data.take_back(mr.loose_indices_num).fill(0.0f);
}
else {
static GPUVertFormat format = {0};
if (format.attr_len == 0) {
GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT);
}
GPU_vertbuf_init_with_format(&vbo, &format);
GPU_vertbuf_data_alloc(&vbo, mr.corners_num + mr.loose_indices_num);
MutableSpan vbo_data(static_cast<uint8_t *>(GPU_vertbuf_get_data(&vbo)), mr.corners_num);
if (mr.extract_type == MR_EXTRACT_MESH) {
extract_edge_factor_mesh(mr, vbo_data);
}
else {
extract_edge_factor_bm(mr, vbo_data);
}
vbo_data.take_back(mr.loose_indices_num).fill(uint8_t(0));
}
MEM_SAFE_FREE(data->edge_loop_count);
MEM_SAFE_FREE(data->edge_pdata);
}
/* Different function than the one used for the non-subdivision case, as we directly take care of
@@ -279,78 +223,44 @@ static gpu::VertBuf *build_poly_other_map_vbo(const DRWSubdivCache &subdiv_cache
return vbo;
}
static void extract_edge_fac_init_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
MeshBatchCache &cache,
void *buffer,
void * /*data*/)
void extract_edge_factor_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
gpu::VertBuf &pos_nor,
gpu::VertBuf &vbo)
{
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buffer);
GPU_vertbuf_init_build_on_device(vbo,
GPU_vertbuf_init_build_on_device(&vbo,
get_subdiv_edge_fac_format(),
subdiv_cache.num_subdiv_loops +
subdiv_loose_edges_num(mr, subdiv_cache) * 2);
gpu::VertBuf *pos_nor = cache.final.buff.vbo.pos;
gpu::VertBuf *poly_other_map = build_poly_other_map_vbo(subdiv_cache);
draw_subdiv_build_edge_fac_buffer(
subdiv_cache, pos_nor, subdiv_cache.edges_draw_flag, poly_other_map, vbo);
subdiv_cache, &pos_nor, subdiv_cache.edges_draw_flag, poly_other_map, &vbo);
GPU_vertbuf_discard(poly_other_map);
}
static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache &subdiv_cache,
const MeshRenderData &mr,
void *buffer,
void * /*data*/)
{
const int loose_edges_num = subdiv_loose_edges_num(mr, subdiv_cache);
if (loose_edges_num == 0) {
return;
}
gpu::VertBuf *vbo = static_cast<gpu::VertBuf *>(buffer);
/* Make sure buffer is active for sending loose data. */
GPU_vertbuf_use(vbo);
GPU_vertbuf_use(&vbo);
const int offset = subdiv_cache.num_subdiv_loops;
if (GPU_crappy_amd_driver() || GPU_minimum_per_vertex_stride() > 1) {
const float values[2] = {1.0f, 1.0f};
for (const int i : IndexRange(loose_edges_num)) {
GPU_vertbuf_update_sub(vbo, (offset + i * 2) * sizeof(float), sizeof(values), values);
GPU_vertbuf_update_sub(&vbo, (offset + i * 2) * sizeof(float), sizeof(values), values);
}
}
else {
const char values[2] = {255, 255};
const uint8_t values[2] = {255, 255};
for (const int i : IndexRange(loose_edges_num)) {
GPU_vertbuf_update_sub(vbo, (offset + i * 2) * sizeof(char), sizeof(values), values);
GPU_vertbuf_update_sub(&vbo, (offset + i * 2) * sizeof(uint8_t), sizeof(values), values);
}
}
}
constexpr MeshExtract create_extractor_edge_fac()
{
MeshExtract extractor = {nullptr};
extractor.init = extract_edge_fac_init;
extractor.iter_face_bm = extract_edge_fac_iter_face_bm;
extractor.iter_face_mesh = extract_edge_fac_iter_face_mesh;
extractor.iter_loose_edge_bm = extract_edge_fac_iter_loose_edge_bm;
extractor.iter_loose_edge_mesh = extract_edge_fac_iter_loose_edge_mesh;
extractor.init_subdiv = extract_edge_fac_init_subdiv;
extractor.iter_loose_geom_subdiv = extract_edge_fac_loose_geom_subdiv;
extractor.finish = extract_edge_fac_finish;
extractor.data_type = MR_DATA_POLY_NOR;
extractor.data_size = sizeof(MeshExtract_EdgeFac_Data);
extractor.use_threading = false;
extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edge_fac);
return extractor;
}
/** \} */
const MeshExtract extract_edge_fac = create_extractor_edge_fac();
} // namespace blender::draw

View File

@@ -245,12 +245,6 @@ GPU_INLINE uint GPU_vertbuf_raw_used(GPUVertBufRaw *a)
void GPU_vertbuf_attr_get_raw_data(blender::gpu::VertBuf *, uint a_idx, GPUVertBufRaw *access);
/**
* Returns the data buffer and set it to null internally to avoid freeing.
* \note Be careful when using this. The data needs to match the expected format.
*/
void *GPU_vertbuf_steal_data(blender::gpu::VertBuf *verts);
/**
* \note Be careful when using this. The data needs to match the expected format.
*/

View File

@@ -282,15 +282,6 @@ void *GPU_vertbuf_get_data(const VertBuf *verts)
return verts->data;
}
void *GPU_vertbuf_steal_data(VertBuf *verts)
{
/* TODO: Assert that the format has no padding. */
BLI_assert(verts->data);
void *data = verts->data;
verts->data = nullptr;
return data;
}
const GPUVertFormat *GPU_vertbuf_get_format(const VertBuf *verts)
{
return &verts->format;