Blender V4.5
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 GPUShader *shader = nullptr;
53 bool front_facing = true;
54 bool inverted_view = false;
58 GPUStorageBuf *resource_id_buf = nullptr;
61
62 void front_facing_set(bool facing)
63 {
64 /* Facing is inverted if view is not in expected handedness. */
65 facing = this->inverted_view == facing;
66 /* Remove redundant changes. */
67 if (assign_if_different(this->front_facing, facing)) {
68 GPU_front_facing(!facing);
69 }
70 }
71
72 void cleanup()
73 {
74 if (front_facing == false) {
75 GPU_front_facing(false);
76 }
77
78 if (G.debug & G_DEBUG_GPU) {
83 }
84 }
85
90};
91
93
94/* -------------------------------------------------------------------- */
97
126
138
140 GPUShader *shader;
141
142 void execute(RecordingState &state) const;
143 std::string serialize() const;
144};
145
147 GPUFrameBuffer **framebuffer;
148
149 void execute() const;
150 std::string serialize() const;
151};
152
155 uint8_t depth_state;
157 uint8_t color_states[8];
158
159 void execute() const;
160 std::string serialize() const;
161};
162
165 int slot;
167
178
179 union {
182 GPUUniformBuf *uniform_buf;
183 GPUUniformBuf **uniform_buf_ref;
184 GPUStorageBuf *storage_buf;
185 GPUStorageBuf **storage_buf_ref;
187 GPUTexture *texture;
188 GPUTexture **texture_ref;
193 };
194
195 ResourceBind() = default;
196
197 ResourceBind(int slot_, GPUUniformBuf *res)
198 : slot(slot_), is_reference(false), type(Type::UniformBuf), uniform_buf(res){};
199 ResourceBind(int slot_, GPUUniformBuf **res)
201 ResourceBind(int slot_, GPUStorageBuf *res)
202 : slot(slot_), is_reference(false), type(Type::StorageBuf), storage_buf(res){};
203 ResourceBind(int slot_, GPUStorageBuf **res)
205 ResourceBind(int slot_, GPUUniformBuf *res, Type /*type*/)
207 ResourceBind(int slot_, GPUUniformBuf **res, Type /*type*/)
209 ResourceBind(int slot_, gpu::VertBuf *res, Type /*type*/)
211 ResourceBind(int slot_, gpu::VertBuf **res, Type /*type*/)
213 ResourceBind(int slot_, gpu::IndexBuf *res, Type /*type*/)
215 ResourceBind(int slot_, gpu::IndexBuf **res, Type /*type*/)
217 ResourceBind(int slot_, draw::Image *res)
218 : slot(slot_), is_reference(false), type(Type::Image), texture(draw::as_texture(res)){};
219 ResourceBind(int slot_, draw::Image **res)
221 ResourceBind(int slot_, GPUTexture *res, GPUSamplerState state)
222 : sampler(state), slot(slot_), is_reference(false), type(Type::Sampler), texture(res){};
223 ResourceBind(int slot_, GPUTexture **res, GPUSamplerState state)
225 ResourceBind(int slot_, gpu::VertBuf *res)
229
230 void execute() const;
231 std::string serialize() const;
232};
233
236 uint8_t array_len;
237 uint8_t comp_len;
250 union {
259 const int *int_ref;
263 const float *float_ref;
268 };
269
270 PushConstant() = default;
271
272 PushConstant(int loc, const float &val)
273 : location(loc), array_len(1), comp_len(1), type(Type::FloatValue), float1_value(val){};
274 PushConstant(int loc, const float2 &val)
275 : location(loc), array_len(1), comp_len(2), type(Type::FloatValue), float2_value(val){};
276 PushConstant(int loc, const float3 &val)
277 : location(loc), array_len(1), comp_len(3), type(Type::FloatValue), float3_value(val){};
278 PushConstant(int loc, const float4 &val)
279 : location(loc), array_len(1), comp_len(4), type(Type::FloatValue), float4_value(val){};
280
281 PushConstant(int loc, const int &val)
282 : location(loc), array_len(1), comp_len(1), type(Type::IntValue), int1_value(val){};
283 PushConstant(int loc, const int2 &val)
284 : location(loc), array_len(1), comp_len(2), type(Type::IntValue), int2_value(val){};
285 PushConstant(int loc, const int3 &val)
286 : location(loc), array_len(1), comp_len(3), type(Type::IntValue), int3_value(val){};
287 PushConstant(int loc, const int4 &val)
288 : location(loc), array_len(1), comp_len(4), type(Type::IntValue), int4_value(val){};
289
290 PushConstant(int loc, const float *val, int arr)
291 : location(loc), array_len(arr), comp_len(1), type(Type::FloatReference), float_ref(val){};
292 PushConstant(int loc, const float2 *val, int arr)
293 : location(loc), array_len(arr), comp_len(2), type(Type::FloatReference), float2_ref(val){};
294 PushConstant(int loc, const float3 *val, int arr)
295 : location(loc), array_len(arr), comp_len(3), type(Type::FloatReference), float3_ref(val){};
296 PushConstant(int loc, const float4 *val, int arr)
297 : location(loc), array_len(arr), comp_len(4), type(Type::FloatReference), float4_ref(val){};
298 PushConstant(int loc, const float4x4 *val)
300
301 PushConstant(int loc, const int *val, int arr)
302 : location(loc), array_len(arr), comp_len(1), type(Type::IntReference), int_ref(val){};
303 PushConstant(int loc, const int2 *val, int arr)
304 : location(loc), array_len(arr), comp_len(2), type(Type::IntReference), int2_ref(val){};
305 PushConstant(int loc, const int3 *val, int arr)
306 : location(loc), array_len(arr), comp_len(3), type(Type::IntReference), int3_ref(val){};
307 PushConstant(int loc, const int4 *val, int arr)
308 : location(loc), array_len(arr), comp_len(4), type(Type::IntReference), int4_ref(val){};
309
310 void execute(RecordingState &state) const;
311 std::string serialize() const;
312};
313
315 /* Shader to set the constant in. */
316 GPUShader *shader;
317 /* Value of the constant or a reference to it. */
318 union {
323 const int *int_ref;
325 const float *float_ref;
326 const bool *bool_ref;
327 };
328
330
341
343
344 SpecializeConstant(GPUShader *sh, int loc, const float &val)
345 : shader(sh), float_value(val), location(loc), type(Type::FloatValue){};
346 SpecializeConstant(GPUShader *sh, int loc, const int &val)
347 : shader(sh), int_value(val), location(loc), type(Type::IntValue){};
348 SpecializeConstant(GPUShader *sh, int loc, const uint &val)
349 : shader(sh), uint_value(val), location(loc), type(Type::UintValue){};
350 SpecializeConstant(GPUShader *sh, int loc, const bool &val)
351 : shader(sh), bool_value(val), location(loc), type(Type::BoolValue){};
352 SpecializeConstant(GPUShader *sh, int loc, const float *val)
353 : shader(sh), float_ref(val), location(loc), type(Type::FloatReference){};
354 SpecializeConstant(GPUShader *sh, int loc, const int *val)
355 : shader(sh), int_ref(val), location(loc), type(Type::IntReference){};
356 SpecializeConstant(GPUShader *sh, int loc, const uint *val)
357 : shader(sh), uint_ref(val), location(loc), type(Type::UintReference){};
358 SpecializeConstant(GPUShader *sh, int loc, const bool *val)
359 : shader(sh), bool_ref(val), location(loc), type(Type::BoolReference){};
360
361 void execute(RecordingState &state) const;
362 std::string serialize() const;
363};
364
365struct Draw {
366 gpu::Batch *batch;
367 uint16_t instance_len;
368 uint8_t expand_prim_type; /* #GPUPrimType */
370 uint32_t vertex_first;
371 uint32_t vertex_len;
373
374 Draw() = default;
375
376 Draw(gpu::Batch *batch,
380 GPUPrimType expanded_prim_type,
381 uint expanded_prim_len,
383 {
384 BLI_assert(batch != nullptr);
385 this->batch = batch;
386 this->handle = handle;
387 this->instance_len = uint16_t(min_uu(instance_len, USHRT_MAX));
388 this->vertex_len = vertex_len;
389 this->vertex_first = vertex_first;
390 this->expand_prim_type = expanded_prim_type;
391 this->expand_prim_len = expanded_prim_len;
392 }
393
395 {
397 }
398
399 void execute(RecordingState &state) const;
400 std::string serialize() const;
401};
402
403struct DrawMulti {
404 gpu::Batch *batch;
408
409 void execute(RecordingState &state) const;
410 std::string serialize(const std::string &line_prefix) const;
411};
412
414 gpu::Batch *batch;
415 GPUStorageBuf **indirect_buf;
417
418 void execute(RecordingState &state) const;
419 std::string serialize() const;
420};
421
422struct Dispatch {
424 union {
427 };
428
429 Dispatch() = default;
430
431 Dispatch(int3 group_len) : is_reference(false), size(group_len){};
432 Dispatch(int3 *group_len) : is_reference(true), size_ref(group_len){};
433
434 void execute(RecordingState &state) const;
435 std::string serialize() const;
436};
437
439 GPUStorageBuf **indirect_buf;
440
441 void execute(RecordingState &state) const;
442 std::string serialize() const;
443};
444
445struct Barrier {
447
448 void execute() const;
449 std::string serialize() const;
450};
451
452struct Clear {
453 uint8_t clear_channels; /* #eGPUFrameBufferBits. But want to save some bits. */
454 uint8_t stencil;
455 float depth;
457
458 void execute() const;
459 std::string serialize() const;
460};
461
466
467 void execute() const;
468 std::string serialize() const;
469};
470
471struct StateSet {
474
475 void execute(RecordingState &state) const;
476 std::string serialize() const;
477
478 /* Set state of the GPU module manually. */
479 static void set(DRWState state = DRW_STATE_DEFAULT);
480};
481
486
487 void execute() const;
488 std::string serialize() const;
489};
490
509
511
512BLI_STATIC_ASSERT(sizeof(Undetermined) <= 24, "One of the command type is too large.")
513
514
515
516/* -------------------------------------------------------------------- */
525
527 friend Manager;
528
529 private:
530 using ResourceIdBuf = StorageArrayBuffer<uint, 128, false>;
532
534 ResourceIdBuf resource_id_buf_;
536 uint resource_id_count_ = 0;
537
538 public:
539 void clear()
540 {
541 resource_id_buf_.trim_to_next_power_of_2(resource_id_count_);
542 };
543
545 Vector<Undetermined, 0> &commands,
546 gpu::Batch *batch,
547 uint instance_len,
548 uint vertex_len,
549 uint vertex_first,
550 ResourceHandleRange handle_range,
551 uint custom_id,
552 GPUPrimType expanded_prim_type,
553 uint16_t expanded_prim_len)
554 {
555 BLI_assert(batch != nullptr);
556 vertex_first = vertex_first != -1 ? vertex_first : 0;
557 instance_len = instance_len != -1 ? instance_len : 1;
558
559 BLI_assert_msg(custom_id == 0, "Custom ID is not supported in PassSimple");
560 UNUSED_VARS_NDEBUG(custom_id);
561
562 for (auto handle : handle_range.index_range()) {
563 int64_t index = commands.append_and_get_index({});
564 headers.append({Type::Draw, uint(index)});
565 commands[index].draw = {batch,
566 instance_len,
567 vertex_len,
568 vertex_first,
569 expanded_prim_type,
570 expanded_prim_len,
571 ResourceHandle(handle)};
572 }
573 }
574
575 void generate_commands(Vector<Header, 0> &headers,
576 Vector<Undetermined, 0> &commands,
577 SubPassVector &sub_passes);
578
579 void bind(RecordingState &state);
580
581 private:
582 static void finalize_commands(Vector<Header, 0> &headers,
583 Vector<Undetermined, 0> &commands,
584 SubPassVector &sub_passes,
585 uint &resource_id_count,
586 ResourceIdBuf &resource_id_buf);
587};
588
590
591/* -------------------------------------------------------------------- */
618
620 friend Manager;
621 friend DrawMulti;
622
623 private:
624 using DrawGroupBuf = StorageArrayBuffer<DrawGroup, 16>;
625 using DrawPrototypeBuf = StorageArrayBuffer<DrawPrototype, 16>;
626 using DrawCommandBuf = StorageArrayBuffer<DrawCommand, 16, true>;
627 using ResourceIdBuf = StorageArrayBuffer<uint, 128, true>;
628
629 using DrawGroupKey = std::pair<uint, gpu::Batch *>;
630 using DrawGroupMap = Map<DrawGroupKey, uint>;
632 DrawGroupMap group_ids_;
633
635 DrawGroupBuf group_buf_ = {"DrawGroupBuf"};
637 DrawPrototypeBuf prototype_buf_ = {"DrawPrototypeBuf"};
639 DrawCommandBuf command_buf_ = {"DrawCommandBuf"};
641 ResourceIdBuf resource_id_buf_ = {"ResourceIdBuf"};
643 uint header_id_counter_ = 0;
645 uint group_count_ = 0;
647 uint prototype_count_ = 0;
649 uint resource_id_count_ = 0;
650
651 public:
652 void clear()
653 {
654 group_buf_.trim_to_next_power_of_2(group_count_);
655 /* Two commands per group (inverted and non-inverted scale). */
656 command_buf_.trim_to_next_power_of_2(group_count_ * 2);
657 prototype_buf_.trim_to_next_power_of_2(prototype_count_);
658 resource_id_buf_.trim_to_next_power_of_2(resource_id_count_);
659 header_id_counter_ = 0;
660 group_count_ = 0;
661 prototype_count_ = 0;
662 group_ids_.clear();
663 }
664
666 Vector<Undetermined, 0> &commands,
667 gpu::Batch *batch,
668 uint instance_len,
669 uint vertex_len,
670 uint vertex_first,
671 ResourceHandleRange handle_range,
672 uint custom_id,
673 GPUPrimType expanded_prim_type,
674 uint16_t expanded_prim_len)
675 {
676 BLI_assert(batch != nullptr);
677 /* Custom draw-calls cannot be batched and will produce one group per draw. */
678 const bool custom_group = ((vertex_first != 0 && vertex_first != -1) || vertex_len != -1);
679
680 BLI_assert(vertex_len != 0);
681 vertex_len = vertex_len == -1 ? 0 : vertex_len;
682 instance_len = instance_len != -1 ? instance_len : 1;
683
684 /* If there was some state changes since previous call, we have to create another command. */
685 if (headers.is_empty() || headers.last().type != Type::DrawMulti) {
686 uint index = commands.append_and_get_index({});
687 headers.append({Type::DrawMulti, index});
688 commands[index].draw_multi = {batch, this, (uint)-1, header_id_counter_++};
689 }
690
691 DrawMulti &cmd = commands.last().draw_multi;
692
693 uint &group_id = group_ids_.lookup_or_add(DrawGroupKey(cmd.uuid, batch), uint(-1));
694
695 bool inverted = handle_range.handle_first.has_inverted_handedness();
696
697 for (auto handle : handle_range.index_range()) {
698 DrawPrototype &draw = prototype_buf_.get_or_resize(prototype_count_++);
699 draw.res_handle = uint32_t(handle);
700 draw.custom_id = custom_id;
701 draw.instance_len = instance_len;
702 draw.group_id = group_id;
703
704 if (group_id == uint(-1) || custom_group) {
705 uint new_group_id = group_count_++;
706 draw.group_id = new_group_id;
707
708 DrawGroup &group = group_buf_.get_or_resize(new_group_id);
709 group.next = cmd.group_first;
710 group.len = instance_len;
711 group.front_facing_len = inverted ? 0 : instance_len;
712 group.front_facing_counter = 0;
713 group.back_facing_counter = 0;
714 group.desc.vertex_len = vertex_len;
715 group.desc.vertex_first = vertex_first;
716 group.desc.gpu_batch = batch;
717 group.desc.expand_prim_type = expanded_prim_type;
718 group.desc.expand_prim_len = expanded_prim_len;
719 BLI_assert_msg(expanded_prim_len < (1 << 3),
720 "Not enough bits to store primitive expansion");
721 /* Custom group are not to be registered in the group_ids_. */
722 if (!custom_group) {
723 group_id = new_group_id;
724 }
725 /* For serialization only. Reset before use on GPU. */
726 (inverted ? group.back_facing_counter : group.front_facing_counter)++;
727 /* Append to list. */
728 cmd.group_first = new_group_id;
729 }
730 else {
731 DrawGroup &group = group_buf_[group_id];
732 group.len += instance_len;
733 group.front_facing_len += inverted ? 0 : instance_len;
734 /* For serialization only. Reset before use on GPU. */
735 (inverted ? group.back_facing_counter : group.front_facing_counter)++;
736 /* NOTE: We assume that primitive expansion is coupled to the shader itself. Meaning we
737 * rely on shader bind to isolate the expanded draws into their own group (as there could
738 * be regular draws and extended draws using the same batch mixed inside the same pass).
739 * This will cause issues if this assumption is broken. Also it is very hard to detect this
740 * case for error checking. At least we can check that expansion settings don't change
741 * inside a group. */
742 BLI_assert(group.desc.expand_prim_type == expanded_prim_type);
743 BLI_assert(group.desc.expand_prim_len == expanded_prim_len);
744 }
745 }
746 }
747
749 Vector<Undetermined, 0> &commands,
750 VisibilityBuf &visibility_buf,
751 int visibility_word_per_draw,
752 int view_len,
753 bool use_custom_ids);
754
756};
757
759
760}; // 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
eGPUBarrier
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, ResourceHandleRange handle_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)
void append_draw(Vector< Header, 0 > &headers, Vector< Undetermined, 0 > &commands, gpu::Batch *batch, uint instance_len, uint vertex_len, uint vertex_first, ResourceHandleRange handle_range, uint custom_id, GPUPrimType expanded_prim_type, uint16_t expanded_prim_len)
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 @064345207361167251075330302113175271221317160336::@113254110077376341056327177062323111323010325277 batch
#define class
static ulong state[N]
#define G(x, y, z)
static GPUTexture * as_texture(Image *img)
BLI_STATIC_ASSERT(MBC_BATCH_LEN< 32, "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::@251306170140361114007106001100121365211105052341 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, ResourceHandle handle)
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)
ResourceBind(int slot_, GPUUniformBuf **res, Type)
enum blender::draw::command::ResourceBind::Type type
ResourceBind(int slot_, draw::Image *res)
ResourceBind(int slot_, gpu::VertBuf *res)
ResourceBind(int slot_, GPUUniformBuf *res)
ResourceBind(int slot_, GPUStorageBuf *res)
ResourceBind(int slot_, GPUTexture *res, GPUSamplerState state)
ResourceBind(int slot_, GPUStorageBuf **res)
ResourceBind(int slot_, draw::Image **res)
ResourceBind(int slot_, GPUTexture **res, GPUSamplerState state)
ResourceBind(int slot_, gpu::VertBuf **res)
ResourceBind(int slot_, gpu::IndexBuf *res, Type)
ResourceBind(int slot_, GPUUniformBuf **res)
ResourceBind(int slot_, gpu::VertBuf *res, Type)
ResourceBind(int slot_, GPUUniformBuf *res, Type)
ResourceBind(int slot_, gpu::IndexBuf **res, Type)
void execute(RecordingState &state) const
SpecializeConstant(GPUShader *sh, int loc, const float &val)
SpecializeConstant(GPUShader *sh, int loc, const bool &val)
SpecializeConstant(GPUShader *sh, int loc, const bool *val)
SpecializeConstant(GPUShader *sh, int loc, const uint &val)
void execute(RecordingState &state) const
SpecializeConstant(GPUShader *sh, int loc, const uint *val)
SpecializeConstant(GPUShader *sh, int loc, const int &val)
SpecializeConstant(GPUShader *sh, int loc, const float *val)
enum blender::draw::command::SpecializeConstant::Type type
SpecializeConstant(GPUShader *sh, int loc, const int *val)
void execute(RecordingState &state) const
static void set(DRWState state=DRW_STATE_DEFAULT)