| 3317 | } |
| 3318 | |
| 3319 | void TaskGraph::execute([[maybe_unused]] ExecutionInfo const & info) |
| 3320 | { |
| 3321 | auto & impl = *r_cast<ImplTaskGraph *>(this->object); |
| 3322 | DAXA_DBG_ASSERT_TRUE_M(impl.compiled, "ERROR: TaskGraph must be completed before execution!"); |
| 3323 | |
| 3324 | std::array<u8, 1u << 16u> tmp_stack_mem; |
| 3325 | MemoryArena tmp_memory = MemoryArena{"TaskGraph::execute tmp memory", tmp_stack_mem}; |
| 3326 | |
| 3327 | /// ============================================================================= |
| 3328 | /// ==== VALIDATE, PATCH AND GENERATE CONNECTING SYNC FOR EXTERNAL RESOURCES ==== |
| 3329 | /// ============================================================================= |
| 3330 | |
| 3331 | // External resources can be changed outside of the taskgraph. |
| 3332 | // Calculate required sync from the pre graph access to the first access of external resources here. |
| 3333 | // Validate all external resources: Are the ids valid? Do the resources match the access requirements? |
| 3334 | // Update ids and data of the external resource inside taskgraph. |
| 3335 | // If the id changed, patch attachment blobs and recreate image views for tasks accessing the resource. |
| 3336 | // All image views and attachment blobs are pre-created and kept between executions. |
| 3337 | // Only patch the outdated parts of attachment blobs and image view arrays when a external resource changed. |
| 3338 | |
| 3339 | // Memory and exeuction dependencies are done via semaphores. |
| 3340 | // Only image initializations require additional pipeline barriers. |
| 3341 | // Image initialization is inserted in the first submit for the queue that uses the image, before all other commands. |
| 3342 | auto image_initializations = tmp_memory.allocate_trivial_span<std::array<ArenaDynamicArray8k<TaskBarrier>, DAXA_QUEUE_COUNT>>(impl.submits.size()); |
| 3343 | for (u32 s = 0; s < impl.submits.size(); ++s) |
| 3344 | { |
| 3345 | for (u32 q = 0; q < DAXA_QUEUE_COUNT; ++q) |
| 3346 | { |
| 3347 | image_initializations[s][q] = ArenaDynamicArray8k<TaskBarrier>(&tmp_memory); |
| 3348 | } |
| 3349 | } |
| 3350 | |
| 3351 | // Taskgraph performs a full barrier between all queues it uses at every submit. |
| 3352 | // Task graph finds all queues exterbal resources were used on prior to its exection. |
| 3353 | // It then constructs a dependency which synchronizes all queues found in the previous step with all queues used by this taskgraph. |
| 3354 | // This synchronization waits on all previously recorded commands to finish before any commands from this taskgraph are executed. |
| 3355 | u32 external_resource_queue_bits = {}; |
| 3356 | |
| 3357 | // Validate the swapchain image we use was not yet presented to |
| 3358 | if (impl.swapchain_image) |
| 3359 | { |
| 3360 | bool const swapchain_image_unused = impl.swapchain_image->access_timeline.size() == 0 && !impl.present.has_value(); |
| 3361 | DAXA_DBG_ASSERT_TRUE_M(!impl.swapchain_image->external->was_presented || swapchain_image_unused, "ERROR: The swapchain image was already presented to and can not be used in actions of this graph!"); |
| 3362 | } |
| 3363 | |
| 3364 | // Validate and patch external resources |
| 3365 | for (u32 er = 0; er < impl.external_resources.size(); ++er) |
| 3366 | { |
| 3367 | auto [resource, resource_i] = impl.external_resources[er]; |
| 3368 | |
| 3369 | DAXA_DBG_ASSERT_TRUE_M(resource->external != nullptr, "IMPOSSIBLE CASE, POSSIBLY CAUSED BY DATA CORRUPTION!"); |
| 3370 | |
| 3371 | // Skip unused resources |
| 3372 | if (resource->access_timeline.size() == 0) |
| 3373 | { |
| 3374 | continue; |
| 3375 | } |
| 3376 | |