Blender  V3.3
extract_mesh_vbo_tan.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2021 Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "BLI_string.h"
11 
12 #include "BKE_editmesh.h"
13 #include "BKE_editmesh_tangent.h"
14 #include "BKE_mesh.h"
15 #include "BKE_mesh_tangent.h"
16 
17 #include "extract_mesh.hh"
18 
19 #include "draw_subdivision.h"
20 
21 namespace blender::draw {
22 
23 /* ---------------------------------------------------------------------- */
28  MeshBatchCache *cache,
30  GPUVertCompType comp_type,
31  GPUVertFetchMode fetch_mode,
32  CustomData *r_loop_data,
33  int *r_v_len,
34  int *r_tan_len,
35  char r_tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME],
36  bool *r_use_orco_tan)
37 {
39 
40  CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata;
41  CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata;
42  uint32_t tan_layers = cache->cd_used.tan;
43  float(*orco)[3] = (float(*)[3])CustomData_get_layer(cd_vdata, CD_ORCO);
44  bool orco_allocated = false;
45  bool use_orco_tan = cache->cd_used.tan_orco != 0;
46 
47  int tan_len = 0;
48 
49  /* FIXME(T91838): This is to avoid a crash when orco tangent was requested but there are valid
50  * uv layers. It would be better to fix the root cause. */
51  if (tan_layers == 0 && use_orco_tan && CustomData_get_layer_index(cd_ldata, CD_MLOOPUV) != -1) {
52  tan_layers = 1;
53  use_orco_tan = false;
54  }
55 
56  for (int i = 0; i < MAX_MTFACE; i++) {
57  if (tan_layers & (1 << i)) {
58  char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
59  const char *layer_name = CustomData_get_layer_name(cd_ldata, CD_MLOOPUV, i);
60  GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
61  /* Tangent layer name. */
62  BLI_snprintf(attr_name, sizeof(attr_name), "t%s", attr_safe_name);
63  GPU_vertformat_attr_add(format, attr_name, comp_type, 4, fetch_mode);
64  /* Active render layer name. */
65  if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) {
67  }
68  /* Active display layer name. */
69  if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) {
71  }
72 
73  BLI_strncpy(r_tangent_names[tan_len++], layer_name, MAX_CUSTOMDATA_LAYER_NAME);
74  }
75  }
76  if (use_orco_tan && orco == nullptr) {
77  /* If `orco` is not available compute it ourselves */
78  orco_allocated = true;
79  orco = (float(*)[3])MEM_mallocN(sizeof(*orco) * mr->vert_len, __func__);
80 
81  if (mr->extract_type == MR_EXTRACT_BMESH) {
82  BMesh *bm = mr->bm;
83  for (int v = 0; v < mr->vert_len; v++) {
84  const BMVert *eve = BM_vert_at_index(bm, v);
85  /* Exceptional case where #bm_vert_co_get can be avoided, as we want the original coords.
86  * not the distorted ones. */
87  copy_v3_v3(orco[v], eve->co);
88  }
89  }
90  else {
91  const MVert *mv = mr->mvert;
92  for (int v = 0; v < mr->vert_len; v++, mv++) {
93  copy_v3_v3(orco[v], mv->co);
94  }
95  }
96  BKE_mesh_orco_verts_transform(mr->me, orco, mr->vert_len, 0);
97  }
98 
99  /* Start Fresh */
100  CustomData_reset(r_loop_data);
101  if (tan_len != 0 || use_orco_tan) {
102  short tangent_mask = 0;
103  bool calc_active_tangent = false;
104  if (mr->extract_type == MR_EXTRACT_BMESH) {
106  calc_active_tangent,
107  r_tangent_names,
108  tan_len,
109  mr->poly_normals,
110  mr->loop_normals,
111  orco,
112  r_loop_data,
113  mr->loop_len,
114  &tangent_mask);
115  }
116  else {
118  mr->mpoly,
119  mr->poly_len,
120  mr->mloop,
121  mr->mlooptri,
122  mr->tri_len,
123  cd_ldata,
124  calc_active_tangent,
125  r_tangent_names,
126  tan_len,
127  mr->vert_normals,
128  mr->poly_normals,
129  mr->loop_normals,
130  orco,
131  r_loop_data,
132  mr->loop_len,
133  &tangent_mask);
134  }
135  }
136 
137  if (use_orco_tan) {
138  char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME];
139  const char *layer_name = CustomData_get_layer_name(r_loop_data, CD_TANGENT, 0);
140  GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME);
141  BLI_snprintf(attr_name, sizeof(*attr_name), "t%s", attr_safe_name);
142  GPU_vertformat_attr_add(format, attr_name, comp_type, 4, fetch_mode);
145  }
146 
147  if (orco_allocated) {
148  MEM_SAFE_FREE(orco);
149  }
150 
151  int v_len = mr->loop_len;
152  if (format->attr_len == 0) {
154  /* VBO will not be used, only allocate minimum of memory. */
155  v_len = 1;
156  }
157 
158  *r_use_orco_tan = use_orco_tan;
159  *r_v_len = v_len;
160  *r_tan_len = tan_len;
161 }
162 
163 static void extract_tan_ex_init(const MeshRenderData *mr,
164  MeshBatchCache *cache,
165  GPUVertBuf *vbo,
166  const bool do_hq)
167 {
168  GPUVertCompType comp_type = do_hq ? GPU_COMP_I16 : GPU_COMP_I10;
170 
171  GPUVertFormat format = {0};
172  CustomData loop_data;
173  int v_len = 0;
174  int tan_len = 0;
175  bool use_orco_tan;
176  char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME];
178  cache,
179  &format,
180  comp_type,
181  fetch_mode,
182  &loop_data,
183  &v_len,
184  &tan_len,
185  tangent_names,
186  &use_orco_tan);
187 
189  GPU_vertbuf_data_alloc(vbo, v_len);
190 
191  if (do_hq) {
192  short(*tan_data)[4] = (short(*)[4])GPU_vertbuf_get_data(vbo);
193  for (int i = 0; i < tan_len; i++) {
194  const char *name = tangent_names[i];
195  float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(
196  &loop_data, CD_TANGENT, name);
197  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
198  normal_float_to_short_v3(*tan_data, layer_data[ml_index]);
199  (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
200  tan_data++;
201  }
202  }
203  if (use_orco_tan) {
204  float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0);
205  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
206  normal_float_to_short_v3(*tan_data, layer_data[ml_index]);
207  (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? SHRT_MAX : SHRT_MIN;
208  tan_data++;
209  }
210  }
211  }
212  else {
214  for (int i = 0; i < tan_len; i++) {
215  const char *name = tangent_names[i];
216  float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(
217  &loop_data, CD_TANGENT, name);
218  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
219  *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]);
220  tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2;
221  tan_data++;
222  }
223  }
224  if (use_orco_tan) {
225  float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0);
226  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
227  *tan_data = GPU_normal_convert_i10_v3(layer_data[ml_index]);
228  tan_data->w = (layer_data[ml_index][3] > 0.0f) ? 1 : -2;
229  tan_data++;
230  }
231  }
232  }
233 
234  CustomData_free(&loop_data, mr->loop_len);
235 }
236 
237 static void extract_tan_init(const MeshRenderData *mr,
238  MeshBatchCache *cache,
239  void *buf,
240  void *UNUSED(tls_data))
241 {
242  GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
243  extract_tan_ex_init(mr, cache, vbo, false);
244 }
245 
247 {
248  static GPUVertFormat format = {0};
249  if (format.attr_len == 0) {
251  }
252  return &format;
253 }
254 
255 static void extract_tan_init_subdiv(const DRWSubdivCache *subdiv_cache,
256  const MeshRenderData *mr,
257  MeshBatchCache *cache,
258  void *buffer,
259  void *UNUSED(data))
260 {
261  GPUVertCompType comp_type = GPU_COMP_F32;
262  GPUVertFetchMode fetch_mode = GPU_FETCH_FLOAT;
263  GPUVertFormat format = {0};
264  CustomData loop_data;
265  int coarse_len = 0;
266  int tan_len = 0;
267  bool use_orco_tan;
268  char tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME];
270  cache,
271  &format,
272  comp_type,
273  fetch_mode,
274  &loop_data,
275  &coarse_len,
276  &tan_len,
277  tangent_names,
278  &use_orco_tan);
279 
280  GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer);
281  GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops);
282 
283  GPUVertBuf *coarse_vbo = GPU_vertbuf_calloc();
284  /* Dynamic as we upload and interpolate layers one at a time. */
286  GPU_vertbuf_data_alloc(coarse_vbo, coarse_len);
287 
288  /* Index of the tangent layer in the compact buffer. Used layers are stored in a single buffer.
289  */
290  int pack_layer_index = 0;
291  for (int i = 0; i < tan_len; i++) {
292  float(*tan_data)[4] = (float(*)[4])GPU_vertbuf_get_data(coarse_vbo);
293  const char *name = tangent_names[i];
294  const float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_named(
295  &loop_data, CD_TANGENT, name);
296  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
297  copy_v3_v3(*tan_data, layer_data[ml_index]);
298  (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? 1.0f : -1.0f;
299  tan_data++;
300  }
301 
302  /* Ensure data is uploaded properly. */
303  GPU_vertbuf_tag_dirty(coarse_vbo);
304  /* Include stride in offset. */
305  const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 4 * pack_layer_index++;
306  draw_subdiv_interp_custom_data(subdiv_cache, coarse_vbo, dst_buffer, 4, dst_offset, false);
307  }
308  if (use_orco_tan) {
309  float(*tan_data)[4] = (float(*)[4])GPU_vertbuf_get_data(coarse_vbo);
310  const float(*layer_data)[4] = (float(*)[4])CustomData_get_layer_n(&loop_data, CD_TANGENT, 0);
311  for (int ml_index = 0; ml_index < mr->loop_len; ml_index++) {
312  copy_v3_v3(*tan_data, layer_data[ml_index]);
313  (*tan_data)[3] = (layer_data[ml_index][3] > 0.0f) ? 1.0f : -1.0f;
314  tan_data++;
315  }
316 
317  /* Ensure data is uploaded properly. */
318  GPU_vertbuf_tag_dirty(coarse_vbo);
319  /* Include stride in offset. */
320  const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 4 * pack_layer_index++;
321  draw_subdiv_interp_custom_data(subdiv_cache, coarse_vbo, dst_buffer, 4, dst_offset, false);
322  }
323 
324  CustomData_free(&loop_data, mr->loop_len);
325  GPU_vertbuf_discard(coarse_vbo);
326 }
327 
329 {
330  MeshExtract extractor = {nullptr};
331  extractor.init = extract_tan_init;
334  extractor.data_size = 0;
335  extractor.use_threading = false;
336  extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.tan);
337  return extractor;
338 }
339 
342 /* ---------------------------------------------------------------------- */
346 static void extract_tan_hq_init(const MeshRenderData *mr,
347  MeshBatchCache *cache,
348  void *buf,
349  void *UNUSED(tls_data))
350 {
351  GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
352  extract_tan_ex_init(mr, cache, vbo, true);
353 }
354 
356 {
357  MeshExtract extractor = {nullptr};
358  extractor.init = extract_tan_hq_init;
360  extractor.data_size = 0;
361  extractor.use_threading = false;
362  extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.tan);
363  return extractor;
364 }
365 
368 } // namespace blender::draw
369 
typedef float(TangentPoint)[2]
void CustomData_free(struct CustomData *data, int totelem)
Definition: customdata.cc:2373
const char * CustomData_get_layer_name(const struct CustomData *data, int type, int n)
int CustomData_get_active_layer(const struct CustomData *data, int type)
void * CustomData_get_layer_named(const struct CustomData *data, int type, const char *name)
void * CustomData_get_layer_n(const struct CustomData *data, int type, int n)
int CustomData_get_layer_index(const struct CustomData *data, int type)
void * CustomData_get_layer(const struct CustomData *data, int type)
void CustomData_reset(struct CustomData *data)
Definition: customdata.cc:2367
int CustomData_get_render_layer(const struct CustomData *data, int type)
void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, bool calc_active_tangent, const char(*tangent_names)[MAX_NAME], int tangent_names_len, const float(*poly_normals)[3], const float(*loop_normals)[3], const float(*vert_orco)[3], CustomData *dm_loopdata_out, uint dm_loopdata_out_len, short *tangent_mask_curr_p)
void BKE_mesh_orco_verts_transform(struct Mesh *me, float(*orco)[3], int totvert, int invert)
Definition: mesh.cc:1331
void BKE_mesh_calc_loop_tangent_ex(const struct MVert *mvert, const struct MPoly *mpoly, uint mpoly_len, const struct MLoop *mloop, const struct MLoopTri *looptri, uint looptri_len, struct CustomData *loopdata, bool calc_active_tangent, const char(*tangent_names)[64], int tangent_names_len, const float(*vert_normals)[3], const float(*poly_normals)[3], const float(*loop_normals)[3], const float(*vert_orco)[3], struct CustomData *loopdata_out, uint loopdata_out_len, short *tangent_mask_curr_p)
MINLINE void normal_float_to_short_v3(short r[3], const float n[3])
MINLINE void copy_v3_v3(float r[3], const float a[3])
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string.c:64
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
#define UNUSED(x)
#define MAX_CUSTOMDATA_LAYER_NAME
@ CD_MLOOPUV
@ CD_TANGENT
#define MAX_MTFACE
void GPU_vertbuf_discard(GPUVertBuf *)
struct GPUVertBuf GPUVertBuf
GPUVertBuf * GPU_vertbuf_calloc(void)
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
void GPU_vertbuf_init_with_format_ex(GPUVertBuf *, const GPUVertFormat *, GPUUsageType)
#define GPU_vertbuf_init_with_format(verts, format)
void * GPU_vertbuf_get_data(const GPUVertBuf *verts)
void GPU_vertbuf_init_build_on_device(GPUVertBuf *verts, GPUVertFormat *format, uint v_len)
void GPU_vertbuf_tag_dirty(GPUVertBuf *verts)
@ GPU_USAGE_DYNAMIC
void GPU_vertformat_safe_attr_name(const char *attr_name, char *r_safe_name, uint max_len)
GPUVertFetchMode
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
#define GPU_MAX_SAFE_ATTR_NAME
BLI_INLINE GPUPackedNormal GPU_normal_convert_i10_v3(const float data[3])
void GPU_vertformat_alias_add(GPUVertFormat *, const char *alias)
void GPU_vertformat_deinterleave(GPUVertFormat *format)
GPUVertCompType
@ GPU_COMP_I10
@ GPU_COMP_F32
@ GPU_COMP_I16
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
ATTR_WARN_UNUSED_RESULT BMesh * bm
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:103
ATTR_WARN_UNUSED_RESULT const BMVert * v
@ MR_DATA_TAN_LOOP_NOR
@ MR_DATA_POLY_NOR
@ MR_DATA_LOOPTRI
void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache, GPUVertBuf *src_data, GPUVertBuf *dst_data, int dimensions, int dst_offset, bool compress_to_u16)
Extraction of Mesh data into VBO to feed to GPU.
@ MR_EXTRACT_BMESH
Definition: extract_mesh.hh:31
const MeshExtract extract_tan_hq
const MeshExtract extract_tan
ccl_global float * buffer
format
Definition: logImageCore.h:38
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
constexpr MeshExtract create_extractor_tan()
static GPUVertFormat * get_coarse_tan_format()
static void extract_tan_init_common(const MeshRenderData *mr, MeshBatchCache *cache, GPUVertFormat *format, GPUVertCompType comp_type, GPUVertFetchMode fetch_mode, CustomData *r_loop_data, int *r_v_len, int *r_tan_len, char r_tangent_names[MAX_MTFACE][MAX_CUSTOMDATA_LAYER_NAME], bool *r_use_orco_tan)
static void extract_tan_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *mr, MeshBatchCache *cache, void *buffer, void *UNUSED(data))
constexpr MeshExtract create_extractor_tan_hq()
static void extract_tan_hq_init(const MeshRenderData *mr, MeshBatchCache *cache, void *buf, void *UNUSED(tls_data))
static void extract_tan_ex_init(const MeshRenderData *mr, MeshBatchCache *cache, GPUVertBuf *vbo, const bool do_hq)
static void extract_tan_init(const MeshRenderData *mr, MeshBatchCache *cache, void *buf, void *UNUSED(tls_data))
unsigned int uint32_t
Definition: stdint.h:80
float co[3]
Definition: bmesh_class.h:87
CustomData vdata
Definition: bmesh_class.h:337
CustomData ldata
Definition: bmesh_class.h:337
DRW_MeshCDMask cd_used
size_t mesh_buffer_offset
eMRDataType data_type
ExtractInitSubdivFn * init_subdiv
size_t data_size
bool use_threading
ExtractInitFn * init
eMRExtractType extract_type
Definition: extract_mesh.hh:37
const float(* poly_normals)[3]
Definition: extract_mesh.hh:85
const MLoop * mloop
Definition: extract_mesh.hh:76
const float(* vert_normals)[3]
Definition: extract_mesh.hh:84
const MVert * mvert
Definition: extract_mesh.hh:74
float(* loop_normals)[3]
Definition: extract_mesh.hh:86
const MPoly * mpoly
Definition: extract_mesh.hh:77
MLoopTri * mlooptri
Definition: extract_mesh.hh:83
BMEditMesh * edit_bmesh
Definition: extract_mesh.hh:55
CustomData vdata
CustomData ldata