Blender V4.5
draw_cache_impl_pointcloud.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_color.hh"
16#include "BLI_listbase.h"
17#include "BLI_task.hh"
18#include "BLI_utildefines.h"
19
20#include "DNA_object_types.h"
22#include "DNA_userdef_types.h"
23
24#include "BKE_attribute.hh"
25#include "BKE_material.hh"
26#include "BKE_pointcloud.hh"
27
28#include "GPU_batch.hh"
29#include "GPU_material.hh"
30
31#include "DRW_render.hh"
32
33#include "draw_attributes.hh"
34#include "draw_cache_impl.hh"
35#include "draw_cache_inline.hh"
36#include "draw_pointcloud_private.hh" /* own include */
37
38namespace blender::draw {
39
40/* -------------------------------------------------------------------- */
43
45 /* Dot primitive types. */
46 gpu::Batch *dots;
47 /* Triangle primitive types. */
48 gpu::Batch *surface;
49 gpu::Batch **surface_per_mat;
50
51 /* Triangles indices to draw the points. */
53
54 /* Position and radius. */
56 /* Active attribute in 3D view. */
58 /* Requested attributes */
60
68
75
77};
78
81
83 gpu::Batch *edit_selection = nullptr;
84
85 /* settings to determine if cache is invalid */
87
94};
95
97{
98 return static_cast<PointCloudBatchCache *>(pointcloud.batch_cache);
99}
100
102{
104
105 if (cache == nullptr) {
106 return false;
107 }
109 return false;
110 }
111 return cache->is_dirty == false;
112}
113
115{
117
118 if (!cache) {
119 cache = MEM_new<PointCloudBatchCache>(__func__);
120 pointcloud.batch_cache = cache;
121 }
122 else {
123 cache->eval_cache = {};
124 cache->edit_selection = nullptr;
125 cache->edit_selection_indices = nullptr;
126 }
127
129 cache->eval_cache.surface_per_mat = static_cast<gpu::Batch **>(
130 MEM_callocN(sizeof(gpu::Batch *) * cache->eval_cache.mat_len, __func__));
131
132 cache->is_dirty = false;
133}
134
136{
138 if (cache == nullptr) {
139 return;
140 }
141 switch (mode) {
143 cache->is_dirty = true;
144 break;
145 default:
146 BLI_assert(0);
147 }
148}
149
151{
152 for (const int j : IndexRange(GPU_MAX_ATTR)) {
154 }
155
156 cache.eval_cache.attr_used.clear();
157}
158
184
186{
187 if (!pointcloud_batch_cache_valid(*pointcloud)) {
188 pointcloud_batch_cache_clear(*pointcloud);
189 pointcloud_batch_cache_init(*pointcloud);
190 }
191}
192
194{
195 pointcloud_batch_cache_clear(*pointcloud);
196 MEM_delete(static_cast<PointCloudBatchCache *>(pointcloud->batch_cache));
197 pointcloud->batch_cache = nullptr;
198}
199
201{
203 if (!cache) {
204 return;
205 }
206
207 bool do_discard = false;
208
210 {
211 cache->eval_cache.last_attr_matching_time = ctime;
212 }
213
214 if (ctime - cache->eval_cache.last_attr_matching_time > U.vbotimeout) {
215 do_discard = true;
216 }
217
219
220 if (do_discard) {
222 }
223}
224
226
227/* -------------------------------------------------------------------- */
230
231static const uint half_octahedron_tris[4][3] = {
232 {0, 1, 2},
233 {0, 2, 3},
234 {0, 3, 4},
235 {0, 4, 1},
236};
237
238static void pointcloud_extract_indices(const PointCloud &pointcloud, PointCloudBatchCache &cache)
239{
240 /* Overlap shape and point indices to avoid both having to store the indices into a separate
241 * buffer and avoid rendering points as instances. */
242 uint32_t vertid_max = pointcloud.totpoint << 3;
243 constexpr uint32_t tri_count_per_point = ARRAY_SIZE(half_octahedron_tris);
244 uint32_t primitive_len = pointcloud.totpoint * tri_count_per_point;
245
246 GPUIndexBufBuilder builder;
247 GPU_indexbuf_init(&builder, GPU_PRIM_TRIS, primitive_len, vertid_max);
249
250 /* TODO(fclem): Could be build on GPU or not be built at all. */
251 threading::parallel_for(IndexRange(pointcloud.totpoint), 1024, [&](const IndexRange range) {
252 for (int p : range) {
253 for (int i : IndexRange(tri_count_per_point)) {
254 data[p * tri_count_per_point + i] = uint3(half_octahedron_tris[i]) | (p << 3);
255 }
256 }
257 });
258
260 &builder, 0, primitive_len * 3, false, cache.eval_cache.geom_indices);
261}
262
265{
266 const bke::AttributeAccessor attributes = pointcloud.attributes();
267 const Span<float3> positions = pointcloud.positions();
268 const VArray<float> radii = *attributes.lookup<float>("radius");
269 static const GPUVertFormat format = [&]() {
272 GPU_vertformat_alias_add(&format, "pos_rad");
273 return format;
274 }();
275
278
279 GPU_vertbuf_data_alloc(*cache.eval_cache.pos_rad, positions.size());
280 MutableSpan<float4> vbo_data = cache.eval_cache.pos_rad->data<float4>();
281 if (radii) {
282 const VArraySpan<float> radii_span(std::move(radii));
283 threading::parallel_for(vbo_data.index_range(), 4096, [&](IndexRange range) {
284 for (const int i : range) {
285 vbo_data[i].x = positions[i].x;
286 vbo_data[i].y = positions[i].y;
287 vbo_data[i].z = positions[i].z;
288 vbo_data[i].w = radii_span[i];
289 }
290 });
291 }
292 else {
293 threading::parallel_for(vbo_data.index_range(), 4096, [&](IndexRange range) {
294 for (const int i : range) {
295 vbo_data[i].x = positions[i].x;
296 vbo_data[i].y = positions[i].y;
297 vbo_data[i].z = positions[i].z;
298 vbo_data[i].w = 0.01f;
299 }
300 });
301 }
302}
303
304static void pointcloud_extract_attribute(const PointCloud &pointcloud,
306 const StringRef name,
307 int index)
308{
309 gpu::VertBuf &attr_buf = *cache.eval_cache.attributes_buf[index];
310
311 const bke::AttributeAccessor attributes = pointcloud.attributes();
312
313 /* TODO(@kevindietrich): float4 is used for scalar attributes as the implicit conversion done
314 * by OpenGL to float4 for a scalar `s` will produce a `float4(s, 0, 0, 1)`. However, following
315 * the Blender convention, it should be `float4(s, s, s, 1)`. This could be resolved using a
316 * similar texture state swizzle to map the attribute correctly as for volume attributes, so we
317 * can control the conversion ourselves. */
319 name, bke::AttrDomain::Point, {0.0f, 0.0f, 0.0f, 1.0f});
320
321 static const GPUVertFormat format = [&]() {
324 return format;
325 }();
327 GPU_vertbuf_init_with_format_ex(attr_buf, format, usage_flag);
328 GPU_vertbuf_data_alloc(attr_buf, pointcloud.totpoint);
329
330 attribute.varray.materialize(attr_buf.data<ColorGeometry4f>());
331}
332
334
335/* -------------------------------------------------------------------- */
338
345
347 GPUMaterial **gpu_materials,
348 int mat_len)
349{
350 const bke::AttributeAccessor attributes = pointcloud->attributes();
352 VectorSet<std::string> attrs_needed;
353
354 for (GPUMaterial *gpu_material : Span<GPUMaterial *>(gpu_materials, mat_len)) {
355 ListBase gpu_attrs = GPU_material_attributes(gpu_material);
356 LISTBASE_FOREACH (GPUMaterialAttribute *, gpu_attr, &gpu_attrs) {
357 const StringRef name = gpu_attr->name;
358 if (!attributes.contains(name)) {
359 continue;
360 }
361 drw_attributes_add_request(&attrs_needed, name);
362 }
363 }
364
365 if (!drw_attributes_overlap(&cache->eval_cache.attr_used, &attrs_needed)) {
366 /* Some new attributes have been added, free all and start over. */
367 for (const int i : IndexRange(GPU_MAX_ATTR)) {
369 }
370 drw_attributes_merge(&cache->eval_cache.attr_used, &attrs_needed, cache->render_mutex);
371 }
372 drw_attributes_merge(&cache->eval_cache.attr_used_over_time, &attrs_needed, cache->render_mutex);
373
375 return cache->eval_cache.surface_per_mat;
376}
377
378gpu::Batch *pointcloud_surface_get(PointCloud *pointcloud)
379{
381 return DRW_batch_request(&cache->eval_cache.surface);
382}
383
385
386/* -------------------------------------------------------------------- */
389
396
402
404{
405 const bke::AttributeAccessor attributes = pointcloud->attributes();
407
408 if (!attributes.contains(name)) {
409 return nullptr;
410 }
411 {
412 VectorSet<std::string> requests{};
413 drw_attributes_add_request(&requests, name);
414 drw_attributes_merge(&cache.eval_cache.attr_used, &requests, cache.render_mutex);
415 }
416
417 int request_i = -1;
418 for (const int i : IndexRange(cache.eval_cache.attr_used.index_range())) {
419 if (cache.eval_cache.attr_used[i] == name) {
420 request_i = i;
421 break;
422 }
423 }
424 if (request_i == -1) {
425 return nullptr;
426 }
427 return &cache.eval_cache.attributes_buf[request_i];
428}
429
431{
432 const int max_index = mask.min_array_size();
433 GPUIndexBufBuilder builder;
434 GPU_indexbuf_init(&builder, GPU_PRIM_POINTS, mask.size(), max_index);
436 mask.to_indices<int>(data.cast<int>());
437 GPU_indexbuf_build_in_place_ex(&builder, 0, max_index, false, &ibo);
438}
439
440static void build_edit_selection_indices(const PointCloud &pointcloud, gpu::IndexBuf &ibo)
441{
442 const VArray selection = *pointcloud.attributes().lookup_or_default<bool>(
443 ".selection", bke::AttrDomain::Point, true);
444 IndexMaskMemory memory;
445 const IndexMask mask = IndexMask::from_bools(selection, memory);
446 if (mask.is_empty()) {
447 return;
448 }
450}
451
453{
456
459 }
460
464 }
465
469 }
470 for (int i = 0; i < cache.eval_cache.mat_len; i++) {
472 /* TODO(fclem): Per material ranges. */
474 }
475 }
476 for (const int j : cache.eval_cache.attr_used.index_range()) {
477 DRW_vbo_request(nullptr, &cache.eval_cache.attributes_buf[j]);
478
480 pointcloud_extract_attribute(pointcloud, cache, cache.eval_cache.attr_used[j], j);
481 }
482 }
483
486 }
487
489 pointcloud_extract_indices(pointcloud, cache);
490 }
491
494 }
495}
496
498{
500 return DRW_batch_request(&cache->edit_selection);
501}
502
504
505} // namespace blender::draw
General operations, lookup, etc. for materials.
int BKE_id_material_used_with_fallback_eval(const ID &id)
General operations for point clouds.
@ BKE_POINTCLOUD_BATCH_DIRTY_ALL
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
unsigned int uint
#define ARRAY_SIZE(arr)
Object is a sort of wrapper for general info.
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:204
void GPU_indexbuf_build_in_place_ex(GPUIndexBufBuilder *builder, uint index_min, uint index_max, bool uses_restart_indices, blender::gpu::IndexBuf *elem)
blender::MutableSpan< uint32_t > GPU_indexbuf_get_data(GPUIndexBufBuilder *)
#define GPU_INDEXBUF_DISCARD_SAFE(elem)
void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len)
ListBase GPU_material_attributes(const GPUMaterial *material)
@ GPU_PRIM_POINTS
@ GPU_PRIM_TRIS
static constexpr int GPU_MAX_ATTR
Definition GPU_shader.hh:34
#define GPU_VERTBUF_DISCARD_SAFE(verts)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
void GPU_vertbuf_init_with_format_ex(blender::gpu::VertBuf &verts, const GPUVertFormat &format, GPUUsageType)
@ GPU_USAGE_STATIC
@ GPU_USAGE_FLAG_BUFFER_TEXTURE_ONLY
@ GPU_FETCH_FLOAT
void GPU_vertformat_alias_add(GPUVertFormat *, blender::StringRef alias)
uint GPU_vertformat_attr_add(GPUVertFormat *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
Read Guarded memory(de)allocation.
#define U
BMesh const char void * data
AttributeSet attributes
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
IndexRange index_range() const
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr int64_t size() const
Definition BLI_span.hh:252
bool contains(StringRef attribute_id) const
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
MutableSpan< T > data()
Utilities for rendering attributes.
bool DRW_batch_requested(blender::gpu::Batch *batch, GPUPrimType prim_type)
blender::gpu::Batch * DRW_batch_request(blender::gpu::Batch **batch)
void DRW_vbo_request(blender::gpu::Batch *batch, blender::gpu::VertBuf **vbo)
bool DRW_vbo_requested(blender::gpu::VertBuf *vbo)
void DRW_ibo_request(blender::gpu::Batch *batch, blender::gpu::IndexBuf **ibo)
bool DRW_ibo_requested(blender::gpu::IndexBuf *ibo)
Mesh & DRW_object_get_data_for_drawing(const Object &object)
#define MEM_SAFE_FREE(v)
format
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void drw_attributes_add_request(VectorSet< std::string > *attrs, const StringRef name)
static PointCloudBatchCache * pointcloud_batch_cache_get(PointCloud &pointcloud)
gpu::Batch * pointcloud_surface_get(PointCloud *pointcloud)
static void pointcloud_extract_attribute(const PointCloud &pointcloud, PointCloudBatchCache &cache, const StringRef name, int index)
static void pointcloud_extract_position_and_radius(const PointCloud &pointcloud, PointCloudBatchCache &cache)
static void build_edit_selection_indices(const PointCloud &pointcloud, gpu::IndexBuf &ibo)
static void pointcloud_discard_attributes(PointCloudBatchCache &cache)
void DRW_pointcloud_batch_cache_dirty_tag(PointCloud *pointcloud, int mode)
static void pointcloud_batch_cache_init(PointCloud &pointcloud)
gpu::Batch ** pointcloud_surface_shaded_get(PointCloud *pointcloud, GPUMaterial **gpu_materials, int mat_len)
void drw_attributes_merge(VectorSet< std::string > *dst, const VectorSet< std::string > *src, Mutex &render_mutex)
blender::gpu::Batch * DRW_pointcloud_batch_cache_get_dots(Object *ob)
static void pointcloud_batch_cache_clear(PointCloud &pointcloud)
static void pointcloud_extract_indices(const PointCloud &pointcloud, PointCloudBatchCache &cache)
void DRW_pointcloud_batch_cache_free_old(PointCloud *pointcloud, int ctime)
blender::gpu::Batch * DRW_pointcloud_batch_cache_get_edit_dots(PointCloud *pointcloud)
bool drw_attributes_overlap(const VectorSet< std::string > *a, const VectorSet< std::string > *b)
gpu::VertBuf ** DRW_pointcloud_evaluated_attribute(PointCloud *pointcloud, StringRef name)
static const uint half_octahedron_tris[4][3]
void DRW_pointcloud_batch_cache_create_requested(Object *ob)
void DRW_pointcloud_batch_cache_validate(PointCloud *pointcloud)
static void index_mask_to_ibo(const IndexMask &mask, gpu::IndexBuf &ibo)
static bool pointcloud_batch_cache_valid(PointCloud &pointcloud)
void DRW_pointcloud_batch_cache_free(PointCloud *pointcloud)
gpu::VertBuf * pointcloud_position_and_radius_get(PointCloud *pointcloud)
gpu::VertBuf * DRW_pointcloud_position_and_radius_buffer_get(Object *ob)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
VecBase< uint32_t, 3 > uint3
VecBase< float, 4 > float4
std::mutex Mutex
Definition BLI_mutex.hh:47
ColorSceneLinear4f< eAlpha::Premultiplied > ColorGeometry4f
Definition BLI_color.hh:342
i
Definition text_draw.cc:230