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_active_edit_mode = object_active &&
331 (DRW_object_is_in_edit_mode(object_active) ||
332 ELEM(object_active->mode, OB_MODE_TEXTURE_PAINT, OB_MODE_SCULPT)) &&
333 ref.object->mode == object_active->mode;
334 matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object);
335 bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object, inflate_bounds);
336 infos_buf.current()
337 .get_or_resize(resource_len_)
338 .sync(ref, is_active_object, is_active_edit_mode);
339 return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
340}
341
343 const float4x4 *model_matrix,
344 const float3 *bounds_center,
345 const float3 *bounds_half_extent)
346{
347 bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active;
348 bool is_active_edit_mode = object_active &&
349 (DRW_object_is_in_edit_mode(object_active) ||
350 ELEM(object_active->mode, OB_MODE_TEXTURE_PAINT, OB_MODE_SCULPT)) &&
351 ref.object->mode == object_active->mode;
352 if (model_matrix) {
353 matrix_buf.current().get_or_resize(resource_len_).sync(*model_matrix);
354 }
355 else {
356 matrix_buf.current().get_or_resize(resource_len_).sync(*ref.object);
357 }
358 if (bounds_center && bounds_half_extent) {
359 bounds_buf.current().get_or_resize(resource_len_).sync(*bounds_center, *bounds_half_extent);
360 }
361 else {
362 bounds_buf.current().get_or_resize(resource_len_).sync(*ref.object);
363 }
364 infos_buf.current()
365 .get_or_resize(resource_len_)
366 .sync(ref, is_active_object, is_active_edit_mode);
367 return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
368}
369
371{
372 matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
373 bounds_buf.current().get_or_resize(resource_len_).sync();
374 infos_buf.current().get_or_resize(resource_len_).sync();
375 return ResourceHandle(resource_len_++, false);
376}
377
379 const float3 &bounds_center,
380 const float3 &bounds_half_extent)
381{
382 matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
383 bounds_buf.current().get_or_resize(resource_len_).sync(bounds_center, bounds_half_extent);
384 infos_buf.current().get_or_resize(resource_len_).sync();
385 return ResourceHandle(resource_len_++, false);
386}
387
389 const float4x4 &model_matrix)
390{
391 bool is_active_object = (ref.dupli_object ? ref.dupli_parent : ref.object) == object_active;
392 bool is_active_edit_mode = object_active &&
393 (DRW_object_is_in_edit_mode(object_active) ||
394 ELEM(object_active->mode, OB_MODE_TEXTURE_PAINT, OB_MODE_SCULPT)) &&
395 ref.object->mode == object_active->mode;
396 matrix_buf.current().get_or_resize(resource_len_).sync(model_matrix);
397 bounds_buf.current().get_or_resize(resource_len_).sync();
398 infos_buf.current()
399 .get_or_resize(resource_len_)
400 .sync(ref, is_active_object, is_active_edit_mode);
401 return ResourceHandle(resource_len_++, (ref.object->transflag & OB_NEG_SCALE) != 0);
402}
403
405 const ObjectRef &ref,
406 float inflate_bounds)
407{
408 bounds_buf.current()[handle.resource_index()].sync(*ref.object, inflate_bounds);
409}
410
412 const float3 &bounds_center,
413 const float3 &bounds_half_extent)
414{
415 bounds_buf.current()[handle.resource_index()].sync(bounds_center, bounds_half_extent);
416}
417
419 const ObjectRef &ref,
420 const GPUMaterial *material)
421{
422 ObjectInfos &infos = infos_buf.current().get_or_resize(handle.resource_index());
423 infos.object_attrs_offset = attribute_len_;
424
425 const GPUUniformAttrList *attr_list = GPU_material_uniform_attributes(material);
426 if (attr_list == nullptr) {
427 return;
428 }
429
430 LISTBASE_FOREACH (const GPUUniformAttr *, attr, &attr_list->list) {
431 if (attributes_buf.get_or_resize(attribute_len_).sync(ref, *attr)) {
432 infos.object_attrs_len++;
433 attribute_len_++;
434 }
435 }
436}
437
439 const ObjectRef &ref,
440 Span<GPUMaterial *> materials)
441{
442 ObjectInfos &infos = infos_buf.current().get_or_resize(handle.resource_index());
443 infos.object_attrs_offset = attribute_len_;
444
445 /* Simple cache solution to avoid duplicates. */
446 Vector<uint32_t, 4> hash_cache;
447
448 for (const GPUMaterial *mat : materials) {
450 if (attr_list == nullptr) {
451 continue;
452 }
453
454 LISTBASE_FOREACH (const GPUUniformAttr *, attr, &attr_list->list) {
456 if ((mat != materials.first()) && (hash_cache.first_index_of_try(attr->hash_code) != -1)) {
457 /* Attribute has already been added to the attribute buffer by another material. */
458 continue;
459 }
460 hash_cache.append(attr->hash_code);
461 if (attributes_buf.get_or_resize(attribute_len_).sync(ref, *attr)) {
462 infos.object_attrs_len++;
463 attribute_len_++;
464 }
465 }
466 }
467}
468
470{
471 const ListBase *attr_list = GPU_material_layer_attributes(material);
472
473 if (attr_list != nullptr) {
474 LISTBASE_FOREACH (const GPULayerAttr *, attr, attr_list) {
477 layer_attributes.add(attr->hash_code, *attr);
478 }
479 }
480}
481
482} // namespace blender::draw
483
484/* TODO(@fclem): This is for testing. The manager should be passed to the engine through the
485 * callbacks. */
#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(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