Blender V4.3
select_instance.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#pragma once
10
11#include "BKE_object_types.hh"
12
13#include "DRW_gpu_wrapper.hh"
14
15#include "GPU_select.hh"
16
17#include "../intern/gpu_select_private.hh"
18
19#include "draw_manager.hh"
20#include "draw_pass.hh"
21
23
24#include "select_defines.hh"
26
28
29// #define DEBUG_PRINT
30
31enum class SelectionType { DISABLED = 0, ENABLED = 1 };
32
33class ID {
34 private:
35 uint32_t value;
36
37 /* Add type safety to selection ID. Only the select types should provide them. */
38 ID(uint32_t value) : value(value){};
39
40 friend struct SelectBuf;
41 friend struct SelectMap;
42
43 public:
44 uint32_t get() const
45 {
46 return value;
47 }
48};
49
83
88struct SelectMap {
90
93#ifndef NDEBUG
96#endif
104 bool disable_depth_test = false;
105
107
108 /* TODO(fclem): The sub_object_id id should eventually become some enum or take a sub-object
109 * reference directly. This would isolate the selection logic to this class. */
110 [[nodiscard]] const ID select_id(const ObjectRef &ob_ref, uint sub_object_id = 0)
111 {
113 return {0};
114 }
115
116 if (sub_object_id == uint(-1)) {
117 /* WORKAROUND: Armature code set the sub_object_id to -1 when individual bones are not
118 * selectable (i.e. in object mode). */
119 sub_object_id = 0;
120 }
121
122 uint object_id = ob_ref.object->runtime->select_id;
123 uint id = select_id_map.append_and_get_index(object_id | sub_object_id);
124
125#ifdef DEBUG_PRINT
126 /* Print mapping from object name, select id and the mapping to internal select id.
127 * If something is wrong at this stage, it indicates an error in the caller code. */
128 printf("%s : %u | %u = %u -> %u\n",
129 ob_ref.object->id.name,
130 object_id,
131 sub_object_id,
132 object_id | sub_object_id,
133 id);
134#endif
135
136#ifndef NDEBUG
137 map_names.append(ob_ref.object->id.name);
138#endif
139 return {id};
140 }
141
142 /* TODO: refactor this method to select::ID::invalid(). */
143 /* Load an invalid index that will not write to the output (not selectable). */
144 [[nodiscard]] static const ID select_invalid_id()
145 {
146 return {uint32_t(-1)};
147 }
148
150 {
152 return;
153 }
154
155 switch (gpu_select_next_get_mode()) {
156 case GPU_SELECT_ALL:
158 disable_depth_test = true;
159 break;
160 /* Not sure if these 2 NEAREST are mapped to the right algorithm. */
166 disable_depth_test = true;
167 break;
171 disable_depth_test = true;
172 break;
173 }
174 info_buf.push_update();
175
177#ifndef NDEBUG
179#endif
180 }
181
184 {
186 return;
187 }
188
189 if (disable_depth_test) {
190 /* TODO: clipping state. */
191 pass.state_set(DRW_STATE_WRITE_COLOR);
192 }
193 pass.bind_ubo(SELECT_DATA, &info_buf);
194 pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf);
195 }
196
199 {
201 return;
202 }
203
204 pass.use_custom_ids = true;
205 if (disable_depth_test) {
206 /* TODO: clipping state. */
207 pass.state_set(DRW_STATE_WRITE_COLOR);
208 }
209 pass.bind_ubo(SELECT_DATA, &info_buf);
210 /* IMPORTANT: This binds a dummy buffer `in_select_buf` but it is not supposed to be used. */
211 pass.bind_ssbo(SELECT_ID_IN, &dummy_select_buf);
212 pass.bind_ssbo(SELECT_ID_OUT, &select_output_buf);
213 }
214
215 /* TODO: Deduplicate. */
218 {
220 return;
221 }
222
223 pass.use_custom_ids = true;
224 if (disable_depth_test) {
225 /* TODO: clipping state. */
227 }
229 /* IMPORTANT: This binds a dummy buffer `in_select_buf` but it is not supposed to be used. */
232 }
233
234 void end_sync()
235 {
237 return;
238 }
239
242 if (info_buf.mode == SelectType::SELECT_ALL) {
243 /* This mode uses atomicOr and store result as a bitmap. Clear to 0 (no selection). */
245 }
246 else {
247 /* Other modes use atomicMin. Clear to UINT_MAX. */
249 }
250 }
251
253 {
255 return;
256 }
257
260
261 Vector<GPUSelectResult> hit_results;
262
263 /* Convert raw data from GPU to #GPUSelectResult. */
264 switch (info_buf.mode) {
266 for (auto i : IndexRange(select_id_map.size())) {
267 if (((select_output_buf[i / 32] >> (i % 32)) & 1) != 0) {
268 GPUSelectResult hit_result{};
269 hit_result.id = select_id_map[i];
270 hit_result.depth = 0xFFFF;
271 hit_results.append(hit_result);
272 }
273 }
274 break;
275
278 for (auto i : IndexRange(select_id_map.size())) {
279 if (select_output_buf[i] != 0xFFFFFFFFu) {
280 /* NOTE: For `SELECT_PICK_NEAREST`, `select_output_buf` also contains the screen
281 * distance to cursor in the lowest bits. */
282 GPUSelectResult hit_result{};
283 hit_result.id = select_id_map[i];
284 hit_result.depth = select_output_buf[i];
285 hit_results.append(hit_result);
286 }
287 }
288 break;
289 }
290#ifdef DEBUG_PRINT
291 for (auto &hit : hit_results) {
292 /* Print hit results right out of the GPU selection buffer.
293 * If something is wrong at this stage, it indicates an error in the selection shaders. */
294 printf(" hit: %u: depth %u\n", hit_result.id, hit_result.depth);
295 }
296#endif
297
298 gpu_select_next_set_result(hit_results.data(), hit_results.size());
299 }
300};
301
302} // namespace blender::draw::select
MINLINE uint ceil_to_multiple_u(uint a, uint b)
unsigned int uint
struct ID ID
@ GPU_SELECT_NEAREST_SECOND_PASS
Definition GPU_select.hh:22
@ GPU_SELECT_NEAREST_FIRST_PASS
Definition GPU_select.hh:21
@ GPU_SELECT_PICK_ALL
Definition GPU_select.hh:24
@ GPU_SELECT_ALL
Definition GPU_select.hh:19
@ GPU_SELECT_PICK_NEAREST
Definition GPU_select.hh:25
void GPU_memory_barrier(eGPUBarrier barrier)
Definition gpu_state.cc:374
@ GPU_BARRIER_BUFFER_UPDATE
Definition GPU_state.hh:56
void GPU_storagebuf_clear(GPUStorageBuf *ssbo, uint32_t clear_value)
int64_t size() const
int64_t append_and_get_index(const T &value)
void append(const T &value)
void state_set(DRWState state, int clip_plane_count=0)
Definition draw_pass.hh:954
void bind_ubo(const char *name, GPUUniformBuf *buffer)
void bind_ssbo(const char *name, GPUStorageBuf *buffer)
#define printf
@ DRW_STATE_WRITE_COLOR
Definition draw_state.hh:30
void gpu_select_next_set_result(GPUSelectResult *hit_buf, uint hit_len)
eGPUSelectMode gpu_select_next_get_mode()
int gpu_select_next_get_pick_area_center()
VecBase< int32_t, 2 > int2
#define SELECT_DATA
#define SELECT_ID_IN
#define SELECT_ID_OUT
unsigned int uint32_t
Definition stdint.h:80
unsigned int id
Definition GPU_select.hh:33
char name[66]
Definition DNA_ID.h:425
ObjectRuntimeHandle * runtime
StorageVectorBuffer< uint32_t > select_buf
void select_bind(PassSimple::Sub &pass)
SelectBuf(const SelectionType selection_type)
void select_bind(PassMain &pass, PassMain::Sub &sub)
UniformBuffer< SelectInfoData > info_buf
void select_bind(PassSimple &pass)
StorageArrayBuffer< uint > select_output_buf
StorageArrayBuffer< uint, 4, true > dummy_select_buf
const ID select_id(const ObjectRef &ob_ref, uint sub_object_id=0)
SelectMap(const SelectionType selection_type)