Blender V4.3
gpu_select_pick.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2017 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <cfloat>
12#include <cstdlib>
13#include <cstring>
14
15#include "GPU_debug.hh"
16#include "GPU_framebuffer.hh"
17#include "GPU_select.hh"
18#include "GPU_state.hh"
19
20#include "MEM_guardedalloc.h"
21
22#include "BLI_listbase.h"
23#include "BLI_rect.h"
24#include "BLI_utildefines.h"
25
26#include "gpu_select_private.hh"
27
28#include "BLI_strict_flags.h" /* Keep last. */
29
30// #define DEBUG_PRINT
31
32/* Alloc number for depths */
33#define ALLOC_DEPTHS 200
34
35/* Z-depth of cleared depth buffer */
36#define DEPTH_MAX 0xffffffff
37
38/* -------------------------------------------------------------------- */
53
55typedef uint depth_t;
56
62static void rect_subregion_stride_calc(const rcti *src, const rcti *dst, SubRectStride *r_sub)
63{
64 const int src_x = BLI_rcti_size_x(src);
65 // const int src_y = BLI_rcti_size_y(src);
66 const int dst_x = BLI_rcti_size_x(dst);
67 const int dst_y = BLI_rcti_size_y(dst);
68 const int x = dst->xmin - src->xmin;
69 const int y = dst->ymin - src->ymin;
70
71 BLI_assert(src->xmin <= dst->xmin && src->ymin <= dst->ymin && src->xmax >= dst->xmax &&
72 src->ymax >= dst->ymax);
73 BLI_assert(x >= 0 && y >= 0);
74
75 r_sub->start = uint((src_x * y) + x);
76 r_sub->span = uint(dst_x);
77 r_sub->span_len = uint(dst_y);
78 r_sub->skip = uint(src_x - dst_x);
79}
80
85BLI_INLINE bool depth_is_filled(const depth_t *prev, const depth_t *curr)
86{
87 return (*prev != *curr) && (*curr != DEPTH_MAX);
88}
89
92/* -------------------------------------------------------------------- */
105
107{
108 DepthBufCache *rect = static_cast<DepthBufCache *>(
109 MEM_mallocN(sizeof(DepthBufCache) + sizeof(depth_t) * rect_len, __func__));
110 rect->id = SELECT_ID_NONE;
111 return rect;
112}
113
114static bool depth_buf_rect_depth_any(const DepthBufCache *rect_depth, uint rect_len)
115{
116 const depth_t *curr = rect_depth->buf;
117 for (uint i = 0; i < rect_len; i++, curr++) {
118 if (*curr != DEPTH_MAX) {
119 return true;
120 }
121 }
122 return false;
123}
124
125static bool depth_buf_subrect_depth_any(const DepthBufCache *rect_depth,
126 const SubRectStride *sub_rect)
127{
128 const depth_t *curr = rect_depth->buf + sub_rect->start;
129 for (uint i = 0; i < sub_rect->span_len; i++) {
130 const depth_t *curr_end = curr + sub_rect->span;
131 for (; curr < curr_end; curr++, curr++) {
132 if (*curr != DEPTH_MAX) {
133 return true;
134 }
135 }
136 curr += sub_rect->skip;
137 }
138 return false;
139}
140
142 const DepthBufCache *rect_curr,
143 uint rect_len)
144{
145#if 0
146 return memcmp(rect_depth_a->buf, rect_depth_b->buf, rect_len * sizeof(depth_t)) != 0;
147#else
148 const depth_t *prev = rect_prev->buf;
149 const depth_t *curr = rect_curr->buf;
150 for (uint i = 0; i < rect_len; i++, curr++, prev++) {
151 if (depth_is_filled(prev, curr)) {
152 return true;
153 }
154 }
155 return false;
156#endif
157}
158
163 const DepthBufCache *rect_dst,
164 const SubRectStride *sub_rect)
165{
166 /* Same as #depth_buf_rect_depth_any_filled but different rectangle sizes. */
167 const depth_t *prev = rect_src->buf + sub_rect->start;
168 const depth_t *curr = rect_dst->buf + sub_rect->start;
169 for (uint i = 0; i < sub_rect->span_len; i++) {
170 const depth_t *curr_end = curr + sub_rect->span;
171 for (; curr < curr_end; prev++, curr++) {
172 if (depth_is_filled(prev, curr)) {
173 return true;
174 }
175 }
176 prev += sub_rect->skip;
177 curr += sub_rect->skip;
178 }
179 return false;
180}
181
184/* -------------------------------------------------------------------- */
194
195static int depth_id_cmp(const void *v1, const void *v2)
196{
197 const DepthID *d1 = static_cast<const DepthID *>(v1), *d2 = static_cast<const DepthID *>(v2);
198 if (d1->id < d2->id) {
199 return -1;
200 }
201 if (d1->id > d2->id) {
202 return 1;
203 }
204
205 return 0;
206}
207
208static int depth_cmp(const void *v1, const void *v2)
209{
210 const DepthID *d1 = static_cast<const DepthID *>(v1), *d2 = static_cast<const DepthID *>(v2);
211 if (d1->depth < d2->depth) {
212 return -1;
213 }
214 if (d1->depth > d2->depth) {
215 return 1;
216 }
217
218 return 0;
219}
220
223/* -------------------------------------------------------------------- */
293
295
297{
299
300#ifdef DEBUG_PRINT
301 printf("%s: mode=%d, use_cache=%d, is_cache=%d\n",
302 __func__,
303 int(mode),
304 ps->use_cache,
305 ps->is_cached);
306#endif
307
308 GPU_debug_group_begin("Selection Pick");
309
310 ps->buffer = buffer;
311 ps->mode = mode;
312
313 const uint rect_len = uint(BLI_rcti_size_x(input) * BLI_rcti_size_y(input));
314 ps->dst.clip_rect = *input;
315 ps->dst.rect_len = rect_len;
316
317 /* Avoids unnecessary GPU operations when cache is available and they are unnecessary. */
318 if (ps->is_cached == false) {
322
323 /* Disable writing to the frame-buffer. */
324 GPU_color_mask(false, false, false, false);
325
326 GPU_depth_mask(true);
327 /* Always use #GPU_DEPTH_LESS_EQUAL even though #GPU_SELECT_PICK_ALL always clears the buffer.
328 * This is because individual objects themselves might have sections that overlap and we need
329 * these to have the correct distance information. */
331
332 float viewport[4];
333 GPU_viewport_size_get_f(viewport);
334
335 ps->src.clip_rect = *input;
336 ps->src.rect_len = rect_len;
337
338 ps->gpu.clip_readpixels[0] = int(viewport[0]);
339 ps->gpu.clip_readpixels[1] = int(viewport[1]);
342
344
345 /* It's possible we don't want to clear depth buffer,
346 * so existing elements are masked by current z-buffer. */
347 GPU_clear_depth(1.0f);
348
349 /* scratch buffer (read new values here) */
350 ps->gpu.rect_depth_test = depth_buf_malloc(rect_len);
351 ps->gpu.rect_depth = depth_buf_malloc(rect_len);
352
353 /* Set initial 'far' value. */
354 for (uint i = 0; i < rect_len; i++) {
355 ps->gpu.rect_depth->buf[i] = DEPTH_MAX;
356 }
357
358 ps->gpu.is_init = false;
359 ps->gpu.prev_id = 0;
360 }
361 else {
362 /* Using cache `ps->is_cached == true`. */
363 /* `src.clip_rect` -> `dst.clip_rect`. */
365 BLI_assert(ps->gpu.rect_depth == nullptr);
366 BLI_assert(ps->gpu.rect_depth_test == nullptr);
367 }
368
369 if (mode == GPU_SELECT_PICK_ALL) {
370 ps->all.hits = static_cast<DepthID *>(
371 MEM_mallocN(sizeof(*ps->all.hits) * ALLOC_DEPTHS, __func__));
372 ps->all.hits_len = 0;
374 }
375 else {
376 /* Set to 0xff for #SELECT_ID_NONE. */
377 ps->nearest.rect_id = static_cast<uint *>(
378 MEM_mallocN(sizeof(uint) * ps->dst.rect_len, __func__));
379 memset(ps->nearest.rect_id, 0xff, sizeof(uint) * ps->dst.rect_len);
380 }
381}
382
387static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr)
388{
390 const uint id = rect_curr->id;
391 /* find the best depth for this pass and store in 'all.hits' */
392 depth_t depth_best = DEPTH_MAX;
393
394#define EVAL_TEST() \
395 if (depth_best > *curr) { \
396 depth_best = *curr; \
397 } \
398 ((void)0)
399
400 if (ps->is_cached == false) {
401 const depth_t *curr = rect_curr->buf;
402 BLI_assert(ps->src.rect_len == ps->dst.rect_len);
403 const uint rect_len = ps->src.rect_len;
404 for (uint i = 0; i < rect_len; i++, curr++) {
405 EVAL_TEST();
406 }
407 }
408 else {
409 /* Same as above but different rectangle sizes. */
410 const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start;
411 for (uint i = 0; i < ps->cache.sub_rect.span_len; i++) {
412 const depth_t *curr_end = curr + ps->cache.sub_rect.span;
413 for (; curr < curr_end; curr++) {
414 EVAL_TEST();
415 }
416 curr += ps->cache.sub_rect.skip;
417 }
418 }
419
420#undef EVAL_TEST
421
422 /* Ensure enough space. */
423 if (UNLIKELY(ps->all.hits_len == ps->all.hits_len_alloc)) {
425 ps->all.hits = static_cast<DepthID *>(
426 MEM_reallocN(ps->all.hits, ps->all.hits_len_alloc * sizeof(*ps->all.hits)));
427 }
428 DepthID *d = &ps->all.hits[ps->all.hits_len++];
429 d->id = id;
430 d->depth = depth_best;
431}
432
434 const DepthBufCache *rect_curr)
435{
437 const uint id = rect_curr->id;
438 /* Keep track each pixels ID in `nearest.rect_id`. */
439 if (id != SELECT_ID_NONE) {
440 uint *id_ptr = ps->nearest.rect_id;
441
442/* Check against DEPTH_MAX because XRAY will clear the buffer,
443 * so previously set values will become unset.
444 * In this case just leave those id's left as-is. */
445#define EVAL_TEST() \
446 if (depth_is_filled(prev, curr)) { \
447 *id_ptr = id; \
448 } \
449 ((void)0)
450
451 if (ps->is_cached == false) {
452 const depth_t *prev = rect_prev->buf;
453 const depth_t *curr = rect_curr->buf;
454 BLI_assert(ps->src.rect_len == ps->dst.rect_len);
455 const uint rect_len = ps->src.rect_len;
456 for (uint i = 0; i < rect_len; i++, curr++, prev++, id_ptr++) {
457 EVAL_TEST();
458 }
459 }
460 else {
461 /* same as above but different rect sizes */
462 const depth_t *prev = rect_prev->buf + ps->cache.sub_rect.start;
463 const depth_t *curr = rect_curr->buf + ps->cache.sub_rect.start;
464 for (uint i = 0; i < ps->cache.sub_rect.span_len; i++) {
465 const depth_t *curr_end = curr + ps->cache.sub_rect.span;
466 for (; curr < curr_end; prev++, curr++, id_ptr++) {
467 EVAL_TEST();
468 }
469 prev += ps->cache.sub_rect.skip;
470 curr += ps->cache.sub_rect.skip;
471 }
472 }
473
474#undef EVAL_TEST
475 }
476}
477
479{
481
482 if (ps->gpu.is_init) {
483 if (id == ps->gpu.prev_id && !end) {
484 /* No need to read if we are still drawing for the same id since
485 * all these depths will be merged / de-duplicated in the end. */
486 return true;
487 }
488
489 const uint rect_len = ps->src.rect_len;
490 GPUFrameBuffer *fb = GPU_framebuffer_active_get();
493 /* Perform initial check since most cases the array remains unchanged. */
494
495 bool do_pass = false;
497 if (depth_buf_rect_depth_any(ps->gpu.rect_depth_test, rect_len)) {
498 ps->gpu.rect_depth_test->id = ps->gpu.prev_id;
500 do_pass = true;
501 }
502 }
503 else {
505 ps->gpu.rect_depth_test->id = ps->gpu.prev_id;
507 do_pass = true;
508 }
509 }
510
511 if (do_pass) {
512 /* Store depth in cache */
513 if (ps->use_cache) {
516 }
517
518 std::swap(ps->gpu.rect_depth, ps->gpu.rect_depth_test);
519
521 /* (fclem) This is to be on the safe side. I don't know if this is required. */
522 bool prev_depth_mask = GPU_depth_mask_get();
523 /* we want new depths every time */
524 GPU_depth_mask(true);
525 GPU_clear_depth(1.0f);
526
527 GPU_depth_mask(prev_depth_mask);
528 }
529 }
530 }
531
532 ps->gpu.is_init = true;
533 ps->gpu.prev_id = id;
534
535 return true;
536}
537
539{
541
542#ifdef DEBUG_PRINT
543 printf("%s\n", __func__);
544#endif
545
546 if (ps->is_cached == false) {
547 if (ps->gpu.is_init) {
548 /* force finishing last pass */
550 }
554 }
555
557
558 /* Assign but never free directly since it may be in cache. */
559 DepthBufCache *rect_depth_final;
560
561 /* Store depth in cache */
562 if (ps->use_cache && !ps->is_cached) {
564 ps->gpu.rect_depth = nullptr;
565 rect_depth_final = static_cast<DepthBufCache *>(ps->cache.bufs.last);
566 }
567 else if (ps->is_cached) {
568 rect_depth_final = static_cast<DepthBufCache *>(ps->cache.bufs.last);
569 }
570 else {
571 /* Common case, no cache. */
572 rect_depth_final = ps->gpu.rect_depth;
573 }
574
575 DepthID *depth_data;
576 uint depth_data_len = 0;
577
579 depth_data = ps->all.hits;
580 depth_data_len = ps->all.hits_len;
581 /* Move ownership. */
582 ps->all.hits = nullptr;
583 ps->all.hits_len = 0;
584 ps->all.hits_len_alloc = 0;
585 }
586 else {
587 /* #GPU_SELECT_PICK_NEAREST */
588
589 /* Over allocate (unlikely we have as many depths as pixels). */
590 uint depth_data_len_first_pass = 0;
591 depth_data = static_cast<DepthID *>(
592 MEM_mallocN(ps->dst.rect_len * sizeof(*depth_data), __func__));
593
594 /* Partially de-duplicating copy,
595 * when contiguous ID's are found - update their closest depth.
596 * This isn't essential but means there is less data to sort. */
597
598#define EVAL_TEST(i_src, i_dst) \
599 { \
600 const uint id = ps->nearest.rect_id[i_dst]; \
601 if (id != SELECT_ID_NONE) { \
602 const depth_t depth = rect_depth_final->buf[i_src]; \
603 if (depth_last == nullptr || depth_last->id != id) { \
604 DepthID *d = &depth_data[depth_data_len_first_pass++]; \
605 d->id = id; \
606 d->depth = depth; \
607 } \
608 else if (depth_last->depth > depth) { \
609 depth_last->depth = depth; \
610 } \
611 } \
612 } \
613 ((void)0)
614
615 {
616 DepthID *depth_last = nullptr;
617 if (ps->is_cached == false) {
618 for (uint i = 0; i < ps->src.rect_len; i++) {
619 EVAL_TEST(i, i);
620 }
621 }
622 else {
623 /* Same as above but different rectangle sizes. */
624 uint i_src = ps->cache.sub_rect.start, i_dst = 0;
625 for (uint j = 0; j < ps->cache.sub_rect.span_len; j++) {
626 const uint i_src_end = i_src + ps->cache.sub_rect.span;
627 for (; i_src < i_src_end; i_src++, i_dst++) {
628 EVAL_TEST(i_src, i_dst);
629 }
630 i_src += ps->cache.sub_rect.skip;
631 }
632 }
633 }
634
635#undef EVAL_TEST
636
637 qsort(depth_data, depth_data_len_first_pass, sizeof(DepthID), depth_id_cmp);
638
639 /* Sort by ID's then keep the best depth for each ID. */
640 depth_data_len = 0;
641 {
642 DepthID *depth_last = nullptr;
643 for (uint i = 0; i < depth_data_len_first_pass; i++) {
644 if (depth_last == nullptr || depth_last->id != depth_data[i].id) {
645 depth_last = &depth_data[depth_data_len++];
646 *depth_last = depth_data[i];
647 }
648 else if (depth_last->depth > depth_data[i].depth) {
649 depth_last->depth = depth_data[i].depth;
650 }
651 }
652 }
653 }
654
655 /* Finally sort each unique (id, depth) pair by depth
656 * so the final hit-list is sorted by depth (nearest first). */
657 uint hits = 0;
658
659 /* Leave sorting up to the caller. */
660 qsort(depth_data, depth_data_len, sizeof(DepthID), depth_cmp);
661
663 for (uint i = 0; i < depth_data_len; i++) {
664#ifdef DEBUG_PRINT
665 printf(" hit: %u: depth %u\n", depth_data[i].id, depth_data[i].depth);
666#endif
667 GPUSelectResult hit_result{};
668 hit_result.id = depth_data[i].id;
669 hit_result.depth = depth_data[i].depth;
671 hits++;
672 }
673
674 MEM_freeN(depth_data);
675
678
680 /* 'hits' already freed as 'depth_data' */
681 }
682 else {
684 ps->nearest.rect_id = nullptr;
685 }
686
687 if (ps->use_cache) {
688 ps->is_cached = true;
689 }
690
691 return hits;
692}
693
696/* -------------------------------------------------------------------- */
703{
705#ifdef DEBUG_PRINT
706 printf("%s\n", __func__);
707#endif
708 g_pick_state.use_cache = true;
709 g_pick_state.is_cached = false;
710}
711
713{
714#ifdef DEBUG_PRINT
715 printf("%s: with %d buffers\n", __func__, BLI_listbase_count(&g_pick_state.cache.bufs));
716#endif
717 g_pick_state.use_cache = false;
718 g_pick_state.is_cached = false;
719
721}
722
727
729{
732#ifdef DEBUG_PRINT
733 printf("%s (building depth from cache)\n", __func__);
734#endif
735 LISTBASE_FOREACH (DepthBufCache *, rect_depth, &ps->cache.bufs) {
736 if (rect_depth->next != nullptr) {
737 /* We know the buffers differ, but this sub-region may not.
738 * Double check before adding an id-pass. */
740 if (depth_buf_subrect_depth_any(rect_depth->next, &ps->cache.sub_rect)) {
741 gpu_select_load_id_pass_all(rect_depth->next);
742 }
743 }
744 else {
745 if (depth_buf_subrect_depth_any_filled(rect_depth, rect_depth->next, &ps->cache.sub_rect))
746 {
747 gpu_select_load_id_pass_nearest(rect_depth, rect_depth->next);
748 }
749 }
750 }
751 }
752}
753
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_INLINE
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
unsigned int uint
#define UNPACK4(a)
#define UNLIKELY(x)
void GPU_debug_group_end()
Definition gpu_debug.cc:33
void GPU_debug_group_begin(const char *name)
Definition gpu_debug.cc:22
GPUFrameBuffer * GPU_framebuffer_active_get()
void GPU_framebuffer_read_depth(GPUFrameBuffer *framebuffer, int x, int y, int width, int height, eGPUDataFormat data_format, void *r_data)
void GPU_clear_depth(float depth)
eGPUSelectMode
Definition GPU_select.hh:18
@ GPU_SELECT_PICK_ALL
Definition GPU_select.hh:24
void GPU_write_mask(eGPUWriteMask mask)
Definition gpu_state.cc:93
eGPUWriteMask
Definition GPU_state.hh:16
void GPU_depth_mask(bool depth)
Definition gpu_state.cc:110
eGPUDepthTest GPU_depth_test_get()
Definition gpu_state.cc:239
void GPU_color_mask(bool r, bool g, bool b, bool a)
Definition gpu_state.cc:98
eGPUWriteMask GPU_write_mask_get()
Definition gpu_state.cc:227
void GPU_viewport(int x, int y, int width, int height)
Definition gpu_state.cc:194
eGPUDepthTest
Definition GPU_state.hh:107
@ GPU_DEPTH_LESS_EQUAL
Definition GPU_state.hh:111
void GPU_depth_test(eGPUDepthTest test)
Definition gpu_state.cc:68
void GPU_viewport_size_get_f(float coords[4])
Definition gpu_state.cc:262
bool GPU_depth_mask_get()
Definition gpu_state.cc:276
void GPU_scissor_get(int coords[4])
Definition gpu_state.cc:257
@ GPU_DATA_UINT
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
int64_t size() const
void append_unchecked(const T &value)
void reserve(const int64_t min_capacity)
#define printf
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
bool gpu_select_pick_load_id(uint id, bool end)
#define DEPTH_MAX
static DepthBufCache * depth_buf_malloc(uint rect_len)
static bool depth_buf_subrect_depth_any(const DepthBufCache *rect_depth, const SubRectStride *sub_rect)
#define ALLOC_DEPTHS
static int depth_cmp(const void *v1, const void *v2)
uint depth_t
uint gpu_select_pick_end()
void gpu_select_pick_cache_begin()
BLI_INLINE bool depth_is_filled(const depth_t *prev, const depth_t *curr)
static bool depth_buf_subrect_depth_any_filled(const DepthBufCache *rect_src, const DepthBufCache *rect_dst, const SubRectStride *sub_rect)
static void rect_subregion_stride_calc(const rcti *src, const rcti *dst, SubRectStride *r_sub)
#define EVAL_TEST()
bool gpu_select_pick_is_cached()
static int depth_id_cmp(const void *v1, const void *v2)
void gpu_select_pick_cache_load_id()
static GPUPickState g_pick_state
static void gpu_select_load_id_pass_all(const DepthBufCache *rect_curr)
static bool depth_buf_rect_depth_any_filled(const DepthBufCache *rect_prev, const DepthBufCache *rect_curr, uint rect_len)
static void gpu_select_load_id_pass_nearest(const DepthBufCache *rect_prev, const DepthBufCache *rect_curr)
void gpu_select_pick_begin(GPUSelectBuffer *buffer, const rcti *input, eGPUSelectMode mode)
void gpu_select_pick_cache_end()
static bool depth_buf_rect_depth_any(const DepthBufCache *rect_depth, uint rect_len)
#define SELECT_ID_NONE
BLI_INLINE float fb(float length, float L)
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
DepthBufCache * next
DepthBufCache * prev
depth_t depth
GPUSelectBuffer * buffer
DepthBufCache * rect_depth
struct GPUPickState::@634 cache
eGPUWriteMask write_mask
struct GPUPickState::@635::@637 all
eGPUDepthTest depth_test
SubRectStride sub_rect
struct GPUPickState::@632 gpu
DepthBufCache * rect_depth_test
struct GPUPickState::@633 src
eGPUSelectMode mode
struct GPUPickState::@633 dst
struct GPUPickState::@635::@638 nearest
GPUSelectStorage storage
Definition GPU_select.hh:46
unsigned int id
Definition GPU_select.hh:33
void * last
int ymin
int ymax
int xmin
int xmax