Blender V5.0
draw_manager.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#pragma once
6
16
17#include "BLI_listbase.h"
18#include "BLI_map.hh"
19#include "BLI_sys_types.h"
20
21#include "GPU_material.hh"
22
23#include "draw_resource.hh"
24#include "draw_view.hh"
25
26#include <atomic>
27
28namespace blender::draw {
29
30/* Forward declarations. */
31
32namespace detail {
33template<typename T> class Pass;
34} // namespace detail
35
36namespace command {
37class DrawCommandBuf;
38class DrawMultiBuf;
39} // namespace command
40
43class PassSortable;
44
45class Manager {
46 using ObjectMatricesBuf = StorageArrayBuffer<ObjectMatrices, 128>;
47 using ObjectBoundsBuf = StorageArrayBuffer<ObjectBounds, 128>;
48 using ObjectInfosBuf = StorageArrayBuffer<ObjectInfos, 128>;
49 using ObjectAttributeBuf = StorageArrayBuffer<ObjectAttribute, 128>;
50 using LayerAttributeBuf = UniformArrayBuffer<LayerAttribute, 512>;
55 using ObjectAttributeLegacyBuf = UniformArrayBuffer<float4, 8 * 512>;
56
57 public:
64
73
81
86 ObjectAttributeBuf attributes_buf;
87
92
96 LayerAttributeBuf layer_attributes_buf;
97
103
104 private:
106 static std::atomic<uint32_t> global_sync_counter_;
107
108 /* Local sync counter. Used for fingerprint. Must never be null. */
109 uint32_t sync_counter_ = 1;
110
112 uint resource_len_ = 0;
114 uint attribute_len_ = 0;
115
116 Object *object_active = nullptr;
117
118 public:
120 ~Manager();
121
126 /* WORKAROUND: Instead of breaking const correctness everywhere, we only break it for this. */
128
130
134 ResourceHandleRange resource_handle(const ObjectRef &ref, float inflate_bounds = 0.0f);
140 const float4x4 *model_matrix,
141 const float3 *bounds_center,
142 const float3 *bounds_half_extent);
147 ResourceHandle resource_handle(const float4x4 &model_matrix);
153 ResourceHandle resource_handle(const float4x4 &model_matrix,
154 const float3 &bounds_center,
155 const float3 &bounds_half_extent);
160 ResourceHandle resource_handle_for_psys(const ObjectRef &ref, const float4x4 &model_matrix);
161
164 const ObjectRef &ref,
165 float inflate_bounds = 0.0f);
166
172 const ObjectRef &ref,
173 const GPUMaterial *material);
175 const ObjectRef &ref,
176 Span<GPUMaterial *> materials);
177
182
220
239 void generate_commands(PassMain &pass, View &view);
244 void generate_commands(PassSimple &pass);
245
252
258 void submit_only(PassMain &pass, View &view);
263 void submit(PassSimple &pass, View &view);
264 void submit(PassMain &pass, View &view);
265 void submit(PassSortable &pass, View &view);
269 void submit(PassSimple &pass, bool inverted_view = false);
270
274 SubmitDebugOutput submit_debug(PassSimple &pass, View &view);
275 SubmitDebugOutput submit_debug(PassMain &pass, View &view);
276
280 DataDebugOutput data_debug();
281
291
296 {
297 return resource_len_;
298 }
299
301 void begin_sync(Object *object_active = nullptr);
302 void end_sync();
303
304 void debug_bind();
305 void resource_bind();
306
307 private:
308 void sync_layer_attributes();
309
310 /* Fingerprint of the manager in a certain state. Assured to not be 0.
311 * Not reliable enough for general update detection. Only to be used for debugging assertion. */
312 uint64_t fingerprint_get();
313};
314
316{
317 if (!ref.handle_.is_valid()) {
318 /* WORKAROUND: Instead of breaking const correctness everywhere, we only break it for this. */
319 const_cast<ObjectRef &>(ref).handle_ = resource_handle(ref);
320 }
321 return ref.handle_;
322}
323
324inline ResourceHandleRange Manager::resource_handle(const ObjectRef &ref, float inflate_bounds)
325{
326 bool is_active_object = ref.is_active(object_active);
327 bool is_active_edit_mode = object_active &&
328 (DRW_object_is_in_edit_mode(object_active) ||
329 ELEM(object_active->mode, OB_MODE_TEXTURE_PAINT, OB_MODE_SCULPT)) &&
330 ref.object->mode == object_active->mode;
331 if (ref.duplis_) {
332 uint start = resource_len_;
333
334 ObjectBounds proto_bounds;
335 proto_bounds.sync(*ref.object, inflate_bounds);
336
337 ObjectInfos proto_info;
338 proto_info.sync(ref, is_active_object, is_active_edit_mode);
339
340 for (const DupliObject *dupli : *ref.duplis_) {
341 matrix_buf.current().get_or_resize(resource_len_).sync(float4x4(dupli->mat));
342 bounds_buf.current().get_or_resize(resource_len_) = proto_bounds;
343
344 ObjectInfos &info = infos_buf.current().get_or_resize(resource_len_);
345 info = proto_info;
346 info.random = dupli->random_id * (1.0f / (float)0xFFFFFFFF);
347
348 resource_len_++;
349 }
351 resource_len_ - start);
352 }
353 else {
354 matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object);
355 bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object, inflate_bounds);
356 infos_buf.current()
357 .get_or_resize(resource_len_)
358 .sync(ref, is_active_object, is_active_edit_mode);
359 return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
360 }
361}
362
364 const float4x4 *model_matrix,
365 const float3 *bounds_center,
366 const float3 *bounds_half_extent)
367{
368 BLI_assert(!ref.duplis_);
369 bool is_active_object = ref.is_active(object_active);
370 bool is_active_edit_mode = object_active &&
371 (DRW_object_is_in_edit_mode(object_active) ||
372 ELEM(object_active->mode, OB_MODE_TEXTURE_PAINT, OB_MODE_SCULPT)) &&
373 ref.object->mode == object_active->mode;
374 if (model_matrix) {
375 matrix_buf.current().get_or_resize(resource_len_).sync(*model_matrix);
376 }
377 else {
378 matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object);
379 }
380 if (bounds_center && bounds_half_extent) {
381 bounds_buf.current().get_or_resize(resource_len_).sync(*bounds_center, *bounds_half_extent);
382 }
383 else {
384 bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object);
385 }
386 infos_buf.current()
387 .get_or_resize(resource_len_)
388 .sync(ref, is_active_object, is_active_edit_mode);
389 return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
390}
391
393{
394 matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
395 bounds_buf.current().get_or_resize(resource_len_).sync();
396 infos_buf.current().get_or_resize(resource_len_).sync();
397 return ResourceHandle(resource_len_++, false);
398}
399
401 const float3 &bounds_center,
402 const float3 &bounds_half_extent)
403{
404 matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
405 bounds_buf.current().get_or_resize(resource_len_).sync(bounds_center, bounds_half_extent);
406 infos_buf.current().get_or_resize(resource_len_).sync();
407 return ResourceHandle(resource_len_++, false);
408}
409
411 const float4x4 &model_matrix)
412{
413 BLI_assert(!ref.duplis_);
414 bool is_active_object = ref.is_active(object_active);
415 bool is_active_edit_mode = object_active &&
416 (DRW_object_is_in_edit_mode(object_active) ||
417 ELEM(object_active->mode, OB_MODE_TEXTURE_PAINT, OB_MODE_SCULPT)) &&
418 ref.object->mode == object_active->mode;
419 matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
420 bounds_buf.current().get_or_resize(resource_len_).sync();
421 infos_buf.current()
422 .get_or_resize(resource_len_)
423 .sync(ref, is_active_object, is_active_edit_mode);
424 return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
425}
426
428 const ObjectRef &ref,
429 float inflate_bounds)
430{
431 bounds_buf.current()[handle.resource_index()].sync(*ref.object, inflate_bounds);
432}
433
435 const ObjectRef &ref,
436 const GPUMaterial *material)
437{
438 ObjectInfos &infos = infos_buf.current().get_or_resize(handle.resource_index());
439 infos.object_attrs_offset = attribute_len_;
440
441 const GPUUniformAttrList *attr_list = GPU_material_uniform_attributes(material);
442 if (attr_list == nullptr) {
443 return;
444 }
445
446 LISTBASE_FOREACH (const GPUUniformAttr *, attr, &attr_list->list) {
447 if (attributes_buf.get_or_resize(attribute_len_).sync(ref, *attr)) {
448 infos.object_attrs_len++;
449 attribute_len_++;
450 }
451 }
452}
453
455 const ObjectRef &ref,
456 Span<GPUMaterial *> materials)
457{
458 ObjectInfos &infos = infos_buf.current().get_or_resize(handle.resource_index());
459 infos.object_attrs_offset = attribute_len_;
460
461 /* Simple cache solution to avoid duplicates. */
462 Vector<uint32_t, 4> hash_cache;
463
464 for (const GPUMaterial *mat : materials) {
466 if (attr_list == nullptr) {
467 continue;
468 }
469
470 LISTBASE_FOREACH (const GPUUniformAttr *, attr, &attr_list->list) {
472 if ((mat != materials.first()) && (hash_cache.first_index_of_try(attr->hash_code) != -1)) {
473 /* Attribute has already been added to the attribute buffer by another material. */
474 continue;
475 }
476 hash_cache.append(attr->hash_code);
477 if (attributes_buf.get_or_resize(attribute_len_).sync(ref, *attr)) {
478 infos.object_attrs_len++;
479 attribute_len_++;
480 }
481 }
482 }
483}
484
486{
487 const ListBase *attr_list = GPU_material_layer_attributes(material);
488
489 if (attr_list != nullptr) {
490 LISTBASE_FOREACH (const GPULayerAttr *, attr, attr_list) {
493 layer_attributes.add(attr->hash_code, *attr);
494 }
495 }
496}
497
498} // namespace blender::draw
499
500/* TODO(@fclem): This is for testing. The manager should be passed to the engine through the
501 * callbacks. */
#define BLI_assert(a)
Definition BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
unsigned int uint
#define ELEM(...)
@ OB_MODE_SCULPT
@ OB_MODE_TEXTURE_PAINT
@ OB_NEG_SCALE
static AppView * view
const ListBase * GPU_material_layer_attributes(const GPUMaterial *material)
const GPUUniformAttrList * GPU_material_uniform_attributes(const GPUMaterial *material)
void GPU_texture_ref(blender::gpu::Texture *texture)
unsigned long long int uint64_t
constexpr const T & first() const
Definition BLI_span.hh:315
void append(const T &value)
int64_t first_index_of_try(const T &value) const
LayerAttributeBuf layer_attributes_buf
void begin_sync(Object *object_active=nullptr)
void register_layer_attributes(GPUMaterial *material)
SwapChain< ObjectBoundsBuf, 2 > bounds_buf
SubmitDebugOutput submit_debug(PassSimple &pass, View &view)
ResourceHandle resource_handle_for_psys(const ObjectRef &ref, const float4x4 &model_matrix)
void acquire_texture(gpu::Texture *texture)
ResourceHandleRange unique_handle_for_sculpt(const ObjectRef &ref)
void generate_commands(PassMain &pass, View &view)
void extract_object_attributes(ResourceHandle handle, const ObjectRef &ref, const GPUMaterial *material)
SwapChain< ObjectInfosBuf, 2 > infos_buf
ResourceHandleRange unique_handle(const ObjectRef &ref)
ObjectAttributeBuf attributes_buf
Map< uint32_t, GPULayerAttr > layer_attributes
void compute_visibility(View &view)
uint resource_handle_count() const
void warm_shader_specialization(PassMain &pass)
void submit_only(PassMain &pass, View &view)
void ensure_visibility(View &view)
void update_handle_bounds(ResourceHandle handle, const ObjectRef &ref, float inflate_bounds=0.0f)
SwapChain< ObjectMatricesBuf, 2 > matrix_buf
Vector< gpu::Texture * > acquired_textures
void submit(PassSimple &pass, View &view)
ResourceHandleRange resource_handle(const ObjectRef &ref, float inflate_bounds=0.0f)
DataDebugOutput data_debug()
bool is_active(const Object *active_object) const
nullptr float
bool DRW_object_is_in_edit_mode(const Object *ob)
blender::draw::Manager * DRW_manager_get()
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
detail::Pass< command::DrawCommandBuf > PassSimple
detail::Pass< command::DrawMultiBuf > PassMain
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
float mat[4][4]
unsigned int random_id
short transflag