| 75 | } |
| 76 | |
| 77 | void device_queue::execute_indirect(const indirect_command_pipeline& indirect_cmd, |
| 78 | const indirect_execution_parameters_t& params, |
| 79 | kernel_completion_handler_f&& completion_handler, |
| 80 | const uint32_t command_offset, |
| 81 | const uint32_t command_count) const { |
| 82 | if (command_count == 0) { |
| 83 | return; |
| 84 | } |
| 85 | if (!dev.indirect_command_support || !dev.indirect_compute_command_support) { |
| 86 | log_error("device $ has no support for indirect command pipelines", dev.name); |
| 87 | return; |
| 88 | } |
| 89 | |
| 90 | #if defined(FLOOR_DEBUG) |
| 91 | if (indirect_cmd.get_description().command_type != indirect_command_description::COMMAND_TYPE::COMPUTE) { |
| 92 | log_error("specified indirect command pipeline \"$\" must be a compute pipeline", |
| 93 | indirect_cmd.get_description().debug_label); |
| 94 | return; |
| 95 | } |
| 96 | #endif |
| 97 | |
| 98 | const auto& generic_indirect_cmd = (const generic_indirect_command_pipeline&)indirect_cmd; |
| 99 | const auto generic_indirect_pipeline_entry = generic_indirect_cmd.get_pipeline_entry(dev); |
| 100 | if (!generic_indirect_pipeline_entry) { |
| 101 | log_error("no indirect command pipeline state for device \"$\" in indirect command pipeline \"$\"", |
| 102 | dev.name, indirect_cmd.get_description().debug_label); |
| 103 | return; |
| 104 | } |
| 105 | |
| 106 | const auto range = generic_indirect_cmd.compute_and_validate_command_range(command_offset, command_count); |
| 107 | if (!range) { |
| 108 | return; |
| 109 | } |
| 110 | |
| 111 | // wait fences handling: we add "wait_fences" to all kernel executions until we hit the first kernel that acts as a barrier, |
| 112 | // i.e. it has wait_until_completion set -> after that, we can safely ignore wait_fences |
| 113 | bool has_encountered_barrier = false; |
| 114 | const std::vector<const device_fence*> empty_wait_fences; |
| 115 | const std::vector<device_fence*> empty_signal_fences; |
| 116 | for (uint32_t cmd_idx = range->offset, cmd_end = range->offset + range->count; cmd_idx < cmd_end; ++cmd_idx) { |
| 117 | const auto& cmd = generic_indirect_pipeline_entry->commands[cmd_idx]; |
| 118 | // the last command is somewhat special: it is used both to execute the final completion handler + emit "signal_fences" |
| 119 | const auto is_last_cmd = (cmd_idx + 1u == cmd_end); |
| 120 | cmd.kernel_ptr->execute(*this, false, cmd.wait_until_completion, cmd.dim, cmd.global_work_size, cmd.local_work_size, cmd.args, |
| 121 | !has_encountered_barrier && !params.wait_fences.empty() ? params.wait_fences : empty_wait_fences, |
| 122 | !is_last_cmd ? empty_signal_fences : params.signal_fences, |
| 123 | params.debug_label ? params.debug_label : generic_indirect_pipeline_entry->debug_label.c_str(), |
| 124 | is_last_cmd && completion_handler ? completion_handler : kernel_completion_handler_f {}); |
| 125 | if (cmd.wait_until_completion) { |
| 126 | has_encountered_barrier = true; |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | if (params.wait_until_completion) { |
| 131 | finish(); |
| 132 | } |
| 133 | } |
| 134 |
nothing calls this directly
no test coverage detected