Blender V4.5
draw_cache_impl_volume.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
10
11#include <cstring>
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_listbase.h"
16#include "BLI_math_matrix.hh"
17#include "BLI_string.h"
18#include "BLI_utildefines.h"
19
20#include "DNA_scene_types.h"
21#include "DNA_volume_types.h"
22
23#include "BKE_global.hh"
24#include "BKE_volume.hh"
26#include "BKE_volume_render.hh"
27
29#include "GPU_batch.hh"
30#include "GPU_capabilities.hh"
31#include "GPU_texture.hh"
32
33#include "DRW_render.hh"
34
35#include "draw_cache.hh" /* own include */
36#include "draw_cache_impl.hh" /* own include */
37
38namespace blender::draw {
39
40static void volume_batch_cache_clear(Volume *volume);
41
42/* ---------------------------------------------------------------------- */
43/* Volume gpu::Batch Cache */
44
46 /* 3D textures */
48
49 /* Wireframe */
50 struct {
52 gpu::Batch *batch;
54
55 /* Surface for selection */
56 gpu::Batch *selection_surface;
57
58 /* settings to determine if cache is invalid */
60};
61
62/* gpu::Batch cache management. */
63
64static bool volume_batch_cache_valid(Volume *volume)
65{
66 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
67 return (cache && cache->is_dirty == false);
68}
69
70static void volume_batch_cache_init(Volume *volume)
71{
72 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
73
74 if (!cache) {
75 volume->batch_cache = cache = MEM_callocN<VolumeBatchCache>(__func__);
76 }
77 else {
78 memset(cache, 0, sizeof(*cache));
79 }
80
81 cache->is_dirty = false;
82}
83
85{
86 if (!volume_batch_cache_valid(volume)) {
89 }
90}
91
93{
95 return static_cast<VolumeBatchCache *>(volume->batch_cache);
96}
97
99{
100 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
101 if (cache == nullptr) {
102 return;
103 }
104 switch (mode) {
106 cache->is_dirty = true;
107 break;
108 default:
109 BLI_assert(0);
110 }
111}
112
114{
115 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
116 if (!cache) {
117 return;
118 }
119
120 LISTBASE_FOREACH (DRWVolumeGrid *, grid, &cache->grids) {
121 MEM_SAFE_FREE(grid->name);
122 GPU_TEXTURE_FREE_SAFE(grid->texture);
123 }
124 BLI_freelistN(&cache->grids);
125
129}
130
140
142 void *userdata, const float (*verts)[3], const int (*edges)[2], int totvert, int totedge)
143{
144 VolumeWireframeUserData *data = static_cast<VolumeWireframeUserData *>(userdata);
145 Scene *scene = data->scene;
146 Volume *volume = data->volume;
147 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
148 const bool do_hq_normals = (scene->r.perf_flag & SCE_PERF_HQ_NORMALS) != 0 ||
150
151 /* Create vertex buffer. */
152 static struct {
153 uint pos_id, nor_id;
154 uint pos_hq_id, nor_hq_id;
155 } attr_id;
156
157 static const GPUVertFormat format = [&]() {
162 return format;
163 }();
164
165 static const GPUVertFormat format_hq = [&]() {
170 return format;
171 }();
172
173 uint pos_id = do_hq_normals ? attr_id.pos_hq_id : attr_id.pos_id;
174 uint nor_id = do_hq_normals ? attr_id.nor_hq_id : attr_id.nor_id;
175
176 cache->face_wire.pos_nor_in_order = GPU_vertbuf_create_with_format(do_hq_normals ? format_hq :
177 format);
180 const float3 normal(1.0f, 0.0f, 0.0f);
181 if (do_hq_normals) {
182 const gpu::PackedNormal packed_normal = gpu::convert_normal<gpu::PackedNormal>(normal);
183 GPU_vertbuf_attr_fill_stride(cache->face_wire.pos_nor_in_order, nor_id, 0, &packed_normal);
184 }
185 else {
186 const short4 packed_normal = gpu::convert_normal<short4>(normal);
187 GPU_vertbuf_attr_fill_stride(cache->face_wire.pos_nor_in_order, nor_id, 0, &packed_normal);
188 }
189
190 /* Create wiredata. */
191 gpu::VertBuf *vbo_wiredata = GPU_vertbuf_calloc();
192 DRW_vertbuf_create_wiredata(vbo_wiredata, totvert);
193
195 /* Create batch. */
198 }
199 else {
200 /* Create edge index buffer. */
202 GPU_indexbuf_init(&elb, GPU_PRIM_LINES, totedge, totvert);
203 for (int i = 0; i < totedge; i++) {
204 GPU_indexbuf_add_line_verts(&elb, edges[i][0], edges[i][1]);
205 }
207
208 /* Create batch. */
211 }
212
213 GPU_batch_vertbuf_add(cache->face_wire.batch, vbo_wiredata, true);
214}
215
217{
219 return nullptr;
220 }
221
223
224 if (cache->face_wire.batch == nullptr) {
225 const bke::VolumeGridData *volume_grid = BKE_volume_grid_active_get_for_read(volume);
226 if (volume_grid == nullptr) {
227 return nullptr;
228 }
229
230 /* Create wireframe from OpenVDB tree. */
231 const DRWContext *draw_ctx = DRW_context_get();
233 userdata.volume = volume;
234 userdata.scene = draw_ctx->scene;
235 BKE_volume_grid_wireframe(volume, volume_grid, drw_volume_wireframe_cb, &userdata);
236 }
237
238 return cache->face_wire.batch;
239}
240
242 void *userdata, float (*verts)[3], int (*tris)[3], int totvert, int tottris)
243{
244 Volume *volume = static_cast<Volume *>(userdata);
245 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
246
247 static uint pos_id;
248 static const GPUVertFormat format = [&]() {
251 return format;
252 }();
253
254 /* Create vertex buffer. */
256 GPU_vertbuf_data_alloc(*vbo_surface, totvert);
257 GPU_vertbuf_attr_fill(vbo_surface, pos_id, verts);
258
259 /* Create index buffer. */
261 GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottris, totvert);
262 for (int i = 0; i < tottris; i++) {
264 }
265 gpu::IndexBuf *ibo_surface = GPU_indexbuf_build(&elb);
266
268 GPU_PRIM_TRIS, vbo_surface, ibo_surface, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
269}
270
272{
274 if (cache->selection_surface == nullptr) {
275 const bke::VolumeGridData *volume_grid = BKE_volume_grid_active_get_for_read(volume);
276 if (volume_grid == nullptr) {
277 return nullptr;
278 }
280 volume, volume_grid, drw_volume_selection_surface_cb, volume);
281 }
282 return cache->selection_surface;
283}
284
286 const bke::VolumeGridData *grid,
287 VolumeBatchCache *cache)
288{
289 const std::string name = bke::volume_grid::get_name(*grid);
290
291 /* Return cached grid. */
292 LISTBASE_FOREACH (DRWVolumeGrid *, cache_grid, &cache->grids) {
293 if (cache_grid->name == name) {
294 return cache_grid;
295 }
296 }
297
298 /* Allocate new grid. */
299 DRWVolumeGrid *cache_grid = MEM_callocN<DRWVolumeGrid>(__func__);
300 cache_grid->name = BLI_strdup(name.c_str());
301 BLI_addtail(&cache->grids, cache_grid);
302
303 /* TODO: can we load this earlier, avoid accessing the global and take
304 * advantage of dependency graph multi-threading? */
305 BKE_volume_load(volume, G.main);
306
307 /* Test if we support textures with the number of channels. */
309 if (!ELEM(channels, 1, 3)) {
310 return cache_grid;
311 }
312
313 DenseFloatVolumeGrid dense_grid;
314 if (BKE_volume_grid_dense_floats(volume, grid, &dense_grid)) {
315 cache_grid->texture_to_object = float4x4(dense_grid.texture_to_object);
316 cache_grid->object_to_texture = math::invert(cache_grid->texture_to_object);
317
318 /* Create GPU texture. */
319 eGPUTextureFormat format = (channels == 3) ? GPU_RGB16F : GPU_R16F;
320 cache_grid->texture = GPU_texture_create_3d("volume_grid",
321 UNPACK3(dense_grid.resolution),
322 1,
323 format,
325 dense_grid.voxels);
326 /* The texture can be null if the resolution along one axis is larger than
327 * GL_MAX_3D_TEXTURE_SIZE. */
328 if (cache_grid->texture != nullptr) {
329 GPU_texture_swizzle_set(cache_grid->texture, (channels == 3) ? "rgb1" : "rrr1");
332 }
333 else {
334 MEM_freeN(dense_grid.voxels);
335 printf("Error: Could not allocate 3D texture for volume.\n");
336 }
337 }
338
339 return cache_grid;
340}
341
343 const bke::VolumeGridData *volume_grid)
344{
346 DRWVolumeGrid *grid = volume_grid_cache_get(volume, volume_grid, cache);
347 return (grid->texture != nullptr) ? grid : nullptr;
348}
349
350} // namespace blender::draw
Volume data-block.
const blender::bke::VolumeGridData * BKE_volume_grid_active_get_for_read(const Volume *volume)
bool BKE_volume_load(const Volume *volume, const Main *bmain)
@ BKE_VOLUME_BATCH_DIRTY_ALL
Definition BKE_volume.hh:61
Volume data-block rendering and viewport drawing utilities.
void BKE_volume_dense_float_grid_clear(DenseFloatVolumeGrid *dense_grid)
void BKE_volume_grid_selection_surface(const Volume *volume, const blender::bke::VolumeGridData *volume_grid, BKE_volume_selection_surface_cb cb, void *cb_userdata)
bool BKE_volume_grid_dense_floats(const Volume *volume, const blender::bke::VolumeGridData *volume_grid, DenseFloatVolumeGrid *r_dense_grid)
void BKE_volume_grid_wireframe(const Volume *volume, const blender::bke::VolumeGridData *volume_grid, BKE_volume_wireframe_cb cb, void *cb_userdata)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
void void BLI_freelistN(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:497
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
unsigned int uint
#define UNPACK3(a)
#define ELEM(...)
@ SCE_PERF_HQ_NORMALS
@ VOLUME_WIREFRAME_NONE
@ VOLUME_WIREFRAME_POINTS
struct Volume Volume
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, eGPUBatchFlag owns_flag)
Definition gpu_batch.cc:51
#define GPU_batch_create(primitive_type, vertex_buf, index_buf)
Definition GPU_batch.hh:148
int GPU_batch_vertbuf_add(blender::gpu::Batch *batch, blender::gpu::VertBuf *vertex_buf, bool own_vbo)
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:204
@ GPU_BATCH_OWNS_INDEX
Definition GPU_batch.hh:50
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:41
bool GPU_use_hq_normals_workaround()
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
blender::gpu::IndexBuf * 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
@ GPU_PRIM_POINTS
@ GPU_PRIM_TRIS
void GPU_texture_extend_mode(GPUTexture *texture, GPUSamplerExtendMode extend_mode)
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER
GPUTexture * GPU_texture_create_3d(const char *name, int width, int height, int depth, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const void *data)
#define GPU_TEXTURE_FREE_SAFE(texture)
eGPUTextureFormat
@ GPU_R16F
@ GPU_RGB16F
void GPU_texture_swizzle_set(GPUTexture *texture, const char swizzle[4])
void GPU_vertbuf_attr_fill_stride(blender::gpu::VertBuf *, uint a_idx, uint stride, const void *data)
#define GPU_vertbuf_create_with_format(format)
void GPU_vertbuf_attr_fill(blender::gpu::VertBuf *, uint a_idx, const void *data)
#define GPU_VERTBUF_DISCARD_SAFE(verts)
blender::gpu::VertBuf * GPU_vertbuf_calloc()
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_I10
@ GPU_COMP_F32
@ GPU_COMP_I16
Read Guarded memory(de)allocation.
BMesh const char void * data
const DRWContext * DRW_context_get()
static float verts[][3]
struct @242053044010324116347033273112253060004051364061::@373043131300025057314200265134167265161140142363 attr_id
#define printf(...)
#define MEM_SAFE_FREE(v)
format
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
std::string get_name(const VolumeGridData &grid)
int get_channels_num(VolumeGridType type)
VolumeGridType get_type(const VolumeGridData &grid)
void DRW_vertbuf_create_wiredata(gpu::VertBuf *vbo, const int vert_len)
Definition draw_cache.cc:71
blender::gpu::Batch * DRW_volume_batch_cache_get_selection_surface(Volume *volume)
static void volume_batch_cache_clear(Volume *volume)
static void volume_batch_cache_init(Volume *volume)
void DRW_volume_batch_cache_free(Volume *volume)
void DRW_volume_batch_cache_validate(Volume *volume)
void DRW_volume_batch_cache_dirty_tag(Volume *volume, int mode)
blender::gpu::Batch * DRW_volume_batch_cache_get_wireframes_face(Volume *volume)
static bool volume_batch_cache_valid(Volume *volume)
static DRWVolumeGrid * volume_grid_cache_get(const Volume *volume, const bke::VolumeGridData *grid, VolumeBatchCache *cache)
static VolumeBatchCache * volume_batch_cache_get(Volume *volume)
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 bke::VolumeGridData *volume_grid)
static void drw_volume_wireframe_cb(void *userdata, const float(*verts)[3], const int(*edges)[2], int totvert, int totedge)
GPUType convert_normal(const float3 &src)
CartesianBasis invert(const CartesianBasis &basis)
MatBase< float, 4, 4 > float4x4
blender::VecBase< int16_t, 4 > short4
VecBase< float, 3 > float3
Scene * scene
struct RenderData r
void * batch_cache
VolumeDisplay display
struct blender::draw::VolumeBatchCache::@103167160167351272355321337360201072204023236244 face_wire
i
Definition text_draw.cc:230