Blender  V3.3
extract_mesh_vbo_edge_fac.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 "GPU_capabilities.h"
11 
12 #include "draw_subdivision.h"
13 #include "extract_mesh.hh"
14 
15 namespace blender::draw {
16 
17 /* ---------------------------------------------------------------------- */
25  /* Number of loop per edge. */
27 };
28 
29 static float loop_edge_factor_get(const float f_no[3],
30  const float v_co[3],
31  const float v_no[3],
32  const float v_next_co[3])
33 {
34  float enor[3], evec[3];
35  sub_v3_v3v3(evec, v_next_co, v_co);
36  cross_v3_v3v3(enor, v_no, evec);
37  normalize_v3(enor);
38  float d = fabsf(dot_v3v3(enor, f_no));
39  /* Re-scale to the slider range. */
40  d *= (1.0f / 0.065f);
41  CLAMP(d, 0.0f, 1.0f);
42  return d;
43 }
44 
45 static void extract_edge_fac_init(const MeshRenderData *mr,
46  MeshBatchCache *UNUSED(cache),
47  void *buf,
48  void *tls_data)
49 {
50  GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
51  static GPUVertFormat format = {0};
52  if (format.attr_len == 0) {
54  }
55 
58 
59  MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(tls_data);
60 
61  if (mr->extract_type == MR_EXTRACT_MESH) {
62  data->edge_loop_count = static_cast<uchar *>(
63  MEM_callocN(sizeof(uint32_t) * mr->edge_len, __func__));
64 
65  /* HACK(@fclem): Detecting the need for edge render.
66  * We could have a flag in the mesh instead or check the modifier stack. */
67  const MEdge *med = mr->medge;
68  for (int e_index = 0; e_index < mr->edge_len; e_index++, med++) {
69  if ((med->flag & ME_EDGERENDER) == 0) {
70  data->use_edge_render = true;
71  break;
72  }
73  }
74  }
75  else {
76  /* HACK to bypass non-manifold check in mesh_edge_fac_finish(). */
77  data->use_edge_render = true;
78  }
79 
80  data->vbo_data = static_cast<uchar *>(GPU_vertbuf_get_data(vbo));
81 }
82 
84  const BMFace *f,
85  const int UNUSED(f_index),
86  void *_data)
87 {
89  BMLoop *l_iter, *l_first;
90  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
91  do {
92  const int l_index = BM_elem_index_get(l_iter);
93 
94  if (BM_edge_is_manifold(l_iter->e)) {
95  float ratio = loop_edge_factor_get(bm_face_no_get(mr, f),
96  bm_vert_co_get(mr, l_iter->v),
97  bm_vert_no_get(mr, l_iter->v),
98  bm_vert_co_get(mr, l_iter->next->v));
99  data->vbo_data[l_index] = ratio * 253 + 1;
100  }
101  else {
102  data->vbo_data[l_index] = 255;
103  }
104  } while ((l_iter = l_iter->next) != l_first);
105 }
106 
108  const MPoly *mp,
109  const int mp_index,
110  void *_data)
111 {
112  MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data);
113 
114  const MLoop *mloop = mr->mloop;
115  const int ml_index_end = mp->loopstart + mp->totloop;
116  for (int ml_index = mp->loopstart; ml_index < ml_index_end; ml_index += 1) {
117  const MLoop *ml = &mloop[ml_index];
118 
119  if (data->use_edge_render) {
120  const MEdge *med = &mr->medge[ml->e];
121  data->vbo_data[ml_index] = (med->flag & ME_EDGERENDER) ? 255 : 0;
122  }
123  else {
124 
125  /* Count loop per edge to detect non-manifold. */
126  if (data->edge_loop_count[ml->e] < 3) {
127  data->edge_loop_count[ml->e]++;
128  }
129  if (data->edge_loop_count[ml->e] == 2) {
130  /* Manifold */
131  const int ml_index_last = mp->totloop + mp->loopstart - 1;
132  const int ml_index_other = (ml_index == ml_index_last) ? mp->loopstart : (ml_index + 1);
133  const MLoop *ml_next = &mr->mloop[ml_index_other];
134  const MVert *v1 = &mr->mvert[ml->v];
135  const MVert *v2 = &mr->mvert[ml_next->v];
136  float ratio = loop_edge_factor_get(
137  mr->poly_normals[mp_index], v1->co, mr->vert_normals[ml->v], v2->co);
138  data->vbo_data[ml_index] = ratio * 253 + 1;
139  }
140  else {
141  /* Non-manifold */
142  data->vbo_data[ml_index] = 255;
143  }
144  }
145  }
146 }
147 
149  const BMEdge *UNUSED(eed),
150  const int ledge_index,
151  void *_data)
152 {
153  MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data);
154  data->vbo_data[mr->loop_len + (ledge_index * 2) + 0] = 255;
155  data->vbo_data[mr->loop_len + (ledge_index * 2) + 1] = 255;
156 }
157 
159  const MEdge *UNUSED(med),
160  const int ledge_index,
161  void *_data)
162 {
163  MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data);
164 
165  data->vbo_data[mr->loop_len + ledge_index * 2 + 0] = 255;
166  data->vbo_data[mr->loop_len + ledge_index * 2 + 1] = 255;
167 }
168 
170  MeshBatchCache *UNUSED(cache),
171  void *buf,
172  void *_data)
173 {
174  GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf);
175  MeshExtract_EdgeFac_Data *data = static_cast<MeshExtract_EdgeFac_Data *>(_data);
176 
177  if (GPU_crappy_amd_driver()) {
178  /* Some AMD drivers strangely crash with VBO's with a one byte format.
179  * To workaround we reinitialize the VBO with another format and convert
180  * all bytes to floats. */
181  static GPUVertFormat format = {0};
182  if (format.attr_len == 0) {
184  }
185  /* We keep the data reference in data->vbo_data. */
186  data->vbo_data = static_cast<uchar *>(GPU_vertbuf_steal_data(vbo));
187  GPU_vertbuf_clear(vbo);
188 
189  int buf_len = mr->loop_len + mr->loop_loose_len;
191  GPU_vertbuf_data_alloc(vbo, buf_len);
192 
193  float *fdata = (float *)GPU_vertbuf_get_data(vbo);
194  for (int ml_index = 0; ml_index < buf_len; ml_index++, fdata++) {
195  *fdata = data->vbo_data[ml_index] / 255.0f;
196  }
197  /* Free old byte data. */
198  MEM_freeN(data->vbo_data);
199  }
200  MEM_SAFE_FREE(data->edge_loop_count);
201 }
202 
203 /* Different function than the one used for the non-subdivision case, as we directly take care of
204  * the buggy AMD driver case. */
206 {
207  static GPUVertFormat format = {0};
208  if (format.attr_len == 0) {
209  if (GPU_crappy_amd_driver()) {
211  }
212  else {
214  }
215  }
216  return &format;
217 }
218 
219 static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache,
220  const MeshRenderData *UNUSED(mr),
221  MeshBatchCache *cache,
222  void *buffer,
223  void *UNUSED(data))
224 {
225  const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
226  GPUVertBuf *edge_idx = cache->final.buff.vbo.edge_idx;
227  GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor;
228  GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
230  vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + loose_geom.loop_len);
231 
232  /* Create a temporary buffer for the edge original indices if it was not requested. */
233  const bool has_edge_idx = edge_idx != nullptr;
234  GPUVertBuf *loop_edge_idx = nullptr;
235  if (has_edge_idx) {
236  loop_edge_idx = edge_idx;
237  }
238  else {
239  loop_edge_idx = GPU_vertbuf_calloc();
241  loop_edge_idx,
242  static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)),
243  subdiv_cache->num_subdiv_loops,
244  0);
245  }
246 
247  draw_subdiv_build_edge_fac_buffer(subdiv_cache, pos_nor, loop_edge_idx, vbo);
248 
249  if (!has_edge_idx) {
250  GPU_vertbuf_discard(loop_edge_idx);
251  }
252 }
253 
254 static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache,
255  const MeshRenderData *UNUSED(mr),
256  void *buffer,
257  void *UNUSED(data))
258 {
259  const DRWSubdivLooseGeom &loose_geom = subdiv_cache->loose_geom;
260  if (loose_geom.edge_len == 0) {
261  return;
262  }
263 
264  GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer);
265 
266  /* Make sure buffer is active for sending loose data. */
267  GPU_vertbuf_use(vbo);
268 
269  uint offset = subdiv_cache->num_subdiv_loops;
270  for (int i = 0; i < loose_geom.edge_len; i++) {
271  if (GPU_crappy_amd_driver()) {
272  float loose_edge_fac[2] = {1.0f, 1.0f};
273  GPU_vertbuf_update_sub(vbo, offset * sizeof(float), sizeof(loose_edge_fac), loose_edge_fac);
274  }
275  else {
276  char loose_edge_fac[2] = {255, 255};
277  GPU_vertbuf_update_sub(vbo, offset * sizeof(char), sizeof(loose_edge_fac), loose_edge_fac);
278  }
279 
280  offset += 2;
281  }
282 }
283 
285 {
286  MeshExtract extractor = {nullptr};
287  extractor.init = extract_edge_fac_init;
294  extractor.finish = extract_edge_fac_finish;
295  extractor.data_type = MR_DATA_POLY_NOR;
296  extractor.data_size = sizeof(MeshExtract_EdgeFac_Data);
297  extractor.use_threading = false;
298  extractor.mesh_buffer_offset = offsetof(MeshBufferList, vbo.edge_fac);
299  return extractor;
300 }
301 
304 } // namespace blender::draw
305 
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void cross_v3_v3v3(float r[3], const float a[3], const float b[3])
unsigned char uchar
Definition: BLI_sys_types.h:70
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNUSED(x)
@ ME_EDGERENDER
bool GPU_crappy_amd_driver(void)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
void GPU_vertbuf_discard(GPUVertBuf *)
void * GPU_vertbuf_steal_data(GPUVertBuf *verts)
struct GPUVertBuf GPUVertBuf
void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data)
GPUVertBuf * GPU_vertbuf_calloc(void)
void GPU_vertbuf_clear(GPUVertBuf *verts)
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
#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_use(GPUVertBuf *)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_U8
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
@ MR_DATA_POLY_NOR
void draw_subdiv_init_origindex_buffer(GPUVertBuf *buffer, int32_t *vert_origindex, uint num_loops, uint loose_len)
void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache, GPUVertBuf *pos_nor, GPUVertBuf *edge_idx, GPUVertBuf *edge_fac)
Extraction of Mesh data into VBO to feed to GPU.
BLI_INLINE const float * bm_face_no_get(const MeshRenderData *mr, const BMFace *efa)
BLI_INLINE const float * bm_vert_co_get(const MeshRenderData *mr, const BMVert *eve)
@ MR_EXTRACT_MESH
Definition: extract_mesh.hh:33
BLI_INLINE const float * bm_vert_no_get(const MeshRenderData *mr, const BMVert *eve)
const MeshExtract extract_edge_fac
ccl_global float * buffer
ccl_gpu_kernel_postfix ccl_global float int int int int float bool int offset
format
Definition: logImageCore.h:38
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
#define fabsf(x)
Definition: metal/compat.h:219
constexpr MeshExtract create_extractor_edge_fac()
static void extract_edge_fac_iter_poly_bm(const MeshRenderData *mr, const BMFace *f, const int UNUSED(f_index), void *_data)
static void extract_edge_fac_init(const MeshRenderData *mr, MeshBatchCache *UNUSED(cache), void *buf, void *tls_data)
static void extract_edge_fac_iter_poly_mesh(const MeshRenderData *mr, const MPoly *mp, const int mp_index, void *_data)
static float loop_edge_factor_get(const float f_no[3], const float v_co[3], const float v_no[3], const float v_next_co[3])
static void extract_edge_fac_iter_ledge_mesh(const MeshRenderData *mr, const MEdge *UNUSED(med), const int ledge_index, void *_data)
static void extract_edge_fac_finish(const MeshRenderData *mr, MeshBatchCache *UNUSED(cache), void *buf, void *_data)
static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), MeshBatchCache *cache, void *buffer, void *UNUSED(data))
static void extract_edge_fac_iter_ledge_bm(const MeshRenderData *mr, const BMEdge *UNUSED(eed), const int ledge_index, void *_data)
static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, const MeshRenderData *UNUSED(mr), void *buffer, void *UNUSED(data))
static GPUVertFormat * get_subdiv_edge_fac_format()
unsigned int uint32_t
Definition: stdint.h:80
struct BMVert * v
Definition: bmesh_class.h:153
struct BMEdge * e
Definition: bmesh_class.h:164
struct BMLoop * next
Definition: bmesh_class.h:233
float co[3]
Definition: bmesh_class.h:87
struct GPUVertBuf * edges_orig_index
DRWSubdivLooseGeom loose_geom
unsigned int e
unsigned int v
MeshBufferCache final
MeshBufferList buff
GPUVertBuf * edge_idx
GPUVertBuf * pos_nor
GPUVertBuf * edge_fac
struct MeshBufferList::@272 vbo
size_t mesh_buffer_offset
eMRDataType data_type
ExtractFinishFn * finish
ExtractLEdgeBMeshFn * iter_ledge_bm
ExtractInitSubdivFn * init_subdiv
size_t data_size
ExtractPolyBMeshFn * iter_poly_bm
ExtractLEdgeMeshFn * iter_ledge_mesh
ExtractPolyMeshFn * iter_poly_mesh
ExtractLooseGeomSubdivFn * iter_loose_geom_subdiv
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
const MEdge * medge
Definition: extract_mesh.hh:75