Blender V4.5
extract_mesh_vbo_pos.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_array_utils.hh"
10#include "BLI_math_vector.h"
11
12#include "extract_mesh.hh"
13
14#include "draw_subdivision.hh"
15
16namespace blender::draw {
17
19{
20 MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
21 MutableSpan loose_edge_data = vbo_data.slice(mr.corners_num, mr.loose_edges.size() * 2);
22 MutableSpan loose_vert_data = vbo_data.take_back(mr.loose_verts.size());
23
25 mr.vert_positions.size_in_bytes() + mr.corner_verts.size_in_bytes() +
26 vbo_data.size_in_bytes() + mr.loose_edges.size(),
27 [&]() {
28 array_utils::gather(mr.vert_positions, mr.corner_verts, corners_data);
29 extract_mesh_loose_edge_data(mr.vert_positions, mr.edges, mr.loose_edges, loose_edge_data);
30 array_utils::gather(mr.vert_positions, mr.loose_verts, loose_vert_data);
31 });
32}
33
35{
36 const BMesh &bm = *mr.bm;
37 MutableSpan corners_data = vbo_data.take_front(mr.corners_num);
38 MutableSpan loose_edge_data = vbo_data.slice(mr.corners_num, mr.loose_edges.size() * 2);
39 MutableSpan loose_vert_data = vbo_data.take_back(mr.loose_verts.size());
40
41 threading::parallel_for(IndexRange(bm.totface), 2048, [&](const IndexRange range) {
42 for (const int face_index : range) {
43 const BMFace &face = *BM_face_at_index(&const_cast<BMesh &>(bm), face_index);
44 const BMLoop *loop = BM_FACE_FIRST_LOOP(&face);
45 for ([[maybe_unused]] const int i : IndexRange(face.len)) {
46 const int index = BM_elem_index_get(loop);
47 corners_data[index] = bm_vert_co_get(mr, loop->v);
48 loop = loop->next;
49 }
50 }
51 });
52
53 const Span<int> loose_edges = mr.loose_edges;
54 threading::parallel_for(loose_edges.index_range(), 4096, [&](const IndexRange range) {
55 for (const int i : range) {
56 const BMEdge &edge = *BM_edge_at_index(&const_cast<BMesh &>(bm), loose_edges[i]);
57 loose_edge_data[i * 2 + 0] = bm_vert_co_get(mr, edge.v1);
58 loose_edge_data[i * 2 + 1] = bm_vert_co_get(mr, edge.v2);
59 }
60 });
61
62 const Span<int> loose_verts = mr.loose_verts;
63 threading::parallel_for(loose_verts.index_range(), 2048, [&](const IndexRange range) {
64 for (const int i : range) {
65 const BMVert &vert = *BM_vert_at_index(&const_cast<BMesh &>(bm), loose_verts[i]);
66 loose_vert_data[i] = bm_vert_co_get(mr, &vert);
67 }
68 });
69}
70
88
90{
91 static const GPUVertFormat format = []() {
95 return format;
96 }();
97 return format;
98}
99
101{
102 static const GPUVertFormat format = []() {
106 return format;
107 }();
108 return format;
109}
110
111static void extract_vertex_flags(const MeshRenderData &mr, char *flags)
112{
113 for (int i = 0; i < mr.verts_num; i++) {
114 char *flag = &flags[i];
115 const bool vert_hidden = !mr.hide_vert.is_empty() && mr.hide_vert[i];
116 /* Flag for paint mode overlay. */
117 if (vert_hidden || ((mr.orig_index_vert) && (mr.orig_index_vert[i] == ORIGINDEX_NONE))) {
118 *flag = -1;
119 }
120 else if (!mr.select_vert.is_empty() && mr.select_vert[i]) {
121 *flag = 1;
122 }
123 else {
124 *flag = 0;
125 }
126 }
127}
128
129static void extract_loose_positions_subdiv(const DRWSubdivCache &subdiv_cache,
130 const MeshRenderData &mr,
131 gpu::VertBuf &vbo)
132{
133 const Span<int> loose_verts = mr.loose_verts;
134 const int loose_edges_num = mr.loose_edges.size();
135 if (loose_verts.is_empty() && loose_edges_num == 0) {
136 return;
137 }
138
139 /* TODO(@kevindietrich): replace this when compressed normals are supported. */
140 struct SubdivPosNorLoop {
141 float pos[3];
142 float nor[3];
143 float flag;
144 };
145
146 /* Make sure buffer is active for sending loose data. */
147 GPU_vertbuf_use(&vbo);
148
149 const int resolution = subdiv_cache.resolution;
150 const Span<float3> cached_positions = subdiv_cache.loose_edge_positions;
151 const int verts_per_edge = subdiv_verts_per_coarse_edge(subdiv_cache);
152 const int edges_per_edge = subdiv_edges_per_coarse_edge(subdiv_cache);
153
154 const int loose_geom_start = subdiv_cache.num_subdiv_loops;
155
156 SubdivPosNorLoop edge_data[2];
157 memset(edge_data, 0, sizeof(SubdivPosNorLoop) * 2);
158 for (const int i : IndexRange(loose_edges_num)) {
159 const int edge_offset = loose_geom_start + i * verts_per_edge;
160 const Span<float3> positions = cached_positions.slice(i * resolution, resolution);
161 for (const int edge : IndexRange(edges_per_edge)) {
162 copy_v3_v3(edge_data[0].pos, positions[edge + 0]);
163 copy_v3_v3(edge_data[1].pos, positions[edge + 1]);
165 (edge_offset + edge * 2) * sizeof(SubdivPosNorLoop),
166 sizeof(SubdivPosNorLoop) * 2,
167 &edge_data);
168 }
169 }
170
171 const int loose_verts_start = loose_geom_start + loose_edges_num * verts_per_edge;
172 const Span<float3> positions = mr.vert_positions;
173
174 SubdivPosNorLoop vert_data;
175 memset(&vert_data, 0, sizeof(SubdivPosNorLoop));
176 for (const int i : loose_verts.index_range()) {
177 copy_v3_v3(vert_data.pos, positions[loose_verts[i]]);
179 (loose_verts_start + i) * sizeof(SubdivPosNorLoop),
180 sizeof(SubdivPosNorLoop),
181 &vert_data);
182 }
183}
184
186 const MeshRenderData &mr,
187 gpu::VertBufPtr *orco_vbo)
188{
191
192 if (subdiv_cache.num_subdiv_loops == 0) {
193 extract_loose_positions_subdiv(subdiv_cache, mr, *vbo);
194 return vbo;
195 }
196
197 static const GPUVertFormat flag_format = []() {
201 return format;
202 }();
203
204 gpu::VertBuf *flags_buffer = GPU_vertbuf_calloc();
205 GPU_vertbuf_init_with_format(*flags_buffer, flag_format);
206 GPU_vertbuf_data_alloc(*flags_buffer, divide_ceil_u(mr.verts_num, 4));
207 char *flags = flags_buffer->data<char>().data();
208 extract_vertex_flags(mr, flags);
209 GPU_vertbuf_tag_dirty(flags_buffer);
210
211 if (orco_vbo) {
212 /* FIXME(fclem): We use the last component as a way to differentiate from generic vertex
213 * attributes. This is a substantial waste of video-ram and should be done another way.
214 * Unfortunately, at the time of writing, I did not found any other "non disruptive"
215 * alternative. */
217 "orco", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
218 *orco_vbo = gpu::VertBufPtr(
220 }
221
223 subdiv_cache, flags_buffer, vbo.get(), orco_vbo ? orco_vbo->get() : nullptr);
224
225 if (subdiv_cache.use_custom_loop_normals) {
226 const Mesh *coarse_mesh = subdiv_cache.mesh;
227
228 gpu::VertBuf *src_custom_normals = GPU_vertbuf_calloc();
230 GPU_vertbuf_data_alloc(*src_custom_normals, coarse_mesh->corners_num);
231
232 src_custom_normals->data<float3>().copy_from(coarse_mesh->corner_normals());
233
234 gpu::VertBuf *dst_custom_normals = GPU_vertbuf_calloc();
236 *dst_custom_normals, get_custom_normals_format(), subdiv_cache.num_subdiv_loops);
237
239 subdiv_cache, *src_custom_normals, *dst_custom_normals, GPU_COMP_F32, 3, 0);
240
241 draw_subdiv_finalize_custom_normals(subdiv_cache, dst_custom_normals, vbo.get());
242
243 GPU_vertbuf_discard(src_custom_normals);
244 GPU_vertbuf_discard(dst_custom_normals);
245 }
246 else {
247 /* We cannot evaluate vertex normals using the limit surface, so compute them manually. */
248 gpu::VertBuf *subdiv_loop_subdiv_vert_index = draw_subdiv_build_origindex_buffer(
249 subdiv_cache.subdiv_loop_subdiv_vert_index, subdiv_cache.num_subdiv_loops);
250
251 gpu::VertBufPtr vert_normals = gpu::VertBufPtr(
253
255 vbo.get(),
257 subdiv_cache.subdiv_vertex_face_adjacency,
258 subdiv_loop_subdiv_vert_index,
259 vert_normals.get());
260
262 subdiv_cache, vert_normals.get(), subdiv_loop_subdiv_vert_index, vbo.get());
263
264 GPU_vertbuf_discard(subdiv_loop_subdiv_vert_index);
265 }
266
267 GPU_vertbuf_discard(flags_buffer);
268
269 extract_loose_positions_subdiv(subdiv_cache, mr, *vbo);
270 return vbo;
271}
272
273} // namespace blender::draw
#define ORIGINDEX_NONE
MINLINE uint divide_ceil_u(uint a, uint b)
MINLINE void copy_v3_v3(float r[3], const float a[3])
blender::gpu::VertBuf * GPU_vertbuf_create_on_device(const GPUVertFormat &format, uint v_len)
void GPU_vertbuf_init_build_on_device(blender::gpu::VertBuf &verts, const GPUVertFormat &format, uint v_len)
#define GPU_vertbuf_create_with_format(format)
void GPU_vertbuf_use(blender::gpu::VertBuf *)
void GPU_vertbuf_tag_dirty(blender::gpu::VertBuf *verts)
#define GPU_vertbuf_init_with_format(verts, format)
blender::gpu::VertBuf * GPU_vertbuf_calloc()
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
void GPU_vertbuf_update_sub(blender::gpu::VertBuf *verts, uint start, uint len, const void *data)
void GPU_vertbuf_discard(blender::gpu::VertBuf *)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT
void GPU_vertformat_alias_add(GPUVertFormat *, blender::StringRef alias)
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
GPUVertFormat GPU_vertformat_from_attribute(blender::StringRef name, const GPUVertCompType comp_type, const uint comp_len, const GPUVertFetchMode fetch_mode)
@ GPU_COMP_F32
@ GPU_COMP_I32
BMesh const char void * data
BMesh * bm
constexpr int64_t size_in_bytes() const
Definition BLI_span.hh:268
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr MutableSpan take_back(const int64_t n) const
Definition BLI_span.hh:640
constexpr T * data() const
Definition BLI_span.hh:539
constexpr int64_t size_in_bytes() const
Definition BLI_span.hh:501
constexpr MutableSpan take_front(const int64_t n) const
Definition BLI_span.hh:629
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
constexpr bool is_empty() const
Definition BLI_span.hh:260
MutableSpan< T > data()
Extraction of Mesh data into VBO to feed to GPU.
uint pos
uint nor
format
int subdiv_verts_per_coarse_edge(const DRWSubdivCache &cache)
int subdiv_edges_per_coarse_edge(const DRWSubdivCache &cache)
static void extract_positions_mesh(const MeshRenderData &mr, MutableSpan< float3 > vbo_data)
static void extract_positions_bm(const MeshRenderData &mr, MutableSpan< float3 > vbo_data)
void draw_subdiv_interp_custom_data(const DRWSubdivCache &cache, gpu::VertBuf &src_data, gpu::VertBuf &dst_data, GPUVertCompType comp_type, int dimensions, int dst_offset)
static void extract_vertex_flags(const MeshRenderData &mr, char *flags)
static void extract_loose_positions_subdiv(const DRWSubdivCache &subdiv_cache, const MeshRenderData &mr, gpu::VertBuf &vbo)
void draw_subdiv_accumulate_normals(const DRWSubdivCache &cache, gpu::VertBuf *pos_nor, gpu::VertBuf *face_adjacency_offsets, gpu::VertBuf *face_adjacency_lists, gpu::VertBuf *vertex_loop_map, gpu::VertBuf *vert_normals)
gpu::VertBufPtr extract_positions_subdiv(const DRWSubdivCache &subdiv_cache, const MeshRenderData &mr, gpu::VertBufPtr *orco_vbo)
void draw_subdiv_extract_pos_nor(const DRWSubdivCache &cache, gpu::VertBuf *flags_buffer, gpu::VertBuf *pos_nor, gpu::VertBuf *orco)
int subdiv_full_vbo_size(const MeshRenderData &mr, const DRWSubdivCache &cache)
static const GPUVertFormat & get_custom_normals_format()
void draw_subdiv_finalize_normals(const DRWSubdivCache &cache, gpu::VertBuf *vert_normals, gpu::VertBuf *subdiv_loop_subdiv_vert_index, gpu::VertBuf *pos_nor)
static const GPUVertFormat & get_normals_format()
gpu::VertBufPtr extract_positions(const MeshRenderData &mr)
gpu::VertBuf * draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_loops)
const GPUVertFormat & draw_subdiv_get_pos_nor_format()
void draw_subdiv_finalize_custom_normals(const DRWSubdivCache &cache, gpu::VertBuf *src_custom_normals, gpu::VertBuf *pos_nor)
std::unique_ptr< gpu::VertBuf, gpu::VertBufDeleter > VertBufPtr
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
void memory_bandwidth_bound_task(const int64_t approximate_bytes_touched, const Function &function)
Definition BLI_task.hh:265
VecBase< float, 3 > float3
int corners_num
gpu::VertBuf * subdiv_vertex_face_adjacency_offsets
VArraySpan< bool > select_vert
i
Definition text_draw.cc:230
uint8_t flag
Definition wm_window.cc:139