Blender V4.5
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
130 /* WORKAROUND: Instead of breaking const correctness everywhere, we only break it for this. */
131 ResourceHandleRange resource_handle(const ObjectRef &ref, float inflate_bounds = 0.0f);
137 const float4x4 *model_matrix,
138 const float3 *bounds_center,
139 const float3 *bounds_half_extent);
144 ResourceHandle resource_handle(const float4x4 &model_matrix);
150 ResourceHandle resource_handle(const float4x4 &model_matrix,
151 const float3 &bounds_center,
152 const float3 &bounds_half_extent);
157 ResourceHandle resource_handle_for_psys(const ObjectRef &ref, const float4x4 &model_matrix);
158
160
163 const ObjectRef &ref,
164 float inflate_bounds = 0.0f);
167 const float3 &bounds_center,
168 const float3 &bounds_half_extent);
169
175 const ObjectRef &ref,
176 const GPUMaterial *material);
178 const ObjectRef &ref,
179 Span<GPUMaterial *> materials);
180
185
223
242 void generate_commands(PassMain &pass, View &view);
247 void generate_commands(PassSimple &pass);
248
255
261 void submit_only(PassMain &pass, View &view);
266 void submit(PassSimple &pass, View &view);
267 void submit(PassMain &pass, View &view);
268 void submit(PassSortable &pass, View &view);
272 void submit(PassSimple &pass, bool inverted_view = false);
273
277 SubmitDebugOutput submit_debug(PassSimple &pass, View &view);
278 SubmitDebugOutput submit_debug(PassMain &pass, View &view);
279
283 DataDebugOutput data_debug();
284
289 void acquire_texture(GPUTexture *texture)
290 {
293 }
294
299 {
300 return resource_len_;
301 }
302
304 void begin_sync(Object *object_active = nullptr);
305 void end_sync();
306
307 void debug_bind();
308 void resource_bind();
309
310 private:
311 void sync_layer_attributes();
312
313 /* Fingerprint of the manager in a certain state. Assured to not be 0.
314 * Not reliable enough for general update detection. Only to be used for debugging assertion. */
315 uint64_t fingerprint_get();
316};
317
319{
320 if (ref.handle.handle_first.raw == 0) {
321 /* WORKAROUND: Instead of breaking const correctness everywhere, we only break it for this. */
322 const_cast<ObjectRef &>(ref).handle = resource_handle(ref);
323 }
324 return ref.handle;
325}
326
327inline ResourceHandleRange Manager::resource_handle(const ObjectRef &ref, float inflate_bounds)
328{
329 bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active;
330 bool is_edit_mode = object_active && DRW_object_is_in_edit_mode(object_active) &&
331 ref.object->mode == object_active->mode;
332 matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object);
333 bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object, inflate_bounds);
334 infos_buf.current().get_or_resize(resource_len_).sync(ref, is_active_object, is_edit_mode);
335 return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
336}
337
339 const float4x4 *model_matrix,
340 const float3 *bounds_center,
341 const float3 *bounds_half_extent)
342{
343 bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active;
344 bool is_edit_mode = object_active && DRW_object_is_in_edit_mode(object_active) &&
345 ref.object->mode == object_active->mode;
346 if (model_matrix) {
347 matrix_buf.current().get_or_resize(resource_len_).sync(*model_matrix);
348 }
349 else {
350 matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object);
351 }
352 if (bounds_center && bounds_half_extent) {
353 bounds_buf.current().get_or_resize(resource_len_).sync(*bounds_center, *bounds_half_extent);
354 }
355 else {
356 bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object);
357 }
358 infos_buf.current().get_or_resize(resource_len_).sync(ref, is_active_object, is_edit_mode);
359 return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
360}
361
363{
364 matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
365 bounds_buf.current().get_or_resize(resource_len_).sync();
366 infos_buf.current().get_or_resize(resource_len_).sync();
367 return ResourceHandle(resource_len_++, false);
368}
369
371 const float3 &bounds_center,
372 const float3 &bounds_half_extent)
373{
374 matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
375 bounds_buf.current().get_or_resize(resource_len_).sync(bounds_center, bounds_half_extent);
376 infos_buf.current().get_or_resize(resource_len_).sync();
377 return ResourceHandle(resource_len_++, false);
378}
379
381 const float4x4 &model_matrix)
382{
383 bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active;
384 bool matches_active_object_edit_mode = object_active &&
385 object_active->mode == eObjectMode::OB_MODE_EDIT &&
386 ref.object->mode == object_active->mode;
387 matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
388 bounds_buf.current().get_or_resize(resource_len_).sync();
389 infos_buf.current()
390 .get_or_resize(resource_len_)
391 .sync(ref, is_active_object, matches_active_object_edit_mode);
392 return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
393}
394
396 const ObjectRef &ref,
397 float inflate_bounds)
398{
399 bounds_buf.current()[handle.resource_index()].sync(*ref.object, inflate_bounds);
400}
401
403 const float3 &bounds_center,
404 const float3 &bounds_half_extent)
405{
406 bounds_buf.current()[handle.resource_index()].sync(bounds_center, bounds_half_extent);
407}
408
410 const ObjectRef &ref,
411 const GPUMaterial *material)
412{
413 ObjectInfos &infos = infos_buf.current().get_or_resize(handle.resource_index());
414 infos.object_attrs_offset = attribute_len_;
415
416 const GPUUniformAttrList *attr_list = GPU_material_uniform_attributes(material);
417 if (attr_list == nullptr) {
418 return;
419 }
420
421 LISTBASE_FOREACH (const GPUUniformAttr *, attr, &attr_list->list) {
422 if (attributes_buf.get_or_resize(attribute_len_).sync(ref, *attr)) {
423 infos.object_attrs_len++;
424 attribute_len_++;
425 }
426 }
427}
428
430 const ObjectRef &ref,
431 Span<GPUMaterial *> materials)
432{
433 ObjectInfos &infos = infos_buf.current().get_or_resize(handle.resource_index());
434 infos.object_attrs_offset = attribute_len_;
435
436 /* Simple cache solution to avoid duplicates. */
437 Vector<uint32_t, 4> hash_cache;
438
439 for (const GPUMaterial *mat : materials) {
441 if (attr_list == nullptr) {
442 continue;
443 }
444
445 LISTBASE_FOREACH (const GPUUniformAttr *, attr, &attr_list->list) {
447 if ((mat != materials.first()) && (hash_cache.first_index_of_try(attr->hash_code) != -1)) {
448 /* Attribute has already been added to the attribute buffer by another material. */
449 continue;
450 }
451 hash_cache.append(attr->hash_code);
452 if (attributes_buf.get_or_resize(attribute_len_).sync(ref, *attr)) {
453 infos.object_attrs_len++;
454 attribute_len_++;
455 }
456 }
457 }
458}
459
461{
462 const ListBase *attr_list = GPU_material_layer_attributes(material);
463
464 if (attr_list != nullptr) {
465 LISTBASE_FOREACH (const GPULayerAttr *, attr, attr_list) {
468 layer_attributes.add(attr->hash_code, *attr);
469 }
470 }
471}
472
473} // namespace blender::draw
474
475/* TODO(@fclem): This is for testing. The manager should be passed to the engine through the
476 * callbacks. */
#define LISTBASE_FOREACH(type, var, list)
unsigned int uint
@ 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(GPUTexture *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 acquire_texture(GPUTexture *texture)
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 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
Vector< GPUTexture * > acquired_textures
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
ResourceHandleRange resource_handle_for_sculpt(const ObjectRef &ref)
void submit(PassSimple &pass, View &view)
ResourceHandleRange resource_handle(const ObjectRef &ref, float inflate_bounds=0.0f)
DataDebugOutput data_debug()
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
short transflag
DupliObject * dupli_object
ResourceHandleRange handle