Blender  V3.3
draw_cache_impl_volume.c
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 
10 #include <string.h>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "BLI_listbase.h"
15 #include "BLI_math_base.h"
16 #include "BLI_math_vector.h"
17 #include "BLI_utildefines.h"
18 
19 #include "DNA_object_types.h"
20 #include "DNA_volume_types.h"
21 
22 #include "BKE_global.h"
23 #include "BKE_volume.h"
24 #include "BKE_volume_render.h"
25 
26 #include "GPU_batch.h"
27 #include "GPU_capabilities.h"
28 #include "GPU_texture.h"
29 
30 #include "DEG_depsgraph_query.h"
31 
32 #include "DRW_render.h"
33 
34 #include "draw_cache.h" /* own include */
35 #include "draw_cache_impl.h" /* own include */
36 
37 static void volume_batch_cache_clear(Volume *volume);
38 
39 /* ---------------------------------------------------------------------- */
40 /* Volume GPUBatch Cache */
41 
42 typedef struct VolumeBatchCache {
43  /* 3D textures */
45 
46  /* Wireframe */
47  struct {
51 
52  /* Surface for selection */
54 
55  /* settings to determine if cache is invalid */
56  bool is_dirty;
58 
59 /* GPUBatch cache management. */
60 
61 static bool volume_batch_cache_valid(Volume *volume)
62 {
63  VolumeBatchCache *cache = volume->batch_cache;
64  return (cache && cache->is_dirty == false);
65 }
66 
67 static void volume_batch_cache_init(Volume *volume)
68 {
69  VolumeBatchCache *cache = volume->batch_cache;
70 
71  if (!cache) {
72  cache = volume->batch_cache = MEM_callocN(sizeof(*cache), __func__);
73  }
74  else {
75  memset(cache, 0, sizeof(*cache));
76  }
77 
78  cache->is_dirty = false;
79 }
80 
82 {
83  if (!volume_batch_cache_valid(volume)) {
86  }
87 }
88 
90 {
92  return volume->batch_cache;
93 }
94 
96 {
97  VolumeBatchCache *cache = volume->batch_cache;
98  if (cache == NULL) {
99  return;
100  }
101  switch (mode) {
103  cache->is_dirty = true;
104  break;
105  default:
106  BLI_assert(0);
107  }
108 }
109 
110 static void volume_batch_cache_clear(Volume *volume)
111 {
112  VolumeBatchCache *cache = volume->batch_cache;
113  if (!cache) {
114  return;
115  }
116 
117  LISTBASE_FOREACH (DRWVolumeGrid *, grid, &cache->grids) {
118  MEM_SAFE_FREE(grid->name);
119  DRW_TEXTURE_FREE_SAFE(grid->texture);
120  }
121  BLI_freelistN(&cache->grids);
122 
126 }
127 
129 {
130  volume_batch_cache_clear(volume);
131  MEM_SAFE_FREE(volume->batch_cache);
132 }
133 typedef struct VolumeWireframeUserData {
137 
139  void *userdata, const float (*verts)[3], const int (*edges)[2], int totvert, int totedge)
140 {
141  VolumeWireframeUserData *data = userdata;
142  Scene *scene = data->scene;
143  Volume *volume = data->volume;
144  VolumeBatchCache *cache = volume->batch_cache;
145  const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
147 
148  /* Create vertex buffer. */
149  static GPUVertFormat format = {0};
150  static GPUVertFormat format_hq = {0};
151  static struct {
152  uint pos_id, nor_id;
153  uint pos_hq_id, nor_hq_id;
154  } attr_id;
155 
156  if (format.attr_len == 0) {
160  attr_id.pos_id = GPU_vertformat_attr_add(&format_hq, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
162  &format_hq, "nor", GPU_COMP_I16, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
163  }
164 
165  static float normal[3] = {1.0f, 0.0f, 0.0f};
166  GPUNormal packed_normal;
167  GPU_normal_convert_v3(&packed_normal, normal, do_hq_normals);
168  uint pos_id = do_hq_normals ? attr_id.pos_hq_id : attr_id.pos_id;
169  uint nor_id = do_hq_normals ? attr_id.nor_hq_id : attr_id.nor_id;
170 
171  cache->face_wire.pos_nor_in_order = GPU_vertbuf_create_with_format(do_hq_normals ? &format_hq :
172  &format);
175  GPU_vertbuf_attr_fill_stride(cache->face_wire.pos_nor_in_order, nor_id, 0, &packed_normal);
176 
177  /* Create wiredata. */
178  GPUVertBuf *vbo_wiredata = GPU_vertbuf_calloc();
179  DRW_vertbuf_create_wiredata(vbo_wiredata, totvert);
180 
182  /* Create batch. */
185  }
186  else {
187  /* Create edge index buffer. */
188  GPUIndexBufBuilder elb;
189  GPU_indexbuf_init(&elb, GPU_PRIM_LINES, totedge, totvert);
190  for (int i = 0; i < totedge; i++) {
191  GPU_indexbuf_add_line_verts(&elb, edges[i][0], edges[i][1]);
192  }
193  GPUIndexBuf *ibo = GPU_indexbuf_build(&elb);
194 
195  /* Create batch. */
198  }
199 
200  GPU_batch_vertbuf_add_ex(cache->face_wire.batch, vbo_wiredata, true);
201 }
202 
204 {
206  return NULL;
207  }
208 
209  VolumeBatchCache *cache = volume_batch_cache_get(volume);
210 
211  if (cache->face_wire.batch == NULL) {
212  const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume);
213  if (volume_grid == NULL) {
214  return NULL;
215  }
216 
217  /* Create wireframe from OpenVDB tree. */
218  const DRWContextState *draw_ctx = DRW_context_state_get();
219  VolumeWireframeUserData userdata;
220  userdata.volume = volume;
221  userdata.scene = draw_ctx->scene;
222  BKE_volume_grid_wireframe(volume, volume_grid, drw_volume_wireframe_cb, &userdata);
223  }
224 
225  return cache->face_wire.batch;
226 }
227 
229  void *userdata, float (*verts)[3], int (*tris)[3], int totvert, int tottris)
230 {
231  Volume *volume = userdata;
232  VolumeBatchCache *cache = volume->batch_cache;
233 
234  static GPUVertFormat format = {0};
235  static uint pos_id;
236  if (format.attr_len == 0) {
238  }
239 
240  /* Create vertex buffer. */
242  GPU_vertbuf_data_alloc(vbo_surface, totvert);
243  GPU_vertbuf_attr_fill(vbo_surface, pos_id, verts);
244 
245  /* Create index buffer. */
246  GPUIndexBufBuilder elb;
247  GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottris, totvert);
248  for (int i = 0; i < tottris; i++) {
249  GPU_indexbuf_add_tri_verts(&elb, UNPACK3(tris[i]));
250  }
251  GPUIndexBuf *ibo_surface = GPU_indexbuf_build(&elb);
252 
254  GPU_PRIM_TRIS, vbo_surface, ibo_surface, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
255 }
256 
258 {
259  VolumeBatchCache *cache = volume_batch_cache_get(volume);
260  if (cache->selection_surface == NULL) {
261  const VolumeGrid *volume_grid = BKE_volume_grid_active_get_for_read(volume);
262  if (volume_grid == NULL) {
263  return NULL;
264  }
266  volume, volume_grid, drw_volume_selection_surface_cb, volume);
267  }
268  return cache->selection_surface;
269 }
270 
272  const VolumeGrid *grid,
273  VolumeBatchCache *cache)
274 {
275  const char *name = BKE_volume_grid_name(grid);
276 
277  /* Return cached grid. */
278  DRWVolumeGrid *cache_grid;
279  for (cache_grid = cache->grids.first; cache_grid; cache_grid = cache_grid->next) {
280  if (STREQ(cache_grid->name, name)) {
281  return cache_grid;
282  }
283  }
284 
285  /* Allocate new grid. */
286  cache_grid = MEM_callocN(sizeof(DRWVolumeGrid), __func__);
287  cache_grid->name = BLI_strdup(name);
288  BLI_addtail(&cache->grids, cache_grid);
289 
290  /* TODO: can we load this earlier, avoid accessing the global and take
291  * advantage of dependency graph multi-threading? */
292  BKE_volume_load(volume, G.main);
293 
294  /* Test if we support textures with the number of channels. */
295  size_t channels = BKE_volume_grid_channels(grid);
296  if (!ELEM(channels, 1, 3)) {
297  return cache_grid;
298  }
299 
300  /* Remember if grid was loaded. If it was not, we want to unload it after the GPUTexture has been
301  * created. */
302  const bool was_loaded = BKE_volume_grid_is_loaded(grid);
303 
304  DenseFloatVolumeGrid dense_grid;
305  if (BKE_volume_grid_dense_floats(volume, grid, &dense_grid)) {
306  copy_m4_m4(cache_grid->texture_to_object, dense_grid.texture_to_object);
307  invert_m4_m4(cache_grid->object_to_texture, dense_grid.texture_to_object);
308 
309  /* Create GPU texture. */
311  cache_grid->texture = GPU_texture_create_3d("volume_grid",
312  UNPACK3(dense_grid.resolution),
313  1,
314  format,
316  dense_grid.voxels);
317  /* The texture can be null if the resolution along one axis is larger than
318  * GL_MAX_3D_TEXTURE_SIZE. */
319  if (cache_grid->texture != NULL) {
320  GPU_texture_swizzle_set(cache_grid->texture, (channels == 3) ? "rgb1" : "rrr1");
321  GPU_texture_wrap_mode(cache_grid->texture, false, false);
323  }
324  else {
325  MEM_freeN(dense_grid.voxels);
326  printf("Error: Could not allocate 3D texture for volume.\n");
327  }
328  }
329 
330  /* Free grid from memory if it wasn't previously loaded. */
331  if (!was_loaded) {
332  BKE_volume_grid_unload(volume, grid);
333  }
334 
335  return cache_grid;
336 }
337 
339 {
340  VolumeBatchCache *cache = volume_batch_cache_get(volume);
341  DRWVolumeGrid *grid = volume_grid_cache_get(volume, volume_grid, cache);
342  return (grid->texture != NULL) ? grid : NULL;
343 }
344 
346 {
347  return max_ii(1, volume->totcol);
348 }
Volume data-block.
int BKE_volume_grid_channels(const struct VolumeGrid *grid)
void BKE_volume_grid_unload(const struct Volume *volume, const struct VolumeGrid *grid)
bool BKE_volume_grid_is_loaded(const struct VolumeGrid *grid)
const char * BKE_volume_grid_name(const struct VolumeGrid *grid)
@ BKE_VOLUME_BATCH_DIRTY_ALL
Definition: BKE_volume.h:50
const VolumeGrid * BKE_volume_grid_active_get_for_read(const struct Volume *volume)
bool BKE_volume_load(const struct Volume *volume, const struct Main *bmain)
Volume data-block rendering and viewport drawing utilities.
void BKE_volume_dense_float_grid_clear(DenseFloatVolumeGrid *dense_grid)
bool BKE_volume_grid_dense_floats(const struct Volume *volume, const struct VolumeGrid *volume_grid, DenseFloatVolumeGrid *r_dense_grid)
void BKE_volume_grid_wireframe(const struct Volume *volume, const struct VolumeGrid *volume_grid, BKE_volume_wireframe_cb cb, void *cb_userdata)
void BKE_volume_grid_selection_surface(const struct Volume *volume, const struct VolumeGrid *volume_grid, BKE_volume_selection_surface_cb cb, void *cb_userdata)
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
MINLINE int max_ii(int a, int b)
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL() ATTR_MALLOC
Definition: string.c:42
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNPACK3(a)
#define ELEM(...)
#define STREQ(a, b)
Object is a sort of wrapper for general info.
@ SCE_PERF_HQ_NORMALS
@ VOLUME_WIREFRAME_NONE
@ VOLUME_WIREFRAME_POINTS
#define DRW_TEXTURE_FREE_SAFE(tex)
Definition: DRW_render.h:183
GPUBatch
Definition: GPU_batch.h:78
#define GPU_batch_create(prim, verts, elem)
Definition: GPU_batch.h:95
int GPU_batch_vertbuf_add_ex(GPUBatch *, GPUVertBuf *, bool own_vbo)
Definition: gpu_batch.cc:171
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition: GPU_batch.h:216
GPUBatch * GPU_batch_create_ex(GPUPrimType prim, GPUVertBuf *vert, GPUIndexBuf *elem, eGPUBatchFlag owns_flag)
Definition: gpu_batch.cc:43
@ GPU_BATCH_OWNS_INDEX
Definition: GPU_batch.h:39
@ GPU_BATCH_OWNS_VBO
Definition: GPU_batch.h:30
bool GPU_use_hq_normals_workaround(void)
struct GPUIndexBuf GPUIndexBuf
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
GPUIndexBuf * GPU_indexbuf_build(GPUIndexBufBuilder *)
void GPU_indexbuf_add_line_verts(GPUIndexBufBuilder *, uint v1, uint v2)
void GPU_indexbuf_add_tri_verts(GPUIndexBufBuilder *, uint v1, uint v2, uint v3)
@ GPU_PRIM_LINES
Definition: GPU_primitive.h:20
@ GPU_PRIM_POINTS
Definition: GPU_primitive.h:19
@ GPU_PRIM_TRIS
Definition: GPU_primitive.h:21
void GPU_texture_swizzle_set(GPUTexture *tex, const char swizzle[4])
Definition: gpu_texture.cc:553
void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat, bool use_clamp)
Definition: gpu_texture.cc:546
@ GPU_DATA_FLOAT
Definition: GPU_texture.h:171
eGPUTextureFormat
Definition: GPU_texture.h:83
@ GPU_R16F
Definition: GPU_texture.h:113
@ GPU_RGB16F
Definition: GPU_texture.h:127
GPUTexture * GPU_texture_create_3d(const char *name, int w, int h, int d, int mip_len, eGPUTextureFormat texture_format, eGPUDataFormat data_format, const void *data)
Definition: gpu_texture.cc:309
#define GPU_vertbuf_create_with_format(format)
struct GPUVertBuf GPUVertBuf
GPUVertBuf * GPU_vertbuf_calloc(void)
void GPU_vertbuf_data_alloc(GPUVertBuf *, uint v_len)
void GPU_vertbuf_attr_fill_stride(GPUVertBuf *, uint a_idx, uint stride, const void *data)
#define GPU_VERTBUF_DISCARD_SAFE(verts)
void GPU_vertbuf_attr_fill(GPUVertBuf *, uint a_idx, const void *data)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
BLI_INLINE void GPU_normal_convert_v3(GPUNormal *gpu_normal, const float data[3], const bool do_hq_normals)
@ GPU_COMP_I10
@ GPU_COMP_F32
@ GPU_COMP_I16
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 a value between a minimum and a maximum Vector Perform vector math operation Invert a producing a negative Combine Generate a color from its and blue channels(Deprecated)") DefNode(ShaderNode
Scene scene
void DRW_vertbuf_create_wiredata(struct GPUVertBuf *vbo, int vert_len)
void DRW_volume_batch_cache_free(Volume *volume)
static DRWVolumeGrid * volume_grid_cache_get(const Volume *volume, const VolumeGrid *grid, VolumeBatchCache *cache)
void DRW_volume_batch_cache_dirty_tag(Volume *volume, int mode)
static void drw_volume_selection_surface_cb(void *userdata, float(*verts)[3], int(*tris)[3], int totvert, int tottris)
DRWVolumeGrid * DRW_volume_batch_cache_get_grid(Volume *volume, const VolumeGrid *volume_grid)
static void volume_batch_cache_init(Volume *volume)
struct VolumeBatchCache VolumeBatchCache
GPUBatch * DRW_volume_batch_cache_get_selection_surface(Volume *volume)
static VolumeBatchCache * volume_batch_cache_get(Volume *volume)
static void volume_batch_cache_clear(Volume *volume)
static bool volume_batch_cache_valid(Volume *volume)
static void drw_volume_wireframe_cb(void *userdata, const float(*verts)[3], const int(*edges)[2], int totvert, int totedge)
struct VolumeWireframeUserData VolumeWireframeUserData
GPUBatch * DRW_volume_batch_cache_get_wireframes_face(Volume *volume)
int DRW_volume_material_count_get(Volume *volume)
void DRW_volume_batch_cache_validate(Volume *volume)
const DRWContextState * DRW_context_state_get(void)
static float verts[][3]
struct @653::@656 attr_id
IconTextureDrawCall normal
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 G(x, y, z)
struct Scene * scene
Definition: DRW_render.h:979
float texture_to_object[4][4]
Definition: draw_cache.h:251
struct DRWVolumeGrid * next
Definition: draw_cache.h:242
struct GPUTexture * texture
Definition: draw_cache.h:248
float object_to_texture[4][4]
Definition: draw_cache.h:252
float texture_to_object[4][4]
void * first
Definition: DNA_listBase.h:31
struct RenderData r
GPUVertBuf * pos_nor_in_order
struct VolumeBatchCache::@292 face_wire
void * batch_cache
short totcol
VolumeDisplay display