Blender V5.0
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 = [&]() {
159 attr_id.pos_id = GPU_vertformat_attr_add(&format, "pos", gpu::VertAttrType::SFLOAT_32_32_32);
161 &format, "nor", blender::gpu::VertAttrType::SNORM_10_10_10_2);
162 return format;
163 }();
164
165 static const GPUVertFormat format_hq = [&]() {
168 &format, "pos", gpu::VertAttrType::SFLOAT_32_32_32);
170 &format, "nor", blender::gpu::VertAttrType::SNORM_16_16_16_16);
171 return format;
172 }();
173
174 uint pos_id = do_hq_normals ? attr_id.pos_hq_id : attr_id.pos_id;
175 uint nor_id = do_hq_normals ? attr_id.nor_hq_id : attr_id.nor_id;
176
177 cache->face_wire.pos_nor_in_order = GPU_vertbuf_create_with_format(do_hq_normals ? format_hq :
178 format);
181 const float3 normal(1.0f, 0.0f, 0.0f);
182 if (do_hq_normals) {
183 const gpu::PackedNormal packed_normal = gpu::convert_normal<gpu::PackedNormal>(normal);
184 GPU_vertbuf_attr_fill_stride(cache->face_wire.pos_nor_in_order, nor_id, 0, &packed_normal);
185 }
186 else {
187 const short4 packed_normal = gpu::convert_normal<short4>(normal);
188 GPU_vertbuf_attr_fill_stride(cache->face_wire.pos_nor_in_order, nor_id, 0, &packed_normal);
189 }
190
191 /* Create wiredata. */
192 gpu::VertBuf *vbo_wiredata = GPU_vertbuf_calloc();
193 DRW_vertbuf_create_wiredata(vbo_wiredata, totvert);
194
196 /* Create batch. */
199 }
200 else {
201 /* Create edge index buffer. */
203 GPU_indexbuf_init(&elb, GPU_PRIM_LINES, totedge, totvert);
204 for (int i = 0; i < totedge; i++) {
205 GPU_indexbuf_add_line_verts(&elb, edges[i][0], edges[i][1]);
206 }
208
209 /* Create batch. */
212 }
213
214 GPU_batch_vertbuf_add(cache->face_wire.batch, vbo_wiredata, true);
215}
216
218{
220 return nullptr;
221 }
222
224
225 if (cache->face_wire.batch == nullptr) {
226 const bke::VolumeGridData *volume_grid = BKE_volume_grid_active_get_for_read(volume);
227 if (volume_grid == nullptr) {
228 return nullptr;
229 }
230
231 /* Create wireframe from OpenVDB tree. */
232 const DRWContext *draw_ctx = DRW_context_get();
234 userdata.volume = volume;
235 userdata.scene = draw_ctx->scene;
236 BKE_volume_grid_wireframe(volume, volume_grid, drw_volume_wireframe_cb, &userdata);
237 }
238
239 return cache->face_wire.batch;
240}
241
243 void *userdata, float (*verts)[3], int (*tris)[3], int totvert, int tottris)
244{
245 Volume *volume = static_cast<Volume *>(userdata);
246 VolumeBatchCache *cache = static_cast<VolumeBatchCache *>(volume->batch_cache);
247
248 static uint pos_id;
249 static const GPUVertFormat format = [&]() {
251 pos_id = GPU_vertformat_attr_add(&format, "pos", gpu::VertAttrType::SFLOAT_32_32_32);
252 return format;
253 }();
254
255 /* Create vertex buffer. */
257 GPU_vertbuf_data_alloc(*vbo_surface, totvert);
258 GPU_vertbuf_attr_fill(vbo_surface, pos_id, verts);
259
260 /* Create index buffer. */
262 GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, tottris, totvert);
263 for (int i = 0; i < tottris; i++) {
265 }
266 gpu::IndexBuf *ibo_surface = GPU_indexbuf_build(&elb);
267
269 GPU_PRIM_TRIS, vbo_surface, ibo_surface, GPU_BATCH_OWNS_VBO | GPU_BATCH_OWNS_INDEX);
270}
271
273{
275 if (cache->selection_surface == nullptr) {
276 const bke::VolumeGridData *volume_grid = BKE_volume_grid_active_get_for_read(volume);
277 if (volume_grid == nullptr) {
278 return nullptr;
279 }
281 volume, volume_grid, drw_volume_selection_surface_cb, volume);
282 }
283 return cache->selection_surface;
284}
285
287 const bke::VolumeGridData *grid,
288 VolumeBatchCache *cache)
289{
290 const std::string name = bke::volume_grid::get_name(*grid);
291
292 /* Return cached grid. */
293 LISTBASE_FOREACH (DRWVolumeGrid *, cache_grid, &cache->grids) {
294 if (cache_grid->name == name) {
295 return cache_grid;
296 }
297 }
298
299 /* Allocate new grid. */
300 DRWVolumeGrid *cache_grid = MEM_callocN<DRWVolumeGrid>(__func__);
301 cache_grid->name = BLI_strdup(name.c_str());
302 BLI_addtail(&cache->grids, cache_grid);
303
304 /* TODO: can we load this earlier, avoid accessing the global and take
305 * advantage of dependency graph multi-threading? */
306 BKE_volume_load(volume, G.main);
307
308 /* Test if we support textures with the number of channels. */
310 if (!ELEM(channels, 1, 3)) {
311 return cache_grid;
312 }
313
314 DenseFloatVolumeGrid dense_grid;
315 if (BKE_volume_grid_dense_floats(volume, grid, &dense_grid)) {
316 cache_grid->texture_to_object = float4x4(dense_grid.texture_to_object);
317 cache_grid->object_to_texture = math::invert(cache_grid->texture_to_object);
318
319 /* Create GPU texture. */
320 blender::gpu::TextureFormat format = (channels == 3) ?
321 blender::gpu::TextureFormat::SFLOAT_16_16_16 :
322 blender::gpu::TextureFormat::SFLOAT_16;
323 cache_grid->texture = GPU_texture_create_3d("volume_grid",
324 UNPACK3(dense_grid.resolution),
325 1,
326 format,
328 dense_grid.voxels);
329 /* The texture can be null if the resolution along one axis is larger than
330 * GL_MAX_3D_TEXTURE_SIZE. */
331 if (cache_grid->texture != nullptr) {
332 GPU_texture_swizzle_set(cache_grid->texture, (channels == 3) ? "rgb1" : "rrr1");
335 }
336 else {
337 MEM_freeN(dense_grid.voxels);
338 printf("Error: Could not allocate 3D texture for volume.\n");
339 }
340 }
341
342 return cache_grid;
343}
344
346 const bke::VolumeGridData *volume_grid)
347{
349 DRWVolumeGrid *grid = volume_grid_cache_get(volume, volume_grid, cache);
350 return (grid->texture != nullptr) ? grid : nullptr;
351}
352
353} // namespace blender::draw
Volume data-block.
const blender::bke::VolumeGridData * BKE_volume_grid_active_get_for_read(const Volume *volume)
@ BKE_VOLUME_BATCH_DIRTY_ALL
Definition BKE_volume.hh:61
bool BKE_volume_load(const Volume *volume, const Main *bmain)
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
#define GPU_batch_create(primitive_type, vertex_buf, index_buf)
Definition GPU_batch.hh:141
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:197
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, GPUBatchFlag owns_flag)
Definition gpu_batch.cc:51
@ GPU_BATCH_OWNS_INDEX
Definition GPU_batch.hh:46
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
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_swizzle_set(blender::gpu::Texture *texture, const char swizzle[4])
void GPU_texture_extend_mode(blender::gpu::Texture *texture, GPUSamplerExtendMode extend_mode)
@ GPU_TEXTURE_USAGE_SHADER_READ
@ GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER
#define GPU_TEXTURE_FREE_SAFE(texture)
blender::gpu::Texture * GPU_texture_create_3d(const char *name, int width, int height, int depth, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const void *data)
void GPU_vertbuf_attr_fill_stride(blender::gpu::VertBuf *, uint a_idx, uint stride, const void *data)
void GPU_vertbuf_attr_fill(blender::gpu::VertBuf *, uint a_idx, const void *data)
static blender::gpu::VertBuf * GPU_vertbuf_create_with_format(const GPUVertFormat &format)
#define GPU_VERTBUF_DISCARD_SAFE(verts)
blender::gpu::VertBuf * GPU_vertbuf_calloc()
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
BMesh const char void * data
const DRWContext * DRW_context_get()
static float verts[][3]
struct @021025263243242147216143265077100330027142264337::@240232116316110053135047106323056371161236243121 attr_id
#define printf(...)
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:72
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
const char * name
Scene * scene
struct RenderData r
void * batch_cache
VolumeDisplay display
struct blender::draw::VolumeBatchCache::@251277341041107130027136061041241155223024010047 face_wire
i
Definition text_draw.cc:230