Skip to content

Commit d36a872

Browse files
committed
Add draw indirect to Rendering Device
1 parent 2be730a commit d36a872

File tree

5 files changed

+183
-0
lines changed

5 files changed

+183
-0
lines changed

doc/classes/RenderingDevice.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,18 @@
324324
Submits [param draw_list] for rendering on the GPU. This is the raster equivalent to [method compute_list_dispatch].
325325
</description>
326326
</method>
327+
<method name="draw_list_draw_indirect">
328+
<return type="void" />
329+
<param index="0" name="draw_list" type="int" />
330+
<param index="1" name="use_indices" type="bool" />
331+
<param index="2" name="buffer" type="RID" />
332+
<param index="3" name="offset" type="int" default="0" />
333+
<param index="4" name="draw_count" type="int" default="1" />
334+
<param index="5" name="stride" type="int" default="0" />
335+
<description>
336+
Submits [param draw_list] for rendering on the GPU with the given parameters stored in the [param buffer] at [param offset]. Parameters being integers: vertex count, instance count, first vertex, first instance. And when using indices: index count, instance count, first index, vertex offset, first instance. Buffer must have been created with [constant STORAGE_BUFFER_USAGE_DISPATCH_INDIRECT] flag.
337+
</description>
338+
</method>
327339
<method name="draw_list_enable_scissor">
328340
<return type="void" />
329341
<param index="0" name="draw_list" type="int" />

servers/rendering/rendering_device.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4191,6 +4191,117 @@ void RenderingDevice::draw_list_draw(DrawListID p_list, bool p_use_indices, uint
41914191
dl->state.draw_count++;
41924192
}
41934193

4194+
void RenderingDevice::draw_list_draw_indirect(DrawListID p_list, bool p_use_indices, RID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
4195+
ERR_RENDER_THREAD_GUARD();
4196+
4197+
DrawList *dl = _get_draw_list_ptr(p_list);
4198+
ERR_FAIL_NULL(dl);
4199+
4200+
Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer);
4201+
ERR_FAIL_NULL(buffer);
4202+
4203+
ERR_FAIL_COND_MSG(!buffer->usage.has_flag(RDD::BUFFER_USAGE_INDIRECT_BIT), "Buffer provided was not created to do indirect dispatch.");
4204+
4205+
#ifdef DEBUG_ENABLED
4206+
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
4207+
#endif
4208+
4209+
#ifdef DEBUG_ENABLED
4210+
ERR_FAIL_COND_MSG(!dl->validation.pipeline_active,
4211+
"No render pipeline was set before attempting to draw.");
4212+
if (dl->validation.pipeline_vertex_format != INVALID_ID) {
4213+
// Pipeline uses vertices, validate format.
4214+
ERR_FAIL_COND_MSG(dl->validation.vertex_format == INVALID_ID,
4215+
"No vertex array was bound, and render pipeline expects vertices.");
4216+
// Make sure format is right.
4217+
ERR_FAIL_COND_MSG(dl->validation.pipeline_vertex_format != dl->validation.vertex_format,
4218+
"The vertex format used to create the pipeline does not match the vertex format bound.");
4219+
}
4220+
4221+
if (dl->validation.pipeline_push_constant_size > 0) {
4222+
// Using push constants, check that they were supplied.
4223+
ERR_FAIL_COND_MSG(!dl->validation.pipeline_push_constant_supplied,
4224+
"The shader in this pipeline requires a push constant to be set before drawing, but it's not present.");
4225+
}
4226+
#endif
4227+
4228+
#ifdef DEBUG_ENABLED
4229+
for (uint32_t i = 0; i < dl->state.set_count; i++) {
4230+
if (dl->state.sets[i].pipeline_expected_format == 0) {
4231+
// Nothing expected by this pipeline.
4232+
continue;
4233+
}
4234+
4235+
if (dl->state.sets[i].pipeline_expected_format != dl->state.sets[i].uniform_set_format) {
4236+
if (dl->state.sets[i].uniform_set_format == 0) {
4237+
ERR_FAIL_MSG(vformat("Uniforms were never supplied for set (%d) at the time of drawing, which are required by the pipeline.", i));
4238+
} else if (uniform_set_owner.owns(dl->state.sets[i].uniform_set)) {
4239+
UniformSet *us = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set);
4240+
ERR_FAIL_MSG(vformat("Uniforms supplied for set (%d):\n%s\nare not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(us->shader_id, us->shader_set), _shader_uniform_debug(dl->state.pipeline_shader)));
4241+
} else {
4242+
ERR_FAIL_MSG(vformat("Uniforms supplied for set (%s, which was just freed) are not the same format as required by the pipeline shader. Pipeline shader requires the following bindings:\n%s", i, _shader_uniform_debug(dl->state.pipeline_shader)));
4243+
}
4244+
}
4245+
}
4246+
#endif
4247+
4248+
// Prepare descriptor sets if the API doesn't use pipeline barriers.
4249+
if (!driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS)) {
4250+
for (uint32_t i = 0; i < dl->state.set_count; i++) {
4251+
if (dl->state.sets[i].pipeline_expected_format == 0) {
4252+
// Nothing expected by this pipeline.
4253+
continue;
4254+
}
4255+
4256+
draw_graph.add_draw_list_uniform_set_prepare_for_use(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i);
4257+
}
4258+
}
4259+
4260+
// Bind descriptor sets.
4261+
for (uint32_t i = 0; i < dl->state.set_count; i++) {
4262+
if (dl->state.sets[i].pipeline_expected_format == 0) {
4263+
continue; // Nothing expected by this pipeline.
4264+
}
4265+
if (!dl->state.sets[i].bound) {
4266+
// All good, see if this requires re-binding.
4267+
draw_graph.add_draw_list_bind_uniform_set(dl->state.pipeline_shader_driver_id, dl->state.sets[i].uniform_set_driver_id, i);
4268+
4269+
UniformSet *uniform_set = uniform_set_owner.get_or_null(dl->state.sets[i].uniform_set);
4270+
_uniform_set_update_shared(uniform_set);
4271+
4272+
draw_graph.add_draw_list_usages(uniform_set->draw_trackers, uniform_set->draw_trackers_usage);
4273+
4274+
dl->state.sets[i].bound = true;
4275+
}
4276+
}
4277+
4278+
if (p_use_indices) {
4279+
#ifdef DEBUG_ENABLED
4280+
ERR_FAIL_COND_MSG(!dl->validation.index_array_count,
4281+
"Draw command requested indices, but no index buffer was set.");
4282+
4283+
ERR_FAIL_COND_MSG(dl->validation.pipeline_uses_restart_indices != dl->validation.index_buffer_uses_restart_indices,
4284+
"The usage of restart indices in index buffer does not match the render primitive in the pipeline.");
4285+
#endif
4286+
4287+
ERR_FAIL_COND_MSG(p_offset + 20 > buffer->size, "Offset provided (+20) is past the end of buffer.");
4288+
4289+
draw_graph.add_draw_list_draw_indexed_indirect(buffer->driver_id, p_offset, p_draw_count, p_stride);
4290+
} else {
4291+
ERR_FAIL_COND_MSG(p_offset + 16 > buffer->size, "Offset provided (+16) is past the end of buffer.");
4292+
4293+
draw_graph.add_draw_list_draw_indirect(buffer->driver_id, p_offset, p_draw_count, p_stride);
4294+
}
4295+
4296+
dl->state.draw_count++;
4297+
4298+
if (buffer->draw_tracker != nullptr) {
4299+
draw_graph.add_draw_list_usage(buffer->draw_tracker, RDG::RESOURCE_USAGE_INDIRECT_BUFFER_READ);
4300+
}
4301+
4302+
_check_transfer_worker_buffer(buffer);
4303+
}
4304+
41944305
void RenderingDevice::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) {
41954306
DrawList *dl = _get_draw_list_ptr(p_list);
41964307

@@ -6023,6 +6134,7 @@ void RenderingDevice::_bind_methods() {
60236134
ClassDB::bind_method(D_METHOD("draw_list_set_push_constant", "draw_list", "buffer", "size_bytes"), &RenderingDevice::_draw_list_set_push_constant);
60246135

60256136
ClassDB::bind_method(D_METHOD("draw_list_draw", "draw_list", "use_indices", "instances", "procedural_vertex_count"), &RenderingDevice::draw_list_draw, DEFVAL(0));
6137+
ClassDB::bind_method(D_METHOD("draw_list_draw_indirect", "draw_list", "use_indices", "buffer", "offset", "draw_count", "stride"), &RenderingDevice::draw_list_draw_indirect, DEFVAL(0), DEFVAL(1), DEFVAL(0));
60266138

60276139
ClassDB::bind_method(D_METHOD("draw_list_enable_scissor", "draw_list", "rect"), &RenderingDevice::draw_list_enable_scissor, DEFVAL(Rect2()));
60286140
ClassDB::bind_method(D_METHOD("draw_list_disable_scissor", "draw_list"), &RenderingDevice::draw_list_disable_scissor);

servers/rendering/rendering_device.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1172,6 +1172,7 @@ class RenderingDevice : public RenderingDeviceCommons {
11721172
void draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size);
11731173

11741174
void draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances = 1, uint32_t p_procedural_vertices = 0);
1175+
void draw_list_draw_indirect(DrawListID p_list, bool p_use_indices, RID p_buffer, uint32_t p_offset = 0, uint32_t p_draw_count = 1, uint32_t p_stride = 0);
11751176

11761177
void draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect);
11771178
void draw_list_disable_scissor(DrawListID p_list);

servers/rendering/rendering_device_graph.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,16 @@ void RenderingDeviceGraph::_run_draw_list_command(RDD::CommandBufferID p_command
699699
driver->command_render_draw_indexed(p_command_buffer, draw_indexed_instruction->index_count, draw_indexed_instruction->instance_count, draw_indexed_instruction->first_index, 0, 0);
700700
instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction);
701701
} break;
702+
case DrawListInstruction::TYPE_DRAW_INDIRECT: {
703+
const DrawListDrawIndirectInstruction *draw_indirect_instruction = reinterpret_cast<const DrawListDrawIndirectInstruction *>(instruction);
704+
driver->command_render_draw_indirect(p_command_buffer, draw_indirect_instruction->buffer, draw_indirect_instruction->offset, draw_indirect_instruction->draw_count, draw_indirect_instruction->stride);
705+
instruction_data_cursor += sizeof(DrawListDrawIndirectInstruction);
706+
} break;
707+
case DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT: {
708+
const DrawListDrawIndexedIndirectInstruction *draw_indexed_indirect_instruction = reinterpret_cast<const DrawListDrawIndexedIndirectInstruction *>(instruction);
709+
driver->command_render_draw_indexed_indirect(p_command_buffer, draw_indexed_indirect_instruction->buffer, draw_indexed_indirect_instruction->offset, draw_indexed_indirect_instruction->draw_count, draw_indexed_indirect_instruction->stride);
710+
instruction_data_cursor += sizeof(DrawListDrawIndexedIndirectInstruction);
711+
} break;
702712
case DrawListInstruction::TYPE_EXECUTE_COMMANDS: {
703713
const DrawListExecuteCommandsInstruction *execute_commands_instruction = reinterpret_cast<const DrawListExecuteCommandsInstruction *>(instruction);
704714
driver->command_buffer_execute_secondary(p_command_buffer, execute_commands_instruction->command_buffer);
@@ -1178,6 +1188,16 @@ void RenderingDeviceGraph::_print_draw_list(const uint8_t *p_instruction_data, u
11781188
print_line("\tDRAW INDICES", draw_indexed_instruction->index_count, "INSTANCES", draw_indexed_instruction->instance_count, "FIRST INDEX", draw_indexed_instruction->first_index);
11791189
instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction);
11801190
} break;
1191+
case DrawListInstruction::TYPE_DRAW_INDIRECT: {
1192+
const DrawListDrawIndirectInstruction *draw_indirect_instruction = reinterpret_cast<const DrawListDrawIndirectInstruction *>(instruction);
1193+
print_line("\tDRAW INDIRECT BUFFER ID", itos(draw_indirect_instruction->buffer.id), "OFFSET", draw_indirect_instruction->offset, "DRAW COUNT", draw_indirect_instruction->draw_count, "STRIDE", draw_indirect_instruction->stride);
1194+
instruction_data_cursor += sizeof(DrawListDrawIndirectInstruction);
1195+
} break;
1196+
case DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT: {
1197+
const DrawListDrawIndexedIndirectInstruction *draw_indexed_indirect_instruction = reinterpret_cast<const DrawListDrawIndexedIndirectInstruction *>(instruction);
1198+
print_line("\tDRAW INDEXED INDIRECT BUFFER ID", itos(draw_indexed_indirect_instruction->buffer.id), "OFFSET", draw_indexed_indirect_instruction->offset, "DRAW COUNT", draw_indexed_indirect_instruction->draw_count, "STRIDE", draw_indexed_indirect_instruction->stride);
1199+
instruction_data_cursor += sizeof(DrawListDrawIndexedIndirectInstruction);
1200+
} break;
11811201
case DrawListInstruction::TYPE_EXECUTE_COMMANDS: {
11821202
print_line("\tEXECUTE COMMANDS");
11831203
instruction_data_cursor += sizeof(DrawListExecuteCommandsInstruction);
@@ -1596,6 +1616,26 @@ void RenderingDeviceGraph::add_draw_list_draw_indexed(uint32_t p_index_count, ui
15961616
instruction->first_index = p_first_index;
15971617
}
15981618

1619+
void RenderingDeviceGraph::add_draw_list_draw_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
1620+
DrawListDrawIndirectInstruction *instruction = reinterpret_cast<DrawListDrawIndirectInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndirectInstruction)));
1621+
instruction->type = DrawListInstruction::TYPE_DRAW_INDIRECT;
1622+
instruction->buffer = p_buffer;
1623+
instruction->offset = p_offset;
1624+
instruction->draw_count = p_draw_count;
1625+
instruction->stride = p_stride;
1626+
draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
1627+
}
1628+
1629+
void RenderingDeviceGraph::add_draw_list_draw_indexed_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
1630+
DrawListDrawIndexedIndirectInstruction *instruction = reinterpret_cast<DrawListDrawIndexedIndirectInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndexedIndirectInstruction)));
1631+
instruction->type = DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT;
1632+
instruction->buffer = p_buffer;
1633+
instruction->offset = p_offset;
1634+
instruction->draw_count = p_draw_count;
1635+
instruction->stride = p_stride;
1636+
draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
1637+
}
1638+
15991639
void RenderingDeviceGraph::add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer) {
16001640
DrawListExecuteCommandsInstruction *instruction = reinterpret_cast<DrawListExecuteCommandsInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListExecuteCommandsInstruction)));
16011641
instruction->type = DrawListInstruction::TYPE_EXECUTE_COMMANDS;

servers/rendering/rendering_device_graph.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ class RenderingDeviceGraph {
6969
TYPE_CLEAR_ATTACHMENTS,
7070
TYPE_DRAW,
7171
TYPE_DRAW_INDEXED,
72+
TYPE_DRAW_INDIRECT,
73+
TYPE_DRAW_INDEXED_INDIRECT,
7274
TYPE_EXECUTE_COMMANDS,
7375
TYPE_NEXT_SUBPASS,
7476
TYPE_SET_BLEND_CONSTANTS,
@@ -463,6 +465,20 @@ class RenderingDeviceGraph {
463465
uint32_t first_index = 0;
464466
};
465467

468+
struct DrawListDrawIndirectInstruction : DrawListInstruction {
469+
RDD::BufferID buffer;
470+
uint32_t offset = 0;
471+
uint32_t draw_count = 0;
472+
uint32_t stride = 0;
473+
};
474+
475+
struct DrawListDrawIndexedIndirectInstruction : DrawListInstruction {
476+
RDD::BufferID buffer;
477+
uint32_t offset = 0;
478+
uint32_t draw_count = 0;
479+
uint32_t stride = 0;
480+
};
481+
466482
struct DrawListEndRenderPassInstruction : DrawListInstruction {
467483
// No contents.
468484
};
@@ -675,6 +691,8 @@ class RenderingDeviceGraph {
675691
void add_draw_list_clear_attachments(VectorView<RDD::AttachmentClear> p_attachments_clear, VectorView<Rect2i> p_attachments_clear_rect);
676692
void add_draw_list_draw(uint32_t p_vertex_count, uint32_t p_instance_count);
677693
void add_draw_list_draw_indexed(uint32_t p_index_count, uint32_t p_instance_count, uint32_t p_first_index);
694+
void add_draw_list_draw_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride);
695+
void add_draw_list_draw_indexed_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride);
678696
void add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer);
679697
void add_draw_list_next_subpass(RDD::CommandBufferType p_command_buffer_type);
680698
void add_draw_list_set_blend_constants(const Color &p_color);

0 commit comments

Comments
 (0)