Blender  V3.3
draw_cache_extract_mesh.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2017 Blender Foundation. All rights reserved. */
3 
9 #include "MEM_guardedalloc.h"
10 
11 #include <optional>
12 
13 #include "atomic_ops.h"
14 
15 #include "DNA_mesh_types.h"
16 #include "DNA_scene_types.h"
17 
18 #include "BLI_array.hh"
19 #include "BLI_math_bits.h"
20 #include "BLI_task.h"
21 #include "BLI_vector.hh"
22 
23 #include "BKE_editmesh.h"
24 
25 #include "GPU_capabilities.h"
26 
27 #include "draw_cache_extract.hh"
28 #include "draw_cache_inline.h"
29 #include "draw_subdivision.h"
30 
32 
33 // #define DEBUG_TIME
34 
35 #ifdef DEBUG_TIME
36 # include "PIL_time_utildefines.h"
37 #endif
38 
39 namespace blender::draw {
40 
41 /* ---------------------------------------------------------------------- */
45 using TaskId = int;
46 using TaskLen = int;
47 
49  /* Extractor where this run data belongs to. */
51  /* During iteration the VBO/IBO that is being build. */
52  void *buffer = nullptr;
54 
56  {
57  }
58 
59 #ifdef WITH_CXX_GUARDEDALLOC
60  MEM_CXX_CLASS_ALLOC_FUNCS("DRAW:ExtractorRunData")
61 #endif
62 };
63 
64 class ExtractorRunDatas : public Vector<ExtractorRunData> {
65  public:
66  void filter_into(ExtractorRunDatas &result, eMRIterType iter_type, const bool is_mesh) const
67  {
68  for (const ExtractorRunData &data : *this) {
69  const MeshExtract *extractor = data.extractor;
70  if ((iter_type & MR_ITER_LOOPTRI) && *(&extractor->iter_looptri_bm + is_mesh)) {
71  result.append(data);
72  continue;
73  }
74  if ((iter_type & MR_ITER_POLY) && *(&extractor->iter_poly_bm + is_mesh)) {
75  result.append(data);
76  continue;
77  }
78  if ((iter_type & MR_ITER_LEDGE) && *(&extractor->iter_ledge_bm + is_mesh)) {
79  result.append(data);
80  continue;
81  }
82  if ((iter_type & MR_ITER_LVERT) && *(&extractor->iter_lvert_bm + is_mesh)) {
83  result.append(data);
84  continue;
85  }
86  }
87  }
88 
90  {
91  for (const ExtractorRunData &data : *this) {
92  const MeshExtract *extractor = data.extractor;
93  if (extractor->use_threading) {
94  result.append(extractor);
95  }
96  }
97  }
98 
99  eMRIterType iter_types() const
100  {
101  eMRIterType iter_type = static_cast<eMRIterType>(0);
102 
103  for (const ExtractorRunData &data : *this) {
104  const MeshExtract *extractor = data.extractor;
105  iter_type |= mesh_extract_iter_type(extractor);
106  }
107  return iter_type;
108  }
109 
111  {
112  const eMRIterType iter_type = iter_types();
113  uint bits = static_cast<uint>(iter_type);
114  return count_bits_i(bits);
115  }
116 
118  {
119  eMRDataType data_type = static_cast<eMRDataType>(0);
120  for (const ExtractorRunData &data : *this) {
121  const MeshExtract *extractor = data.extractor;
122  data_type |= extractor->data_type;
123  }
124  return data_type;
125  }
126 
128  {
129  size_t data_size = 0;
130  for (const ExtractorRunData &data : *this) {
131  const MeshExtract *extractor = data.extractor;
132  data_size += extractor->data_size;
133  }
134  return data_size;
135  }
136 
137 #ifdef WITH_CXX_GUARDEDALLOC
138  MEM_CXX_CLASS_ALLOC_FUNCS("DRAW:ExtractorRunDatas")
139 #endif
140 };
141 
144 /* ---------------------------------------------------------------------- */
149  const MeshRenderData *mr = nullptr;
150  MeshBatchCache *cache = nullptr;
153 
154  eMRIterType iter_type;
155  bool use_threading = false;
156 
161  const bool use_threading)
162  : mr(mr),
163  cache(cache),
167  {
169  };
170 
172 
174  {
175  delete extractors;
176  }
177 
178 #ifdef WITH_CXX_GUARDEDALLOC
179  MEM_CXX_CLASS_ALLOC_FUNCS("DRW:ExtractTaskData")
180 #endif
181 };
182 
183 static void extract_task_data_free(void *data)
184 {
185  ExtractTaskData *task_data = static_cast<ExtractTaskData *>(data);
186  delete task_data;
187 }
188 
191 /* ---------------------------------------------------------------------- */
196  MeshBatchCache *cache,
197  ExtractorRunDatas &extractors,
198  MeshBufferList *mbuflist,
199  void *data_stack)
200 {
201  uint32_t data_offset = 0;
202  for (ExtractorRunData &run_data : extractors) {
203  const MeshExtract *extractor = run_data.extractor;
204  run_data.buffer = mesh_extract_buffer_get(extractor, mbuflist);
205  run_data.data_offset = data_offset;
206  extractor->init(mr, cache, run_data.buffer, POINTER_OFFSET(data_stack, data_offset));
207  data_offset += (uint32_t)extractor->data_size;
208  }
209 }
210 
212  MeshBatchCache *cache,
213  const ExtractorRunDatas &extractors,
214  void *data_stack)
215 {
216  for (const ExtractorRunData &run_data : extractors) {
217  const MeshExtract *extractor = run_data.extractor;
218  if (extractor->finish) {
219  extractor->finish(
220  mr, cache, run_data.buffer, POINTER_OFFSET(data_stack, run_data.data_offset));
221  }
222  }
223 }
224 
227 /* ---------------------------------------------------------------------- */
233  const MeshRenderData *mr = nullptr;
234  const void *elems = nullptr;
235  const int *loose_elems = nullptr;
236 
237 #ifdef WITH_CXX_GUARDEDALLOC
238  MEM_CXX_CLASS_ALLOC_FUNCS("DRW:MeshRenderDataUpdateTaskData")
239 #endif
240 };
241 
242 static void extract_task_reduce(const void *__restrict userdata,
243  void *__restrict chunk_to,
244  void *__restrict chunk_from)
245 {
246  const ExtractorIterData *data = static_cast<const ExtractorIterData *>(userdata);
247  for (const ExtractorRunData &run_data : data->extractors) {
248  const MeshExtract *extractor = run_data.extractor;
249  if (extractor->task_reduce) {
250  extractor->task_reduce(POINTER_OFFSET(chunk_to, run_data.data_offset),
251  POINTER_OFFSET(chunk_from, run_data.data_offset));
252  }
253  }
254 }
255 
256 static void extract_range_iter_looptri_bm(void *__restrict userdata,
257  const int iter,
258  const TaskParallelTLS *__restrict tls)
259 {
260  const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
261  void *extract_data = tls->userdata_chunk;
262  const MeshRenderData *mr = data->mr;
263  BMLoop **elt = ((BMLoop * (*)[3]) data->elems)[iter];
264  for (const ExtractorRunData &run_data : data->extractors) {
265  run_data.extractor->iter_looptri_bm(
266  mr, elt, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
267  }
268 }
269 
270 static void extract_range_iter_looptri_mesh(void *__restrict userdata,
271  const int iter,
272  const TaskParallelTLS *__restrict tls)
273 {
274  void *extract_data = tls->userdata_chunk;
275 
276  const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
277  const MeshRenderData *mr = data->mr;
278  const MLoopTri *mlt = &((const MLoopTri *)data->elems)[iter];
279  for (const ExtractorRunData &run_data : data->extractors) {
280  run_data.extractor->iter_looptri_mesh(
281  mr, mlt, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
282  }
283 }
284 
285 static void extract_range_iter_poly_bm(void *__restrict userdata,
286  const int iter,
287  const TaskParallelTLS *__restrict tls)
288 {
289  void *extract_data = tls->userdata_chunk;
290 
291  const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
292  const MeshRenderData *mr = data->mr;
293  const BMFace *f = ((const BMFace **)data->elems)[iter];
294  for (const ExtractorRunData &run_data : data->extractors) {
295  run_data.extractor->iter_poly_bm(
296  mr, f, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
297  }
298 }
299 
300 static void extract_range_iter_poly_mesh(void *__restrict userdata,
301  const int iter,
302  const TaskParallelTLS *__restrict tls)
303 {
304  void *extract_data = tls->userdata_chunk;
305 
306  const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
307  const MeshRenderData *mr = data->mr;
308  const MPoly *mp = &((const MPoly *)data->elems)[iter];
309  for (const ExtractorRunData &run_data : data->extractors) {
310  run_data.extractor->iter_poly_mesh(
311  mr, mp, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
312  }
313 }
314 
315 static void extract_range_iter_ledge_bm(void *__restrict userdata,
316  const int iter,
317  const TaskParallelTLS *__restrict tls)
318 {
319  void *extract_data = tls->userdata_chunk;
320 
321  const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
322  const MeshRenderData *mr = data->mr;
323  const int ledge_index = data->loose_elems[iter];
324  const BMEdge *eed = ((const BMEdge **)data->elems)[ledge_index];
325  for (const ExtractorRunData &run_data : data->extractors) {
326  run_data.extractor->iter_ledge_bm(
327  mr, eed, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
328  }
329 }
330 
331 static void extract_range_iter_ledge_mesh(void *__restrict userdata,
332  const int iter,
333  const TaskParallelTLS *__restrict tls)
334 {
335  void *extract_data = tls->userdata_chunk;
336 
337  const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
338  const MeshRenderData *mr = data->mr;
339  const int ledge_index = data->loose_elems[iter];
340  const MEdge *med = &((const MEdge *)data->elems)[ledge_index];
341  for (const ExtractorRunData &run_data : data->extractors) {
342  run_data.extractor->iter_ledge_mesh(
343  mr, med, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
344  }
345 }
346 
347 static void extract_range_iter_lvert_bm(void *__restrict userdata,
348  const int iter,
349  const TaskParallelTLS *__restrict tls)
350 {
351  void *extract_data = tls->userdata_chunk;
352 
353  const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
354  const MeshRenderData *mr = data->mr;
355  const int lvert_index = data->loose_elems[iter];
356  const BMVert *eve = ((const BMVert **)data->elems)[lvert_index];
357  for (const ExtractorRunData &run_data : data->extractors) {
358  run_data.extractor->iter_lvert_bm(
359  mr, eve, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
360  }
361 }
362 
363 static void extract_range_iter_lvert_mesh(void *__restrict userdata,
364  const int iter,
365  const TaskParallelTLS *__restrict tls)
366 {
367  void *extract_data = tls->userdata_chunk;
368 
369  const ExtractorIterData *data = static_cast<ExtractorIterData *>(userdata);
370  const MeshRenderData *mr = data->mr;
371  const int lvert_index = data->loose_elems[iter];
372  const MVert *mv = &((const MVert *)data->elems)[lvert_index];
373  for (const ExtractorRunData &run_data : data->extractors) {
374  run_data.extractor->iter_lvert_mesh(
375  mr, mv, iter, POINTER_OFFSET(extract_data, run_data.data_offset));
376  }
377 }
378 
380  ExtractorRunDatas *extractors,
381  const eMRIterType iter_type,
382  bool is_mesh,
383  TaskParallelSettings *settings)
384 {
385  ExtractorIterData range_data;
386  range_data.mr = mr;
387 
389  int stop;
390  switch (iter_type) {
391  case MR_ITER_LOOPTRI:
392  range_data.elems = is_mesh ? mr->mlooptri : (void *)mr->edit_bmesh->looptris;
394  stop = mr->tri_len;
395  break;
396  case MR_ITER_POLY:
397  range_data.elems = is_mesh ? mr->mpoly : (void *)mr->bm->ftable;
399  stop = mr->poly_len;
400  break;
401  case MR_ITER_LEDGE:
402  range_data.loose_elems = mr->ledges;
403  range_data.elems = is_mesh ? mr->medge : (void *)mr->bm->etable;
405  stop = mr->edge_loose_len;
406  break;
407  case MR_ITER_LVERT:
408  range_data.loose_elems = mr->lverts;
409  range_data.elems = is_mesh ? mr->mvert : (void *)mr->bm->vtable;
411  stop = mr->vert_loose_len;
412  break;
413  default:
414  BLI_assert(false);
415  return;
416  }
417 
418  extractors->filter_into(range_data.extractors, iter_type, is_mesh);
419  BLI_task_parallel_range(0, stop, &range_data, func, settings);
420 }
421 
422 static void extract_task_range_run(void *__restrict taskdata)
423 {
424  ExtractTaskData *data = (ExtractTaskData *)taskdata;
425  const eMRIterType iter_type = data->iter_type;
426  const bool is_mesh = data->mr->extract_type != MR_EXTRACT_BMESH;
427 
428  size_t userdata_chunk_size = data->extractors->data_size_total();
429  void *userdata_chunk = MEM_callocN(userdata_chunk_size, __func__);
430 
431  TaskParallelSettings settings;
433  settings.use_threading = data->use_threading;
434  settings.userdata_chunk = userdata_chunk;
435  settings.userdata_chunk_size = userdata_chunk_size;
436  settings.func_reduce = extract_task_reduce;
438 
439  extract_init(data->mr, data->cache, *data->extractors, data->mbuflist, userdata_chunk);
440 
441  if (iter_type & MR_ITER_LOOPTRI) {
442  extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_LOOPTRI, is_mesh, &settings);
443  }
444  if (iter_type & MR_ITER_POLY) {
445  extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_POLY, is_mesh, &settings);
446  }
447  if (iter_type & MR_ITER_LEDGE) {
448  extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_LEDGE, is_mesh, &settings);
449  }
450  if (iter_type & MR_ITER_LVERT) {
451  extract_task_range_run_iter(data->mr, data->extractors, MR_ITER_LVERT, is_mesh, &settings);
452  }
453 
454  extract_finish(data->mr, data->cache, *data->extractors, userdata_chunk);
455  MEM_freeN(userdata_chunk);
456 }
457 
460 /* ---------------------------------------------------------------------- */
464 static struct TaskNode *extract_task_node_create(struct TaskGraph *task_graph,
465  const MeshRenderData *mr,
466  MeshBatchCache *cache,
467  ExtractorRunDatas *extractors,
468  MeshBufferList *mbuflist,
469  const bool use_threading)
470 {
471  ExtractTaskData *taskdata = new ExtractTaskData(mr, cache, extractors, mbuflist, use_threading);
472  struct TaskNode *task_node = BLI_task_graph_node_create(
473  task_graph,
475  taskdata,
477  return task_node;
478 }
479 
482 /* ---------------------------------------------------------------------- */
487  MeshRenderData *mr = nullptr;
488  MeshBufferCache *cache = nullptr;
489  eMRIterType iter_type;
491 
494  eMRIterType iter_type,
497  {
498  }
499 
501  {
503  }
504 
505 #ifdef WITH_CXX_GUARDEDALLOC
506  MEM_CXX_CLASS_ALLOC_FUNCS("DRW:MeshRenderDataUpdateTaskData")
507 #endif
508 };
509 
511 {
513  BLI_assert(taskdata);
514  delete taskdata;
515 }
516 
517 static void mesh_extract_render_data_node_exec(void *__restrict task_data)
518 {
519  MeshRenderDataUpdateTaskData *update_task_data = static_cast<MeshRenderDataUpdateTaskData *>(
520  task_data);
521  MeshRenderData *mr = update_task_data->mr;
522  const eMRIterType iter_type = update_task_data->iter_type;
523  const eMRDataType data_flag = update_task_data->data_flag;
524 
525  mesh_render_data_update_normals(mr, data_flag);
526  mesh_render_data_update_looptris(mr, iter_type, data_flag);
527  mesh_render_data_update_loose_geom(mr, update_task_data->cache, iter_type, data_flag);
528  mesh_render_data_update_polys_sorted(mr, update_task_data->cache, data_flag);
529 }
530 
531 static struct TaskNode *mesh_extract_render_data_node_create(struct TaskGraph *task_graph,
532  MeshRenderData *mr,
533  MeshBufferCache *cache,
534  const eMRIterType iter_type,
535  const eMRDataType data_flag)
536 {
538  mr, cache, iter_type, data_flag);
539 
540  struct TaskNode *task_node = BLI_task_graph_node_create(
541  task_graph,
543  task_data,
545  return task_node;
546 }
547 
550 /* ---------------------------------------------------------------------- */
555  MeshBatchCache *cache,
556  MeshBufferCache *mbc,
557  Object *object,
558  Mesh *me,
559 
560  const bool is_editmode,
561  const bool is_paint_mode,
562  const bool is_mode_active,
563  const float obmat[4][4],
564  const bool do_final,
565  const bool do_uvedit,
566  const Scene *scene,
567  const ToolSettings *ts,
568  const bool use_hide)
569 {
570  /* For each mesh where batches needs to be updated a sub-graph will be added to the task_graph.
571  * This sub-graph starts with an extract_render_data_node. This fills/converts the required
572  * data from Mesh.
573  *
574  * Small extractions and extractions that can't be multi-threaded are grouped in a single
575  * `extract_single_threaded_task_node`.
576  *
577  * Other extractions will create a node for each loop exceeding 8192 items. these nodes are
578  * linked to the `user_data_init_task_node`. the `user_data_init_task_node` prepares the
579  * user_data needed for the extraction based on the data extracted from the mesh.
580  * counters are used to check if the finalize of a task has to be called.
581  *
582  * Mesh extraction sub graph
583  *
584  * +----------------------+
585  * +-----> | extract_task1_loop_1 |
586  * | +----------------------+
587  * +------------------+ +----------------------+ +----------------------+
588  * | mesh_render_data | --> | | --> | extract_task1_loop_2 |
589  * +------------------+ | | +----------------------+
590  * | | | +----------------------+
591  * | | user_data_init | --> | extract_task2_loop_1 |
592  * v | | +----------------------+
593  * +------------------+ | | +----------------------+
594  * | single_threaded | | | --> | extract_task2_loop_2 |
595  * +------------------+ +----------------------+ +----------------------+
596  * | +----------------------+
597  * +-----> | extract_task2_loop_3 |
598  * +----------------------+
599  */
600  const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
602  const bool override_single_mat = mesh_render_mat_len_get(object, me) <= 1;
603 
604  /* Create an array containing all the extractors that needs to be executed. */
605  ExtractorRunDatas extractors;
606 
607  MeshBufferList *mbuflist = &mbc->buff;
608 
609 #define EXTRACT_ADD_REQUESTED(type, name) \
610  do { \
611  if (DRW_##type##_requested(mbuflist->type.name)) { \
612  const MeshExtract *extractor = mesh_extract_override_get( \
613  &extract_##name, do_hq_normals, override_single_mat); \
614  extractors.append(extractor); \
615  } \
616  } while (0)
617 
618  EXTRACT_ADD_REQUESTED(vbo, pos_nor);
619  EXTRACT_ADD_REQUESTED(vbo, lnor);
620  EXTRACT_ADD_REQUESTED(vbo, uv);
622  EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
623  EXTRACT_ADD_REQUESTED(vbo, orco);
624  EXTRACT_ADD_REQUESTED(vbo, edge_fac);
625  EXTRACT_ADD_REQUESTED(vbo, weights);
626  EXTRACT_ADD_REQUESTED(vbo, edit_data);
627  EXTRACT_ADD_REQUESTED(vbo, edituv_data);
628  EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_area);
629  EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
630  EXTRACT_ADD_REQUESTED(vbo, mesh_analysis);
631  EXTRACT_ADD_REQUESTED(vbo, fdots_pos);
632  EXTRACT_ADD_REQUESTED(vbo, fdots_nor);
633  EXTRACT_ADD_REQUESTED(vbo, fdots_uv);
634  EXTRACT_ADD_REQUESTED(vbo, fdots_edituv_data);
635  EXTRACT_ADD_REQUESTED(vbo, poly_idx);
636  EXTRACT_ADD_REQUESTED(vbo, edge_idx);
637  EXTRACT_ADD_REQUESTED(vbo, vert_idx);
638  EXTRACT_ADD_REQUESTED(vbo, fdot_idx);
639  EXTRACT_ADD_REQUESTED(vbo, skin_roots);
640  for (int i = 0; i < GPU_MAX_ATTR; i++) {
641  EXTRACT_ADD_REQUESTED(vbo, attr[i]);
642  }
643 
644  EXTRACT_ADD_REQUESTED(ibo, tris);
645  if (DRW_ibo_requested(mbuflist->ibo.lines_loose)) {
646  /* `ibo.lines_loose` require the `ibo.lines` buffer. */
647  if (mbuflist->ibo.lines == nullptr) {
648  DRW_ibo_request(nullptr, &mbuflist->ibo.lines);
649  }
650  const MeshExtract *extractor = DRW_ibo_requested(mbuflist->ibo.lines) ?
653  extractors.append(extractor);
654  }
655  else if (DRW_ibo_requested(mbuflist->ibo.lines)) {
656  const MeshExtract *extractor;
657  if (mbuflist->ibo.lines_loose != nullptr) {
658  /* Update `ibo.lines_loose` as it depends on `ibo.lines`. */
659  extractor = &extract_lines_with_lines_loose;
660  }
661  else {
662  extractor = &extract_lines;
663  }
664  extractors.append(extractor);
665  }
666  EXTRACT_ADD_REQUESTED(ibo, points);
667  EXTRACT_ADD_REQUESTED(ibo, fdots);
668  EXTRACT_ADD_REQUESTED(ibo, lines_paint_mask);
669  EXTRACT_ADD_REQUESTED(ibo, lines_adjacency);
670  EXTRACT_ADD_REQUESTED(ibo, edituv_tris);
671  EXTRACT_ADD_REQUESTED(ibo, edituv_lines);
672  EXTRACT_ADD_REQUESTED(ibo, edituv_points);
673  EXTRACT_ADD_REQUESTED(ibo, edituv_fdots);
674 
675 #undef EXTRACT_ADD_REQUESTED
676 
677  if (extractors.is_empty()) {
678  return;
679  }
680 
681 #ifdef DEBUG_TIME
682  double rdata_start = PIL_check_seconds_timer();
683 #endif
684 
686  object, me, is_editmode, is_paint_mode, is_mode_active, obmat, do_final, do_uvedit, ts);
687  mr->use_hide = use_hide;
688  mr->use_subsurf_fdots = mr->me && mr->me->runtime.subsurf_face_dot_tags != nullptr;
689  mr->use_final_mesh = do_final;
690 
691 #ifdef DEBUG_TIME
692  double rdata_end = PIL_check_seconds_timer();
693 #endif
694 
695  eMRIterType iter_type = extractors.iter_types();
696  eMRDataType data_flag = extractors.data_types();
697 
698  struct TaskNode *task_node_mesh_render_data = mesh_extract_render_data_node_create(
699  task_graph, mr, mbc, iter_type, data_flag);
700 
701  /* Simple heuristic. */
702  const bool use_thread = (mr->loop_len + mr->loop_loose_len) > MIN_RANGE_LEN;
703 
704  if (use_thread) {
705  /* First run the requested extractors that do not support asynchronous ranges. */
706  for (const ExtractorRunData &run_data : extractors) {
707  const MeshExtract *extractor = run_data.extractor;
708  if (!extractor->use_threading) {
709  ExtractorRunDatas *single_threaded_extractors = new ExtractorRunDatas();
710  single_threaded_extractors->append(extractor);
711  struct TaskNode *task_node = extract_task_node_create(
712  task_graph, mr, cache, single_threaded_extractors, mbuflist, false);
713 
714  BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
715  }
716  }
717 
718  /* Distribute the remaining extractors into ranges per core. */
719  ExtractorRunDatas *multi_threaded_extractors = new ExtractorRunDatas();
720  extractors.filter_threaded_extractors_into(*multi_threaded_extractors);
721  if (!multi_threaded_extractors->is_empty()) {
722  struct TaskNode *task_node = extract_task_node_create(
723  task_graph, mr, cache, multi_threaded_extractors, mbuflist, true);
724 
725  BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
726  }
727  else {
728  /* No tasks created freeing extractors list. */
729  delete multi_threaded_extractors;
730  }
731  }
732  else {
733  /* Run all requests on the same thread. */
734  ExtractorRunDatas *extractors_copy = new ExtractorRunDatas(extractors);
735  struct TaskNode *task_node = extract_task_node_create(
736  task_graph, mr, cache, extractors_copy, mbuflist, false);
737 
738  BLI_task_graph_edge_create(task_node_mesh_render_data, task_node);
739  }
740 
741  /* Trigger the sub-graph for this mesh. */
742  BLI_task_graph_node_push_work(task_node_mesh_render_data);
743 
744 #ifdef DEBUG_TIME
745  BLI_task_graph_work_and_wait(task_graph);
746  double end = PIL_check_seconds_timer();
747 
748  static double avg = 0;
749  static double avg_fps = 0;
750  static double avg_rdata = 0;
751  static double end_prev = 0;
752 
753  if (end_prev == 0) {
754  end_prev = end;
755  }
756 
757  avg = avg * 0.95 + (end - rdata_end) * 0.05;
758  avg_fps = avg_fps * 0.95 + (end - end_prev) * 0.05;
759  avg_rdata = avg_rdata * 0.95 + (rdata_end - rdata_start) * 0.05;
760 
761  printf(
762  "rdata %.0fms iter %.0fms (frame %.0fms)\n", avg_rdata * 1000, avg * 1000, avg_fps * 1000);
763 
764  end_prev = end;
765 #endif
766 }
767 
770 /* ---------------------------------------------------------------------- */
775  MeshBufferCache *mbc,
776  DRWSubdivCache *subdiv_cache,
777  MeshRenderData *mr)
778 {
779  /* Create an array containing all the extractors that needs to be executed. */
780  ExtractorRunDatas extractors;
781 
782  MeshBufferList *mbuflist = &mbc->buff;
783 
784 #define EXTRACT_ADD_REQUESTED(type, name) \
785  do { \
786  if (DRW_##type##_requested(mbuflist->type.name)) { \
787  const MeshExtract *extractor = &extract_##name; \
788  extractors.append(extractor); \
789  } \
790  } while (0)
791 
792  /* The order in which extractors are added to the list matters somewhat, as some buffers are
793  * reused when building others. */
794  EXTRACT_ADD_REQUESTED(ibo, tris);
795 
796  /* Orcos are extracted at the same time as positions. */
797  if (DRW_vbo_requested(mbuflist->vbo.pos_nor) || DRW_vbo_requested(mbuflist->vbo.orco)) {
798  extractors.append(&extract_pos_nor);
799  }
800 
801  EXTRACT_ADD_REQUESTED(vbo, lnor);
802  for (int i = 0; i < GPU_MAX_ATTR; i++) {
803  EXTRACT_ADD_REQUESTED(vbo, attr[i]);
804  }
805 
806  /* We use only one extractor for face dots, as the work is done in a single compute shader. */
807  if (DRW_vbo_requested(mbuflist->vbo.fdots_nor) || DRW_vbo_requested(mbuflist->vbo.fdots_pos) ||
808  DRW_ibo_requested(mbuflist->ibo.fdots)) {
809  extractors.append(&extract_fdots_pos);
810  }
811 
812  if (DRW_ibo_requested(mbuflist->ibo.lines_loose)) {
813  /* `ibo.lines_loose` require the `ibo.lines` buffer. */
814  if (mbuflist->ibo.lines == nullptr) {
815  DRW_ibo_request(nullptr, &mbuflist->ibo.lines);
816  }
817  const MeshExtract *extractor = DRW_ibo_requested(mbuflist->ibo.lines) ?
820  extractors.append(extractor);
821  }
822  else if (DRW_ibo_requested(mbuflist->ibo.lines)) {
823  const MeshExtract *extractor;
824  if (mbuflist->ibo.lines_loose != nullptr) {
825  /* Update `ibo.lines_loose` as it depends on `ibo.lines`. */
826  extractor = &extract_lines_with_lines_loose;
827  }
828  else {
829  extractor = &extract_lines;
830  }
831  extractors.append(extractor);
832  }
833  EXTRACT_ADD_REQUESTED(ibo, edituv_points);
834  EXTRACT_ADD_REQUESTED(ibo, edituv_tris);
835  EXTRACT_ADD_REQUESTED(ibo, edituv_lines);
836  EXTRACT_ADD_REQUESTED(vbo, vert_idx);
837  EXTRACT_ADD_REQUESTED(vbo, edge_idx);
838  EXTRACT_ADD_REQUESTED(vbo, poly_idx);
839  EXTRACT_ADD_REQUESTED(vbo, edge_fac);
840  EXTRACT_ADD_REQUESTED(ibo, points);
841  EXTRACT_ADD_REQUESTED(vbo, edit_data);
842  EXTRACT_ADD_REQUESTED(vbo, edituv_data);
843  /* Make sure UVs are computed before edituv stuffs. */
844  EXTRACT_ADD_REQUESTED(vbo, uv);
846  EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_area);
847  EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle);
848  EXTRACT_ADD_REQUESTED(ibo, lines_paint_mask);
849  EXTRACT_ADD_REQUESTED(ibo, lines_adjacency);
850  EXTRACT_ADD_REQUESTED(vbo, weights);
851  EXTRACT_ADD_REQUESTED(vbo, sculpt_data);
852 
853 #undef EXTRACT_ADD_REQUESTED
854 
855  if (extractors.is_empty()) {
856  return;
857  }
858 
861  mesh_render_data_update_loose_geom(mr, mbc, MR_ITER_LEDGE | MR_ITER_LVERT, MR_DATA_LOOSE_GEOM);
862  DRW_subdivide_loose_geom(subdiv_cache, mbc);
863 
864  void *data_stack = MEM_mallocN(extractors.data_size_total(), __func__);
865  uint32_t data_offset = 0;
866  for (const ExtractorRunData &run_data : extractors) {
867  const MeshExtract *extractor = run_data.extractor;
868  void *buffer = mesh_extract_buffer_get(extractor, mbuflist);
869  void *data = POINTER_OFFSET(data_stack, data_offset);
870 
871  extractor->init_subdiv(subdiv_cache, mr, cache, buffer, data);
872 
873  if (extractor->iter_subdiv_mesh || extractor->iter_subdiv_bm) {
874  int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index;
875  if (mr->extract_type == MR_EXTRACT_BMESH) {
876  for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) {
877  /* Multiply by 4 to have the start index of the quad's loop, as subdiv_loop_poly_index is
878  * based on the subdivision loops. */
879  const int poly_origindex = subdiv_loop_poly_index[i * 4];
880  const BMFace *efa = BM_face_at_index(mr->bm, poly_origindex);
881  extractor->iter_subdiv_bm(subdiv_cache, mr, data, i, efa);
882  }
883  }
884  else {
885  for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) {
886  /* Multiply by 4 to have the start index of the quad's loop, as subdiv_loop_poly_index is
887  * based on the subdivision loops. */
888  const int poly_origindex = subdiv_loop_poly_index[i * 4];
889  const MPoly *mp = &mr->mpoly[poly_origindex];
890  extractor->iter_subdiv_mesh(subdiv_cache, mr, data, i, mp);
891  }
892  }
893  }
894 
895  if (extractor->iter_loose_geom_subdiv) {
896  extractor->iter_loose_geom_subdiv(subdiv_cache, mr, buffer, data);
897  }
898 
899  if (extractor->finish_subdiv) {
900  extractor->finish_subdiv(subdiv_cache, mr, cache, buffer, data);
901  }
902  }
903  MEM_freeN(data_stack);
904 }
905 
908 } // namespace blender::draw
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
MINLINE int count_bits_i(unsigned int n)
unsigned int uint
Definition: BLI_sys_types.h:67
void(* TaskGraphNodeFreeFunction)(void *task_data)
Definition: BLI_task.h:388
void BLI_task_graph_edge_create(struct TaskNode *from_node, struct TaskNode *to_node)
Definition: task_graph.cc:139
bool BLI_task_graph_node_push_work(struct TaskNode *task_node)
Definition: task_graph.cc:127
void BLI_task_parallel_range(int start, int stop, void *userdata, TaskParallelRangeFunc func, const TaskParallelSettings *settings)
Definition: task_range.cc:94
void(* TaskParallelRangeFunc)(void *__restrict userdata, int iter, const TaskParallelTLS *__restrict tls)
Definition: BLI_task.h:145
struct TaskNode * BLI_task_graph_node_create(struct TaskGraph *task_graph, TaskGraphNodeRunFunction run, void *user_data, TaskGraphNodeFreeFunction free_func)
Definition: task_graph.cc:117
BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings)
Definition: BLI_task.h:293
void BLI_task_graph_work_and_wait(struct TaskGraph *task_graph)
Definition: task_graph.cc:108
#define POINTER_OFFSET(v, ofs)
@ SCE_PERF_HQ_NORMALS
bool GPU_use_hq_normals_workaround(void)
#define GPU_MAX_ATTR
Definition: GPU_shader.h:388
Read Guarded memory(de)allocation.
Utility defines for timing/benchmarks.
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:115
void append(const T &value)
Definition: BLI_vector.hh:433
bool is_empty() const
Definition: BLI_vector.hh:706
void filter_into(ExtractorRunDatas &result, eMRIterType iter_type, const bool is_mesh) const
void filter_threaded_extractors_into(ExtractorRunDatas &result)
Scene scene
SyclQueue void void * src
BLI_INLINE int mesh_render_mat_len_get(const Object *object, const Mesh *me)
@ MR_DATA_TAN_LOOP_NOR
@ MR_DATA_LOOPTRI
@ MR_DATA_LOOSE_GEOM
#define EXTRACT_ADD_REQUESTED(type, name)
void mesh_render_data_update_looptris(MeshRenderData *mr, const eMRIterType iter_type, const eMRDataType data_flag)
void mesh_render_data_free(MeshRenderData *mr)
MeshRenderData * mesh_render_data_create(Object *object, Mesh *me, const bool is_editmode, const bool is_paint_mode, const bool is_mode_active, const float obmat[4][4], const bool do_final, const bool do_uvedit, const ToolSettings *ts)
void mesh_render_data_update_loose_geom(MeshRenderData *mr, MeshBufferCache *cache, const eMRIterType iter_type, const eMRDataType data_flag)
void mesh_render_data_update_polys_sorted(MeshRenderData *mr, MeshBufferCache *cache, const eMRDataType data_flag)
void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_flag)
void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cache)
BLI_INLINE bool DRW_vbo_requested(GPUVertBuf *vbo)
BLI_INLINE void DRW_ibo_request(GPUBatch *batch, GPUIndexBuf **ibo)
BLI_INLINE bool DRW_ibo_requested(GPUIndexBuf *ibo)
eMRIterType mesh_extract_iter_type(const MeshExtract *ext)
Definition: extract_mesh.cc:30
void * mesh_extract_buffer_get(const MeshExtract *extractor, MeshBufferList *mbuflist)
Definition: extract_mesh.cc:20
Extraction of Mesh data into VBO to feed to GPU.
const MeshExtract extract_fdots_pos
const MeshExtract extract_lines_with_lines_loose
const MeshExtract extract_lines_loose_only
const MeshExtract extract_lines
@ MR_EXTRACT_BMESH
Definition: extract_mesh.hh:31
#define MIN_RANGE_LEN
Definition: extract_mesh.hh:24
const MeshExtract extract_pos_nor
ccl_global float * buffer
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
INLINE Rall1d< T, V, S > tan(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:327
void mesh_buffer_cache_create_requested(TaskGraph *task_graph, MeshBatchCache *cache, MeshBufferCache *mbc, Object *object, Mesh *me, bool is_editmode, bool is_paint_mode, bool is_mode_active, const float obmat[4][4], bool do_final, bool do_uvedit, const Scene *scene, const ToolSettings *ts, bool use_hide)
static void extract_range_iter_looptri_mesh(void *__restrict userdata, const int iter, const TaskParallelTLS *__restrict tls)
static void extract_range_iter_looptri_bm(void *__restrict userdata, const int iter, const TaskParallelTLS *__restrict tls)
static void extract_task_data_free(void *data)
BLI_INLINE void extract_init(const MeshRenderData *mr, MeshBatchCache *cache, ExtractorRunDatas &extractors, MeshBufferList *mbuflist, void *data_stack)
static struct TaskNode * extract_task_node_create(struct TaskGraph *task_graph, const MeshRenderData *mr, MeshBatchCache *cache, ExtractorRunDatas *extractors, MeshBufferList *mbuflist, const bool use_threading)
static void extract_range_iter_ledge_bm(void *__restrict userdata, const int iter, const TaskParallelTLS *__restrict tls)
static void extract_task_reduce(const void *__restrict userdata, void *__restrict chunk_to, void *__restrict chunk_from)
BLI_INLINE void extract_finish(const MeshRenderData *mr, MeshBatchCache *cache, const ExtractorRunDatas &extractors, void *data_stack)
static void extract_task_range_run(void *__restrict taskdata)
BLI_INLINE void extract_task_range_run_iter(const MeshRenderData *mr, ExtractorRunDatas *extractors, const eMRIterType iter_type, bool is_mesh, TaskParallelSettings *settings)
static struct TaskNode * mesh_extract_render_data_node_create(struct TaskGraph *task_graph, MeshRenderData *mr, MeshBufferCache *cache, const eMRIterType iter_type, const eMRDataType data_flag)
static void extract_range_iter_ledge_mesh(void *__restrict userdata, const int iter, const TaskParallelTLS *__restrict tls)
static void mesh_extract_render_data_node_exec(void *__restrict task_data)
static void extract_range_iter_poly_mesh(void *__restrict userdata, const int iter, const TaskParallelTLS *__restrict tls)
static void mesh_render_data_update_task_data_free(void *data)
static void extract_range_iter_lvert_bm(void *__restrict userdata, const int iter, const TaskParallelTLS *__restrict tls)
void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, MeshBufferCache *mbc, DRWSubdivCache *subdiv_cache, MeshRenderData *mr)
static void extract_range_iter_lvert_mesh(void *__restrict userdata, const int iter, const TaskParallelTLS *__restrict tls)
static void extract_range_iter_poly_bm(void *__restrict userdata, const int iter, const TaskParallelTLS *__restrict tls)
unsigned int uint32_t
Definition: stdint.h:80
struct BMLoop *(* looptris)[3]
Definition: BKE_editmesh.h:48
BMEdge ** etable
Definition: bmesh_class.h:322
BMVert ** vtable
Definition: bmesh_class.h:321
BMFace ** ftable
Definition: bmesh_class.h:323
int * subdiv_loop_poly_index
MeshBufferList buff
GPUIndexBuf * lines_loose
GPUIndexBuf * lines
GPUVertBuf * pos_nor
GPUIndexBuf * fdots
GPUVertBuf * fdots_nor
struct MeshBufferList::@272 vbo
struct MeshBufferList::@273 ibo
GPUVertBuf * fdots_pos
ExtractIterSubdivBMeshFn * iter_subdiv_bm
eMRDataType data_type
ExtractFinishFn * finish
ExtractLVertBMeshFn * iter_lvert_bm
ExtractLVertMeshFn * iter_lvert_mesh
ExtractLEdgeBMeshFn * iter_ledge_bm
ExtractIterSubdivMeshFn * iter_subdiv_mesh
ExtractInitSubdivFn * init_subdiv
size_t data_size
ExtractTriBMeshFn * iter_looptri_bm
ExtractPolyBMeshFn * iter_poly_bm
ExtractLEdgeMeshFn * iter_ledge_mesh
ExtractFinishSubdivFn * finish_subdiv
ExtractPolyMeshFn * iter_poly_mesh
ExtractLooseGeomSubdivFn * iter_loose_geom_subdiv
ExtractTaskReduceFn * task_reduce
ExtractTriMeshFn * iter_looptri_mesh
bool use_threading
ExtractInitFn * init
eMRExtractType extract_type
Definition: extract_mesh.hh:37
bool use_subsurf_fdots
Definition: extract_mesh.hh:47
const MVert * mvert
Definition: extract_mesh.hh:74
const MPoly * mpoly
Definition: extract_mesh.hh:77
MLoopTri * mlooptri
Definition: extract_mesh.hh:83
BMEditMesh * edit_bmesh
Definition: extract_mesh.hh:55
const MEdge * medge
Definition: extract_mesh.hh:75
uint32_t * subsurf_face_dot_tags
Mesh_Runtime runtime
struct RenderData r
void * task_data
Definition: task_graph.cc:43
TaskParallelReduceFunc func_reduce
Definition: BLI_task.h:181
size_t userdata_chunk_size
Definition: BLI_task.h:169
ExtractTaskData(const ExtractTaskData &src)=default
ExtractTaskData(const MeshRenderData *mr, MeshBatchCache *cache, ExtractorRunDatas *extractors, MeshBufferList *mbuflist, const bool use_threading)
ExtractorRunData(const MeshExtract *extractor)
MeshRenderDataUpdateTaskData(MeshRenderData *mr, MeshBufferCache *cache, eMRIterType iter_type, eMRDataType data_flag)
double PIL_check_seconds_timer(void)
Definition: time.c:64