Blender  V2.93
gpu_select.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2014 Blender Foundation.
17  * All rights reserved.
18  */
19 
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "GPU_select.h"
30 
31 #include "MEM_guardedalloc.h"
32 
33 #include "BLI_rect.h"
34 
35 #include "DNA_userdef_types.h"
36 
37 #include "BLI_utildefines.h"
38 
39 #include "gpu_select_private.h"
40 
41 /* Internal algorithm used */
42 enum {
49 };
50 
51 typedef struct GPUSelectState {
52  /* To ignore selection id calls when not initialized */
54  /* mode of operation */
55  char mode;
56  /* internal algorithm for selection */
57  char algorithm;
58  /* allow GPU_select_begin/end without drawing */
59  bool use_cache;
61 
63 
67 void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, int oldhits)
68 {
69  if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
70  /* In the case hits was '-1',
71  * don't start the second pass since it's not going to give useful results.
72  * As well as buffer overflow in 'gpu_select_query_load_id'. */
73  BLI_assert(oldhits != -1);
74  }
75 
77  g_select_state.mode = mode;
78 
81  }
82  else {
84  }
85 
86  switch (g_select_state.algorithm) {
87  case ALGO_GL_QUERY: {
88  g_select_state.use_cache = false;
89  gpu_select_query_begin((uint(*)[4])buffer, bufsize / 4, input, mode, oldhits);
90  break;
91  }
92  default: /* ALGO_GL_PICK */
93  {
94  gpu_select_pick_begin((uint(*)[4])buffer, bufsize / 4, input, mode);
95  break;
96  }
97  }
98 }
99 
109 {
110  /* if no selection mode active, ignore */
112  return true;
113  }
114 
115  switch (g_select_state.algorithm) {
116  case ALGO_GL_QUERY: {
117  return gpu_select_query_load_id(id);
118  }
119  default: /* ALGO_GL_PICK */
120  {
121  return gpu_select_pick_load_id(id, false);
122  }
123  }
124 }
125 
132 {
133  uint hits = 0;
134 
135  switch (g_select_state.algorithm) {
136  case ALGO_GL_QUERY: {
137  hits = gpu_select_query_end();
138  break;
139  }
140  default: /* ALGO_GL_PICK */
141  {
142  hits = gpu_select_pick_end();
143  break;
144  }
145  }
146 
148 
149  return hits;
150 }
151 
152 /* ----------------------------------------------------------------------------
153  * Caching
154  *
155  * Support multiple begin/end's as long as they are within the initial region.
156  * Currently only used by ALGO_GL_PICK.
157  */
158 
160 {
161  /* validate on GPU_select_begin, clear if not supported */
163  g_select_state.use_cache = true;
166  }
167 }
168 
170 {
174  }
175 }
176 
178 {
181  }
182  g_select_state.use_cache = false;
183 }
184 
186 {
188 }
189 
190 /* ----------------------------------------------------------------------------
191  * Utilities
192  */
193 
200 const uint *GPU_select_buffer_near(const uint *buffer, int hits)
201 {
202  const uint *buffer_near = NULL;
203  uint depth_min = (uint)-1;
204  for (int i = 0; i < hits; i++) {
205  if (buffer[1] < depth_min) {
206  BLI_assert(buffer[3] != -1);
207  depth_min = buffer[1];
208  buffer_near = buffer;
209  }
210  buffer += 4;
211  }
212  return buffer_near;
213 }
214 
216 {
217  uint *buffer_src = buffer;
218  uint *buffer_dst = buffer;
219  int hits_final = 0;
220  for (int i = 0; i < hits; i++) {
221  if (buffer_src[3] != select_id) {
222  if (buffer_dst != buffer_src) {
223  memcpy(buffer_dst, buffer_src, sizeof(int[4]));
224  }
225  buffer_dst += 4;
226  hits_final += 1;
227  }
228  buffer_src += 4;
229  }
230  return hits_final;
231 }
232 
233 /* Part of the solution copied from `rect_subregion_stride_calc`. */
234 void GPU_select_buffer_stride_realign(const rcti *src, const rcti *dst, uint *r_buf)
235 {
236  const int x = dst->xmin - src->xmin;
237  const int y = dst->ymin - src->ymin;
238 
239  BLI_assert(src->xmin <= dst->xmin && src->ymin <= dst->ymin && src->xmax >= dst->xmax &&
240  src->ymax >= dst->ymax);
241  BLI_assert(x >= 0 && y >= 0);
242 
243  const int src_x = BLI_rcti_size_x(src);
244  const int src_y = BLI_rcti_size_y(src);
245  const int dst_x = BLI_rcti_size_x(dst);
246  const int dst_y = BLI_rcti_size_y(dst);
247 
248  int last_px_id = src_x * (y + dst_y - 1) + (x + dst_x - 1);
249  memset(&r_buf[last_px_id + 1], 0, (src_x * src_y - (last_px_id + 1)) * sizeof(*r_buf));
250 
251  if (last_px_id < 0) {
252  /* Nothing to write. */
253  BLI_assert(last_px_id == -1);
254  return;
255  }
256 
257  int last_px_written = dst_x * dst_y - 1;
258  const int skip = src_x - dst_x;
259 
260  while (true) {
261  for (int i = dst_x; i--;) {
262  r_buf[last_px_id--] = r_buf[last_px_written--];
263  }
264  if (last_px_written < 0) {
265  break;
266  }
267  last_px_id -= skip;
268  memset(&r_buf[last_px_id + 1], 0, skip * sizeof(*r_buf));
269  }
270  memset(r_buf, 0, (last_px_id + 1) * sizeof(*r_buf));
271 }
#define BLI_assert(a)
Definition: BLI_assert.h:58
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition: BLI_rect.h:157
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition: BLI_rect.h:153
unsigned int uint
Definition: BLI_sys_types.h:83
#define ELEM(...)
_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 y
@ GPU_SELECT_NEAREST_SECOND_PASS
Definition: GPU_select.h:39
@ GPU_SELECT_PICK_ALL
Definition: GPU_select.h:41
@ GPU_SELECT_PICK_NEAREST
Definition: GPU_select.h:42
Read Guarded memory(de)allocation.
static GPUSelectState g_select_state
Definition: gpu_select.c:62
uint GPU_select_end(void)
Definition: gpu_select.c:131
@ ALGO_GL_QUERY
Definition: gpu_select.c:45
@ ALGO_GL_PICK
Definition: gpu_select.c:48
uint GPU_select_buffer_remove_by_id(uint *buffer, int hits, uint select_id)
Definition: gpu_select.c:215
void GPU_select_cache_begin(void)
Definition: gpu_select.c:159
void GPU_select_begin(uint *buffer, uint bufsize, const rcti *input, char mode, int oldhits)
Definition: gpu_select.c:67
bool GPU_select_is_cached(void)
Definition: gpu_select.c:185
bool GPU_select_load_id(uint id)
Definition: gpu_select.c:108
void GPU_select_cache_load_id(void)
Definition: gpu_select.c:169
void GPU_select_cache_end(void)
Definition: gpu_select.c:177
struct GPUSelectState GPUSelectState
const uint * GPU_select_buffer_near(const uint *buffer, int hits)
Definition: gpu_select.c:200
void GPU_select_buffer_stride_realign(const rcti *src, const rcti *dst, uint *r_buf)
Definition: gpu_select.c:234
bool gpu_select_pick_load_id(uint id, bool end)
bool gpu_select_pick_is_cached(void)
void gpu_select_pick_begin(uint(*buffer)[4], uint bufsize, const rcti *input, char mode)
void gpu_select_pick_cache_end(void)
uint gpu_select_pick_end(void)
void gpu_select_pick_cache_begin(void)
void gpu_select_pick_cache_load_id(void)
bool gpu_select_query_load_id(uint id)
void gpu_select_query_begin(uint(*buffer)[4], uint bufsize, const rcti *input, char mode, int oldhits)
uint gpu_select_query_end(void)
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
bool select_is_active
Definition: gpu_select.c:53
int ymin
Definition: DNA_vec_types.h:80
int ymax
Definition: DNA_vec_types.h:80
int xmin
Definition: DNA_vec_types.h:79
int xmax
Definition: DNA_vec_types.h:79