Blender V5.0
draw_command.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
15
16#include "BKE_global.hh"
17#include "BLI_map.hh"
18#include "BLI_math_base.h"
19#include "DRW_gpu_wrapper.hh"
20
21#include "GPU_index_buffer.hh"
23#include "draw_handle.hh"
24#include "draw_state.hh"
25#include "draw_view.hh"
26
27/* Forward declarations. */
29template<typename T, int64_t block_size> class SubPassVector;
30template<typename DrawCommandBufType> class PassBase;
31} // namespace blender::draw::detail
32
33namespace blender::draw::command {
34
35class DrawCommandBuf;
36class DrawMultiBuf;
37
38/* -------------------------------------------------------------------- */
41
48 /* True if specialization_constants was set. */
50 /* True if the bound shader uses specialization. */
52 gpu::Shader *shader = nullptr;
53 bool front_facing = true;
54 bool inverted_view = false;
59
60 void front_facing_set(bool facing)
61 {
62 /* Facing is inverted if view is not in expected handedness. */
63 facing = this->inverted_view == facing;
64 /* Remove redundant changes. */
65 if (assign_if_different(this->front_facing, facing)) {
66 GPU_front_facing(!facing);
67 }
68 }
69
70 void cleanup()
71 {
72 if (front_facing == false) {
73 GPU_front_facing(false);
74 }
75
76 if (G.debug & G_DEBUG_GPU) {
81 }
82 }
83
88};
89
91
92/* -------------------------------------------------------------------- */
95
124
136
139
140 void execute(RecordingState &state) const;
141 std::string serialize() const;
142};
143
146
147 void execute() const;
148 std::string serialize() const;
149};
150
153 uint8_t depth_state;
155 uint8_t color_states[8];
156
157 void execute() const;
158 std::string serialize() const;
159};
160
163 int slot;
165
176
177 union {
191 };
192
193 ResourceBind() = default;
194
196 : slot(slot_), is_reference(false), type(Type::UniformBuf), uniform_buf(res) {};
200 : slot(slot_), is_reference(false), type(Type::StorageBuf), storage_buf(res) {};
203 ResourceBind(int slot_, gpu::UniformBuf *res, Type /*type*/)
205 ResourceBind(int slot_, gpu::UniformBuf **res, Type /*type*/)
207 ResourceBind(int slot_, gpu::VertBuf *res, Type /*type*/)
209 ResourceBind(int slot_, gpu::VertBuf **res, Type /*type*/)
211 ResourceBind(int slot_, gpu::IndexBuf *res, Type /*type*/)
213 ResourceBind(int slot_, gpu::IndexBuf **res, Type /*type*/)
215 ResourceBind(int slot_, draw::Image *res)
216 : slot(slot_), is_reference(false), type(Type::Image), texture(draw::as_texture(res)) {};
217 ResourceBind(int slot_, draw::Image **res)
218 : slot(slot_), is_reference(true), type(Type::Image), texture_ref(draw::as_texture(res)) {};
223 ResourceBind(int slot_, gpu::VertBuf *res)
224 : slot(slot_), is_reference(false), type(Type::BufferSampler), vertex_buf(res) {};
225 ResourceBind(int slot_, gpu::VertBuf **res)
227
228 void execute() const;
229 std::string serialize() const;
230};
231
234 uint8_t array_len;
235 uint8_t comp_len;
248 union {
257 const int *int_ref;
261 const float *float_ref;
266 };
267
268 PushConstant() = default;
269
270 PushConstant(int loc, const float &val)
271 : location(loc), array_len(1), comp_len(1), type(Type::FloatValue), float1_value(val) {};
272 PushConstant(int loc, const float2 &val)
273 : location(loc), array_len(1), comp_len(2), type(Type::FloatValue), float2_value(val) {};
274 PushConstant(int loc, const float3 &val)
275 : location(loc), array_len(1), comp_len(3), type(Type::FloatValue), float3_value(val) {};
276 PushConstant(int loc, const float4 &val)
277 : location(loc), array_len(1), comp_len(4), type(Type::FloatValue), float4_value(val) {};
278
279 PushConstant(int loc, const int &val)
280 : location(loc), array_len(1), comp_len(1), type(Type::IntValue), int1_value(val) {};
281 PushConstant(int loc, const int2 &val)
282 : location(loc), array_len(1), comp_len(2), type(Type::IntValue), int2_value(val) {};
283 PushConstant(int loc, const int3 &val)
284 : location(loc), array_len(1), comp_len(3), type(Type::IntValue), int3_value(val) {};
285 PushConstant(int loc, const int4 &val)
286 : location(loc), array_len(1), comp_len(4), type(Type::IntValue), int4_value(val) {};
287
288 PushConstant(int loc, const float *val, int arr)
289 : location(loc), array_len(arr), comp_len(1), type(Type::FloatReference), float_ref(val) {};
290 PushConstant(int loc, const float2 *val, int arr)
291 : location(loc), array_len(arr), comp_len(2), type(Type::FloatReference), float2_ref(val) {};
292 PushConstant(int loc, const float3 *val, int arr)
293 : location(loc), array_len(arr), comp_len(3), type(Type::FloatReference), float3_ref(val) {};
294 PushConstant(int loc, const float4 *val, int arr)
295 : location(loc), array_len(arr), comp_len(4), type(Type::FloatReference), float4_ref(val) {};
296 PushConstant(int loc, const float4x4 *val)
298 };
299
300 PushConstant(int loc, const int *val, int arr)
301 : location(loc), array_len(arr), comp_len(1), type(Type::IntReference), int_ref(val) {};
302 PushConstant(int loc, const int2 *val, int arr)
303 : location(loc), array_len(arr), comp_len(2), type(Type::IntReference), int2_ref(val) {};
304 PushConstant(int loc, const int3 *val, int arr)
305 : location(loc), array_len(arr), comp_len(3), type(Type::IntReference), int3_ref(val) {};
306 PushConstant(int loc, const int4 *val, int arr)
307 : location(loc), array_len(arr), comp_len(4), type(Type::IntReference), int4_ref(val) {};
308
309 void execute(RecordingState &state) const;
310 std::string serialize() const;
311};
312
314 /* Shader to set the constant in. */
316 /* Value of the constant or a reference to it. */
317 union {
322 const int *int_ref;
324 const float *float_ref;
325 const bool *bool_ref;
326 };
327
329
340
342
343 SpecializeConstant(gpu::Shader *sh, int loc, const float &val)
344 : shader(sh), float_value(val), location(loc), type(Type::FloatValue) {};
345 SpecializeConstant(gpu::Shader *sh, int loc, const int &val)
346 : shader(sh), int_value(val), location(loc), type(Type::IntValue) {};
347 SpecializeConstant(gpu::Shader *sh, int loc, const uint &val)
348 : shader(sh), uint_value(val), location(loc), type(Type::UintValue) {};
349 SpecializeConstant(gpu::Shader *sh, int loc, const bool &val)
350 : shader(sh), bool_value(val), location(loc), type(Type::BoolValue) {};
351 SpecializeConstant(gpu::Shader *sh, int loc, const float *val)
352 : shader(sh), float_ref(val), location(loc), type(Type::FloatReference) {};
353 SpecializeConstant(gpu::Shader *sh, int loc, const int *val)
354 : shader(sh), int_ref(val), location(loc), type(Type::IntReference) {};
355 SpecializeConstant(gpu::Shader *sh, int loc, const uint *val)
356 : shader(sh), uint_ref(val), location(loc), type(Type::UintReference) {};
357 SpecializeConstant(gpu::Shader *sh, int loc, const bool *val)
358 : shader(sh), bool_ref(val), location(loc), type(Type::BoolReference) {};
359
360 void execute(RecordingState &state) const;
361 std::string serialize() const;
362};
363
364struct Draw {
365 gpu::Batch *batch;
366 uint16_t instance_len;
367 uint8_t expand_prim_type; /* #GPUPrimType */
369 uint32_t vertex_first;
370 uint32_t vertex_len;
372
373 Draw() = default;
374
375 Draw(gpu::Batch *batch,
379 GPUPrimType expanded_prim_type,
380 uint expanded_prim_len,
382 {
383 BLI_assert(batch != nullptr);
384 this->batch = batch;
385 this->res_index = res_index;
386 this->instance_len = uint16_t(min_uu(instance_len, USHRT_MAX));
387 this->vertex_len = vertex_len;
388 this->vertex_first = vertex_first;
389 this->expand_prim_type = expanded_prim_type;
390 this->expand_prim_len = expanded_prim_len;
391 }
392
394 {
396 }
397
398 void execute(RecordingState &state) const;
399 std::string serialize() const;
400};
401
402struct DrawMulti {
403 gpu::Batch *batch;
407
408 void execute(RecordingState &state) const;
409 std::string serialize(const std::string &line_prefix) const;
410};
411
413 gpu::Batch *batch;
416
417 void execute(RecordingState &state) const;
418 std::string serialize() const;
419};
420
421struct Dispatch {
423 union {
426 };
427
428 Dispatch() = default;
429
430 Dispatch(int3 group_len) : is_reference(false), size(group_len) {};
431 Dispatch(int3 *group_len) : is_reference(true), size_ref(group_len) {};
432
433 void execute(RecordingState &state) const;
434 std::string serialize() const;
435};
436
439
440 void execute(RecordingState &state) const;
441 std::string serialize() const;
442};
443
444struct Barrier {
446
447 void execute() const;
448 std::string serialize() const;
449};
450
451struct Clear {
452 uint8_t clear_channels; /* #GPUFrameBufferBits. But want to save some bits. */
453 uint8_t stencil;
454 float depth;
456
457 void execute() const;
458 std::string serialize() const;
459};
460
465
466 void execute() const;
467 std::string serialize() const;
468};
469
470struct StateSet {
473
474 void execute(RecordingState &state) const;
475 std::string serialize() const;
476
477 /* Set state of the GPU module manually. */
478 static void set(DRWState state = DRW_STATE_DEFAULT);
479};
480
485
486 void execute() const;
487 std::string serialize() const;
488};
489
508
510
511BLI_STATIC_ASSERT(sizeof(Undetermined) <= 24, "One of the command type is too large.")
512
513
514
515/* -------------------------------------------------------------------- */
524
526 friend Manager;
527
528 private:
529 using ResourceIdBuf = StorageArrayBuffer<uint, 128, false>;
531
533 ResourceIdBuf resource_id_buf_;
535 uint resource_id_count_ = 0;
536
537 public:
538 void clear()
539 {
540 resource_id_buf_.trim_to_next_power_of_2(resource_id_count_);
541 };
542
544 Vector<Undetermined, 0> &commands,
545 gpu::Batch *batch,
546 uint instance_len,
547 uint vertex_len,
548 uint vertex_first,
549 ResourceIndexRange index_range,
550 uint custom_id,
551 GPUPrimType expanded_prim_type,
552 uint16_t expanded_prim_len)
553 {
554 BLI_assert(batch != nullptr);
555 vertex_first = vertex_first != -1 ? vertex_first : 0;
556 instance_len = instance_len != -1 ? instance_len : 1;
557
558 BLI_assert_msg(custom_id == 0, "Custom ID is not supported in PassSimple");
559 UNUSED_VARS_NDEBUG(custom_id);
560
561 for (auto res_index : index_range.index_range()) {
562 int64_t index = commands.append_and_get_index({});
563 headers.append({Type::Draw, uint(index)});
564 commands[index].draw = {batch,
565 instance_len,
566 vertex_len,
567 vertex_first,
568 expanded_prim_type,
569 expanded_prim_len,
570 ResourceIndex(res_index)};
571 }
572 }
573
574 void generate_commands(Vector<Header, 0> &headers,
575 Vector<Undetermined, 0> &commands,
576 SubPassVector &sub_passes);
577
578 void bind(RecordingState &state);
579
580 private:
581 static void finalize_commands(Vector<Header, 0> &headers,
582 Vector<Undetermined, 0> &commands,
583 SubPassVector &sub_passes,
584 uint &resource_id_count,
585 ResourceIdBuf &resource_id_buf);
586};
587
589
590/* -------------------------------------------------------------------- */
617
619 friend Manager;
620 friend DrawMulti;
621
622 private:
623 using DrawGroupBuf = StorageArrayBuffer<DrawGroup, 16>;
624 using DrawPrototypeBuf = StorageArrayBuffer<DrawPrototype, 16>;
625 using DrawCommandBuf = StorageArrayBuffer<DrawCommand, 16, true>;
626 using ResourceIdBuf = StorageArrayBuffer<uint, 128, true>;
627
628 using DrawGroupKey = std::pair<uint, gpu::Batch *>;
629 using DrawGroupMap = Map<DrawGroupKey, uint>;
631 DrawGroupMap group_ids_;
632
634 DrawGroupBuf group_buf_ = {"DrawGroupBuf"};
636 DrawPrototypeBuf prototype_buf_ = {"DrawPrototypeBuf"};
638 DrawCommandBuf command_buf_ = {"DrawCommandBuf"};
640 ResourceIdBuf resource_id_buf_ = {"ResourceIdBuf"};
642 uint header_id_counter_ = 0;
644 uint group_count_ = 0;
646 uint prototype_count_ = 0;
648 uint resource_id_count_ = 0;
649
650 public:
651 void clear()
652 {
653 group_buf_.trim_to_next_power_of_2(group_count_);
654 /* Two commands per group (inverted and non-inverted scale). */
655 command_buf_.trim_to_next_power_of_2(group_count_ * 2);
656 prototype_buf_.trim_to_next_power_of_2(prototype_count_);
657 resource_id_buf_.trim_to_next_power_of_2(resource_id_count_);
658 header_id_counter_ = 0;
659 group_count_ = 0;
660 prototype_count_ = 0;
661 group_ids_.clear();
662 }
663
665 Vector<Undetermined, 0> &commands,
666 gpu::Batch *batch,
667 uint instance_len,
668 uint vertex_len,
669 uint vertex_first,
670 ResourceIndexRange index_range,
671 uint custom_id,
672 GPUPrimType expanded_prim_type,
673 uint16_t expanded_prim_len)
674 {
675 BLI_assert(batch != nullptr);
676 /* Custom draw-calls cannot be batched and will produce one group per draw. */
677 const bool custom_group = ((vertex_first != 0 && vertex_first != -1) || vertex_len != -1);
678
679 BLI_assert(vertex_len != 0);
680 vertex_len = vertex_len == -1 ? 0 : vertex_len;
681 instance_len = instance_len != -1 ? instance_len : 1;
682
683 /* If there was some state changes since previous call, we have to create another command. */
684 if (headers.is_empty() || headers.last().type != Type::DrawMulti) {
685 uint index = commands.append_and_get_index({});
686 headers.append({Type::DrawMulti, index});
687 commands[index].draw_multi = {batch, this, (uint)-1, header_id_counter_++};
688 }
689
690 DrawMulti &cmd = commands.last().draw_multi;
691
692 uint &group_id = group_ids_.lookup_or_add(DrawGroupKey(cmd.uuid, batch), uint(-1));
693
694 bool inverted = index_range.has_inverted_handedness();
695
696 for (auto res_index : index_range.index_range()) {
697 DrawPrototype &draw = prototype_buf_.get_or_resize(prototype_count_++);
698 draw.res_index = uint32_t(res_index);
699 draw.custom_id = custom_id;
700 draw.instance_len = instance_len;
701 draw.group_id = group_id;
702
703 if (group_id == uint(-1) || custom_group) {
704 uint new_group_id = group_count_++;
705 draw.group_id = new_group_id;
706
707 DrawGroup &group = group_buf_.get_or_resize(new_group_id);
708 group.next = cmd.group_first;
709 group.len = instance_len;
710 group.front_facing_len = inverted ? 0 : instance_len;
711 group.front_facing_counter = 0;
712 group.back_facing_counter = 0;
713 group.desc.vertex_len = vertex_len;
714 group.desc.vertex_first = vertex_first;
715 group.desc.gpu_batch = batch;
716 group.desc.expand_prim_type = expanded_prim_type;
717 group.desc.expand_prim_len = expanded_prim_len;
718 BLI_assert_msg(expanded_prim_len < (1 << 3),
719 "Not enough bits to store primitive expansion");
720 /* Custom group are not to be registered in the group_ids_. */
721 if (!custom_group) {
722 group_id = new_group_id;
723 }
724 /* For serialization only. Reset before use on GPU. */
725 (inverted ? group.back_facing_counter : group.front_facing_counter)++;
726 /* Append to list. */
727 cmd.group_first = new_group_id;
728 }
729 else {
730 DrawGroup &group = group_buf_[group_id];
731 group.len += instance_len;
732 group.front_facing_len += inverted ? 0 : instance_len;
733 /* For serialization only. Reset before use on GPU. */
734 (inverted ? group.back_facing_counter : group.front_facing_counter)++;
735 /* NOTE: We assume that primitive expansion is coupled to the shader itself. Meaning we
736 * rely on shader bind to isolate the expanded draws into their own group (as there could
737 * be regular draws and extended draws using the same batch mixed inside the same pass).
738 * This will cause issues if this assumption is broken. Also it is very hard to detect this
739 * case for error checking. At least we can check that expansion settings don't change
740 * inside a group. */
741 BLI_assert(group.desc.expand_prim_type == expanded_prim_type);
742 BLI_assert(group.desc.expand_prim_len == expanded_prim_len);
743 }
744 }
745 }
746
748 Vector<Undetermined, 0> &commands,
749 VisibilityBuf &visibility_buf,
750 int visibility_word_per_draw,
751 int view_len,
752 bool use_custom_ids);
753
755};
756
758
759}; // namespace blender::draw::command
@ G_DEBUG_GPU
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
MINLINE uint min_uu(uint a, uint b)
unsigned int uint
#define UNUSED_VARS_NDEBUG(...)
GPUPrimType
@ GPU_PRIM_NONE
GPUBarrier
Definition GPU_state.hh:29
void GPU_front_facing(bool invert)
Definition gpu_state.cc:58
void GPU_storagebuf_debug_unbind_all()
void GPU_texture_image_unbind_all()
void GPU_texture_unbind_all()
void GPU_uniformbuf_debug_unbind_all()
return true
long long int int64_t
int64_t append_and_get_index(const T &value)
void append(const T &value)
const T & last(const int64_t n=0) const
bool is_empty() const
void append_draw(Vector< Header, 0 > &headers, Vector< Undetermined, 0 > &commands, gpu::Batch *batch, uint instance_len, uint vertex_len, uint vertex_first, ResourceIndexRange index_range, uint custom_id, GPUPrimType expanded_prim_type, uint16_t expanded_prim_len)
void append_draw(Vector< Header, 0 > &headers, Vector< Undetermined, 0 > &commands, gpu::Batch *batch, uint instance_len, uint vertex_len, uint vertex_first, ResourceIndexRange index_range, uint custom_id, GPUPrimType expanded_prim_type, uint16_t expanded_prim_len)
void generate_commands(Vector< Header, 0 > &headers, Vector< Undetermined, 0 > &commands, VisibilityBuf &visibility_buf, int visibility_word_per_draw, int view_len, bool use_custom_ids)
void bind(RecordingState &state)
DRWState
Definition draw_state.hh:25
@ DRW_STATE_NO_DRAW
Definition draw_state.hh:27
#define DRW_STATE_DEFAULT
Definition draw_state.hh:79
struct @021025263243242147216143265077100330027142264337::@225245033123204053237120173316075113304004012000 batch
static ulong state[N]
#define G(x, y, z)
static gpu::Texture * as_texture(Image *img)
BLI_STATIC_ASSERT(MBC_BATCH_LEN< 64, "Number of batches exceeded the limit of bit fields")
StorageArrayBuffer< uint, 4, true > VisibilityBuf
Definition draw_view.hh:35
VecBase< int32_t, 4 > int4
bool assign_if_different(T &old_value, T new_value)
MatBase< float, 4, 4 > float4x4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
std::string serialize() const
void execute(RecordingState &state) const
void execute(RecordingState &state) const
struct blender::draw::command::DrawGroup::@065172161005140006364026044166345126204356255202 desc
void execute(RecordingState &state) const
std::string serialize(const std::string &line_prefix) const
void execute(RecordingState &state) const
void execute(RecordingState &state) const
std::string serialize() const
Draw(gpu::Batch *batch, uint instance_len, uint vertex_len, uint vertex_first, GPUPrimType expanded_prim_type, uint expanded_prim_len, ResourceIndex res_index)
PushConstant(int loc, const float4x4 *val)
PushConstant(int loc, const float3 *val, int arr)
PushConstant(int loc, const int3 *val, int arr)
void execute(RecordingState &state) const
PushConstant(int loc, const int4 *val, int arr)
PushConstant(int loc, const float2 *val, int arr)
PushConstant(int loc, const int3 &val)
enum blender::draw::command::PushConstant::Type type
PushConstant(int loc, const float3 &val)
PushConstant(int loc, const int2 &val)
PushConstant(int loc, const int &val)
PushConstant(int loc, const int2 *val, int arr)
PushConstant(int loc, const float *val, int arr)
PushConstant(int loc, const float4 &val)
PushConstant(int loc, const float2 &val)
PushConstant(int loc, const float4 *val, int arr)
PushConstant(int loc, const float &val)
PushConstant(int loc, const int *val, int arr)
PushConstant(int loc, const int4 &val)
gpu::shader::SpecializationConstants specialization_constants
const gpu::shader::SpecializationConstants * specialization_constants_get()
ResourceBind(int slot_, gpu::VertBuf **res, Type)
enum blender::draw::command::ResourceBind::Type type
ResourceBind(int slot_, draw::Image *res)
ResourceBind(int slot_, gpu::StorageBuf **res)
ResourceBind(int slot_, gpu::VertBuf *res)
ResourceBind(int slot_, gpu::UniformBuf *res)
ResourceBind(int slot_, gpu::Texture **res, GPUSamplerState state)
ResourceBind(int slot_, gpu::UniformBuf **res)
ResourceBind(int slot_, gpu::UniformBuf **res, Type)
ResourceBind(int slot_, gpu::Texture *res, GPUSamplerState state)
ResourceBind(int slot_, draw::Image **res)
ResourceBind(int slot_, gpu::VertBuf **res)
ResourceBind(int slot_, gpu::IndexBuf *res, Type)
ResourceBind(int slot_, gpu::StorageBuf *res)
ResourceBind(int slot_, gpu::UniformBuf *res, Type)
ResourceBind(int slot_, gpu::VertBuf *res, Type)
ResourceBind(int slot_, gpu::IndexBuf **res, Type)
void execute(RecordingState &state) const
SpecializeConstant(gpu::Shader *sh, int loc, const uint *val)
SpecializeConstant(gpu::Shader *sh, int loc, const int &val)
SpecializeConstant(gpu::Shader *sh, int loc, const bool *val)
SpecializeConstant(gpu::Shader *sh, int loc, const float *val)
void execute(RecordingState &state) const
SpecializeConstant(gpu::Shader *sh, int loc, const uint &val)
SpecializeConstant(gpu::Shader *sh, int loc, const bool &val)
SpecializeConstant(gpu::Shader *sh, int loc, const int *val)
enum blender::draw::command::SpecializeConstant::Type type
SpecializeConstant(gpu::Shader *sh, int loc, const float &val)
void execute(RecordingState &state) const
static void set(DRWState state=DRW_STATE_DEFAULT)