summaryrefslogtreecommitdiffstats
path: root/servers/rendering/rendering_device_graph.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'servers/rendering/rendering_device_graph.cpp')
-rw-r--r--servers/rendering/rendering_device_graph.cpp128
1 files changed, 112 insertions, 16 deletions
diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp
index abcb76cd43..ebfe328393 100644
--- a/servers/rendering/rendering_device_graph.cpp
+++ b/servers/rendering/rendering_device_graph.cpp
@@ -140,6 +140,42 @@ RDD::BarrierAccessBits RenderingDeviceGraph::_usage_to_access_bits(ResourceUsage
#endif
}
+bool RenderingDeviceGraph::_check_command_intersection(ResourceTracker *p_resource_tracker, int32_t p_previous_command_index, int32_t p_command_index) const {
+ if (p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE && p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE) {
+ // We don't check possible intersections for usages that aren't consecutive color or depth writes.
+ return true;
+ }
+
+ const uint32_t previous_command_data_offset = command_data_offsets[p_previous_command_index];
+ const uint32_t current_command_data_offset = command_data_offsets[p_command_index];
+ const RecordedDrawListCommand &previous_draw_list_command = *reinterpret_cast<const RecordedDrawListCommand *>(&command_data[previous_command_data_offset]);
+ const RecordedDrawListCommand &current_draw_list_command = *reinterpret_cast<const RecordedDrawListCommand *>(&command_data[current_command_data_offset]);
+ if (previous_draw_list_command.type != RecordedCommand::TYPE_DRAW_LIST || current_draw_list_command.type != RecordedCommand::TYPE_DRAW_LIST) {
+ // We don't check possible intersections if both commands aren't draw lists.
+ return true;
+ }
+
+ // We check if the region used by both draw lists have an intersection.
+ return previous_draw_list_command.region.intersects(current_draw_list_command.region);
+}
+
+bool RenderingDeviceGraph::_check_command_partial_coverage(ResourceTracker *p_resource_tracker, int32_t p_command_index) const {
+ if (p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_COLOR_READ_WRITE && p_resource_tracker->usage != RESOURCE_USAGE_ATTACHMENT_DEPTH_STENCIL_READ_WRITE) {
+ // We don't check for partial coverage in usages that aren't attachment writes.
+ return true;
+ }
+
+ const uint32_t command_data_offset = command_data_offsets[p_command_index];
+ const RecordedDrawListCommand &draw_list_command = *reinterpret_cast<const RecordedDrawListCommand *>(&command_data[command_data_offset]);
+ if (draw_list_command.type != RecordedCommand::TYPE_DRAW_LIST) {
+ // We don't check for partial coverage on commands that aren't draw lists.
+ return false;
+ }
+
+ Rect2i texture_region(Point2i(0, 0), p_resource_tracker->texture_size);
+ return !draw_list_command.region.encloses(texture_region);
+}
+
int32_t RenderingDeviceGraph::_add_to_command_list(int32_t p_command_index, int32_t p_list_index) {
DEV_ASSERT(p_command_index < int32_t(command_count));
DEV_ASSERT(p_list_index < int32_t(command_list_nodes.size()));
@@ -175,7 +211,7 @@ int32_t RenderingDeviceGraph::_add_to_slice_read_list(int32_t p_command_index, R
return next_index;
}
-int32_t RenderingDeviceGraph::_add_to_write_list(int32_t p_command_index, Rect2i p_subresources, int32_t p_list_index) {
+int32_t RenderingDeviceGraph::_add_to_write_list(int32_t p_command_index, Rect2i p_subresources, int32_t p_list_index, bool p_partial_coverage) {
DEV_ASSERT(p_command_index < int32_t(command_count));
DEV_ASSERT(p_list_index < int32_t(write_slice_list_nodes.size()));
@@ -186,6 +222,7 @@ int32_t RenderingDeviceGraph::_add_to_write_list(int32_t p_command_index, Rect2i
new_node.command_index = p_command_index;
new_node.next_list_index = p_list_index;
new_node.subresources = p_subresources;
+ new_node.partial_coverage = p_partial_coverage;
return next_index;
}
@@ -425,11 +462,9 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
#if USE_BUFFER_BARRIERS
_add_buffer_barrier_to_command(resource_tracker->buffer_driver_id, resource_tracker->usage_access, new_usage_access, r_command->buffer_barrier_index, r_command->buffer_barrier_count);
#endif
- // FIXME: Memory barriers are currently pushed regardless of whether buffer barriers are being used or not. Refer to the comment on the
- // definition of USE_BUFFER_BARRIERS for the reason behind this. This can be fixed to be one case or the other once it's been confirmed
- // the buffer and memory barrier behavior discrepancy has been solved.
- r_command->memory_barrier.src_access = resource_tracker->usage_access;
- r_command->memory_barrier.dst_access = new_usage_access;
+ // Memory barriers are pushed regardless of buffer barriers being used or not.
+ r_command->memory_barrier.src_access = r_command->memory_barrier.src_access | resource_tracker->usage_access;
+ r_command->memory_barrier.dst_access = r_command->memory_barrier.dst_access | new_usage_access;
} else {
DEV_ASSERT(false && "Resource tracker does not contain a valid buffer or texture ID.");
}
@@ -438,12 +473,23 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
// Always update the access of the tracker according to the latest usage.
resource_tracker->usage_access = new_usage_access;
+ // Always accumulate the stages of the tracker with the commands that use it.
+ search_tracker->current_frame_stages = search_tracker->current_frame_stages | r_command->self_stages;
+
+ if (!search_tracker->previous_frame_stages.is_empty()) {
+ // Add to the command the stages the tracker was used on in the previous frame.
+ r_command->previous_stages = r_command->previous_stages | search_tracker->previous_frame_stages;
+ search_tracker->previous_frame_stages.clear();
+ }
+
if (different_usage) {
// Even if the usage of the resource isn't a write usage explicitly, a different usage implies a transition and it should therefore be considered a write.
- write_usage = true;
+ // In the case of buffers however, this is not exactly necessary if the driver does not consider different buffer usages as different states.
+ write_usage = write_usage || bool(resource_tracker->texture_driver_id) || driver_buffers_require_transitions;
resource_tracker->usage = new_resource_usage;
}
+ bool write_usage_has_partial_coverage = !different_usage && _check_command_partial_coverage(resource_tracker, p_command_index);
if (search_tracker->write_command_or_list_index >= 0) {
if (search_tracker->write_command_list_enabled) {
// Make this command adjacent to any commands that wrote to this resource and intersect with the slice if it applies.
@@ -455,11 +501,11 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
if (!resource_has_parent || search_tracker_rect.intersects(write_list_node.subresources)) {
if (write_list_node.command_index == p_command_index) {
ERR_FAIL_COND_MSG(!resource_has_parent, "Command can't have itself as a dependency.");
- } else {
+ } else if (!write_list_node.partial_coverage || _check_command_intersection(resource_tracker, write_list_node.command_index, p_command_index)) {
// Command is dependent on this command. Add this command to the adjacency list of the write command.
_add_adjacent_command(write_list_node.command_index, p_command_index, r_command);
- if (resource_has_parent && write_usage && search_tracker_rect.encloses(write_list_node.subresources)) {
+ if (resource_has_parent && write_usage && search_tracker_rect.encloses(write_list_node.subresources) && !write_usage_has_partial_coverage) {
// Eliminate redundant writes from the list.
if (previous_write_list_index >= 0) {
RecordedSliceListNode &previous_list_node = write_slice_list_nodes[previous_write_list_index];
@@ -488,15 +534,16 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
}
if (write_usage) {
- if (resource_has_parent) {
+ bool use_write_list = resource_has_parent || write_usage_has_partial_coverage;
+ if (use_write_list) {
if (!search_tracker->write_command_list_enabled && search_tracker->write_command_or_list_index >= 0) {
// Write command list was not being used but there was a write command recorded. Add a new node with the entire parent resource's subresources and the recorded command index to the list.
const RDD::TextureSubresourceRange &tracker_subresources = search_tracker->texture_subresources;
Rect2i tracker_rect(tracker_subresources.base_mipmap, tracker_subresources.base_layer, tracker_subresources.mipmap_count, tracker_subresources.layer_count);
- search_tracker->write_command_or_list_index = _add_to_write_list(search_tracker->write_command_or_list_index, tracker_rect, -1);
+ search_tracker->write_command_or_list_index = _add_to_write_list(search_tracker->write_command_or_list_index, tracker_rect, -1, false);
}
- search_tracker->write_command_or_list_index = _add_to_write_list(p_command_index, search_tracker_rect, search_tracker->write_command_or_list_index);
+ search_tracker->write_command_or_list_index = _add_to_write_list(p_command_index, search_tracker_rect, search_tracker->write_command_or_list_index, write_usage_has_partial_coverage);
search_tracker->write_command_list_enabled = true;
} else {
search_tracker->write_command_or_list_index = p_command_index;
@@ -521,7 +568,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
read_full_command_list_index = read_full_next_index;
}
- if (!resource_has_parent) {
+ if (!use_write_list) {
// Clear the full list if this resource is not a slice.
search_tracker->read_full_command_list_index = -1;
}
@@ -531,7 +578,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
int32_t read_slice_command_list_index = search_tracker->read_slice_command_list_index;
while (read_slice_command_list_index >= 0) {
const RecordedSliceListNode &read_list_node = read_slice_list_nodes[read_slice_command_list_index];
- if (!resource_has_parent || search_tracker_rect.encloses(read_list_node.subresources)) {
+ if (!use_write_list || search_tracker_rect.encloses(read_list_node.subresources)) {
if (previous_slice_command_list_index >= 0) {
// Erase this element and connect the previous one to the next element.
read_slice_list_nodes[previous_slice_command_list_index].next_list_index = read_list_node.next_list_index;
@@ -699,6 +746,16 @@ void RenderingDeviceGraph::_run_draw_list_command(RDD::CommandBufferID p_command
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);
instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction);
} break;
+ case DrawListInstruction::TYPE_DRAW_INDIRECT: {
+ const DrawListDrawIndirectInstruction *draw_indirect_instruction = reinterpret_cast<const DrawListDrawIndirectInstruction *>(instruction);
+ 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);
+ instruction_data_cursor += sizeof(DrawListDrawIndirectInstruction);
+ } break;
+ case DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT: {
+ const DrawListDrawIndexedIndirectInstruction *draw_indexed_indirect_instruction = reinterpret_cast<const DrawListDrawIndexedIndirectInstruction *>(instruction);
+ 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);
+ instruction_data_cursor += sizeof(DrawListDrawIndexedIndirectInstruction);
+ } break;
case DrawListInstruction::TYPE_EXECUTE_COMMANDS: {
const DrawListExecuteCommandsInstruction *execute_commands_instruction = reinterpret_cast<const DrawListExecuteCommandsInstruction *>(instruction);
driver->command_buffer_execute_secondary(p_command_buffer, execute_commands_instruction->command_buffer);
@@ -874,7 +931,7 @@ void RenderingDeviceGraph::_run_label_command_change(RDD::CommandBufferID p_comm
}
if (p_ignore_previous_value || p_new_label_index != r_current_label_index || p_new_level != r_current_label_level) {
- if (!p_ignore_previous_value && (p_use_label_for_empty || r_current_label_index >= 0)) {
+ if (!p_ignore_previous_value && (p_use_label_for_empty || r_current_label_index >= 0 || r_current_label_level >= 0)) {
// End the current label.
driver->command_end_label(p_command_buffer);
}
@@ -888,6 +945,8 @@ void RenderingDeviceGraph::_run_label_command_change(RDD::CommandBufferID p_comm
} else if (p_use_label_for_empty) {
label_name = "Command graph";
label_color = Color(1, 1, 1, 1);
+ } else {
+ return;
}
// Add the level to the name.
@@ -1178,6 +1237,16 @@ void RenderingDeviceGraph::_print_draw_list(const uint8_t *p_instruction_data, u
print_line("\tDRAW INDICES", draw_indexed_instruction->index_count, "INSTANCES", draw_indexed_instruction->instance_count, "FIRST INDEX", draw_indexed_instruction->first_index);
instruction_data_cursor += sizeof(DrawListDrawIndexedInstruction);
} break;
+ case DrawListInstruction::TYPE_DRAW_INDIRECT: {
+ const DrawListDrawIndirectInstruction *draw_indirect_instruction = reinterpret_cast<const DrawListDrawIndirectInstruction *>(instruction);
+ 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);
+ instruction_data_cursor += sizeof(DrawListDrawIndirectInstruction);
+ } break;
+ case DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT: {
+ const DrawListDrawIndexedIndirectInstruction *draw_indexed_indirect_instruction = reinterpret_cast<const DrawListDrawIndexedIndirectInstruction *>(instruction);
+ 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);
+ instruction_data_cursor += sizeof(DrawListDrawIndexedIndirectInstruction);
+ } break;
case DrawListInstruction::TYPE_EXECUTE_COMMANDS: {
print_line("\tEXECUTE COMMANDS");
instruction_data_cursor += sizeof(DrawListExecuteCommandsInstruction);
@@ -1287,6 +1356,7 @@ void RenderingDeviceGraph::initialize(RDD *p_driver, RenderingContextDriver::Dev
driver_honors_barriers = driver->api_trait_get(RDD::API_TRAIT_HONORS_PIPELINE_BARRIERS);
driver_clears_with_copy_engine = driver->api_trait_get(RDD::API_TRAIT_CLEARS_WITH_COPY_ENGINE);
+ driver_buffers_require_transitions = driver->api_trait_get(RDD::API_TRAIT_BUFFERS_REQUIRE_TRANSITIONS);
}
void RenderingDeviceGraph::finalize() {
@@ -1404,7 +1474,9 @@ void RenderingDeviceGraph::add_buffer_update(RDD::BufferID p_dst, ResourceTracke
void RenderingDeviceGraph::add_compute_list_begin(RDD::BreadcrumbMarker p_phase, uint32_t p_breadcrumb_data) {
compute_instruction_list.clear();
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
compute_instruction_list.breadcrumb = p_breadcrumb_data | (p_phase & ((1 << 16) - 1));
+#endif
compute_instruction_list.index++;
}
@@ -1500,7 +1572,9 @@ void RenderingDeviceGraph::add_draw_list_begin(RDD::RenderPassID p_render_pass,
draw_instruction_list.render_pass = p_render_pass;
draw_instruction_list.framebuffer = p_framebuffer;
draw_instruction_list.region = p_region;
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
draw_instruction_list.breadcrumb = p_breadcrumb;
+#endif
draw_instruction_list.clear_values.resize(p_clear_values.size());
for (uint32_t i = 0; i < p_clear_values.size(); i++) {
draw_instruction_list.clear_values[i] = p_clear_values[i];
@@ -1596,6 +1670,26 @@ void RenderingDeviceGraph::add_draw_list_draw_indexed(uint32_t p_index_count, ui
instruction->first_index = p_first_index;
}
+void RenderingDeviceGraph::add_draw_list_draw_indirect(RDD::BufferID p_buffer, uint32_t p_offset, uint32_t p_draw_count, uint32_t p_stride) {
+ DrawListDrawIndirectInstruction *instruction = reinterpret_cast<DrawListDrawIndirectInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndirectInstruction)));
+ instruction->type = DrawListInstruction::TYPE_DRAW_INDIRECT;
+ instruction->buffer = p_buffer;
+ instruction->offset = p_offset;
+ instruction->draw_count = p_draw_count;
+ instruction->stride = p_stride;
+ draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
+}
+
+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) {
+ DrawListDrawIndexedIndirectInstruction *instruction = reinterpret_cast<DrawListDrawIndexedIndirectInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListDrawIndexedIndirectInstruction)));
+ instruction->type = DrawListInstruction::TYPE_DRAW_INDEXED_INDIRECT;
+ instruction->buffer = p_buffer;
+ instruction->offset = p_offset;
+ instruction->draw_count = p_draw_count;
+ instruction->stride = p_stride;
+ draw_instruction_list.stages.set_flag(RDD::PIPELINE_STAGE_DRAW_INDIRECT_BIT);
+}
+
void RenderingDeviceGraph::add_draw_list_execute_commands(RDD::CommandBufferID p_command_buffer) {
DrawListExecuteCommandsInstruction *instruction = reinterpret_cast<DrawListExecuteCommandsInstruction *>(_allocate_draw_list_instruction(sizeof(DrawListExecuteCommandsInstruction)));
instruction->type = DrawListInstruction::TYPE_EXECUTE_COMMANDS;
@@ -1711,7 +1805,9 @@ void RenderingDeviceGraph::add_draw_list_end() {
command->framebuffer = draw_instruction_list.framebuffer;
command->command_buffer_type = command_buffer_type;
command->region = draw_instruction_list.region;
+#if defined(DEBUG_ENABLED) || defined(DEV_ENABLED)
command->breadcrumb = draw_instruction_list.breadcrumb;
+#endif
command->clear_values_count = draw_instruction_list.clear_values.size();
RDD::RenderPassClearValue *clear_values = command->clear_values();
@@ -2064,7 +2160,7 @@ void RenderingDeviceGraph::end(bool p_reorder_commands, bool p_full_barriers, RD
}
}
- _run_label_command_change(r_command_buffer, -1, -1, true, false, nullptr, 0, current_label_index, current_label_level);
+ _run_label_command_change(r_command_buffer, -1, -1, false, false, nullptr, 0, current_label_index, current_label_level);
#if PRINT_COMMAND_RECORDING
print_line(vformat("Recorded %d commands", command_count));