// Copyright 2014-2022 The Khronos Group Inc. // // SPDX-License-Identifier: CC-BY-4.0 include::{generated}/meta/{refprefix}VK_KHR_deferred_host_operations.adoc[] === Other Extension Metadata *Last Modified Date*:: 2020-11-12 *IP Status*:: No known IP claims. *Contributors*:: - Joshua Barczak, Intel - Jeff Bolz, NVIDIA - Daniel Koch, NVIDIA - Slawek Grajewski, Intel - Tobias Hector, AMD - Yuriy O'Donnell, Epic - Eric Werness, NVIDIA - Baldur Karlsson, Valve - Jesse Barker, Unity - Contributors to VK_KHR_acceleration_structure, VK_KHR_ray_tracing_pipeline === Description The `apiext:VK_KHR_deferred_host_operations` extension defines the infrastructure and usage patterns for deferrable commands, but does not specify any commands as deferrable. This is left to additional dependent extensions. Commands must: not be deferred unless the deferral is specifically allowed by another extension which depends on `apiext:VK_KHR_deferred_host_operations`. include::{generated}/interfaces/VK_KHR_deferred_host_operations.adoc[] === Code Examples The following examples will illustrate the concept of deferrable operations using a hypothetical example. The command ftext:vkDoSomethingExpensive denotes a deferrable command. The following example illustrates how a vulkan application might request deferral of an expensive operation: [source,cpp] ---- // create a deferred operation VkDeferredOperationKHR hOp; VkResult result = vkCreateDeferredOperationKHR(device, pCallbacks, &hOp); assert(result == VK_SUCCESS); result = vkDoSomethingExpensive(device, hOp, ...); assert( result == VK_OPERATION_DEFERRED_KHR ); // operation was deferred. Execute it asynchronously std::async::launch( [ hOp ] ( ) { vkDeferredOperationJoinKHR(device, hOp); result = vkGetDeferredOperationResultKHR(device, hOp); // deferred operation is now complete. 'result' indicates success or failure vkDestroyDeferredOperationKHR(device, hOp, pCallbacks); } ); ---- The following example illustrates extracting concurrency from a single deferred operation: [source,cpp] ---- // create a deferred operation VkDeferredOperationKHR hOp; VkResult result = vkCreateDeferredOperationKHR(device, pCallbacks, &hOp); assert(result == VK_SUCCESS); result = vkDoSomethingExpensive(device, hOp, ...); assert( result == VK_OPERATION_DEFERRED_KHR ); // Query the maximum amount of concurrency and clamp to the desired maximum uint32_t numLaunches = std::min(vkGetDeferredOperationMaxConcurrencyKHR(device, hOp), maxThreads); std::vector > joins; for (uint32_t i = 0; i < numLaunches; i++) { joins.emplace_back(std::async::launch( [ hOp ] ( ) { vkDeferredOperationJoinKHR(device, hOp); // in a job system, a return of VK_THREAD_IDLE_KHR should queue another // job, but it is not functionally required } )); } for (auto &f : joins) { f.get(); } result = vkGetDeferredOperationResultKHR(device, hOp); // deferred operation is now complete. 'result' indicates success or failure vkDestroyDeferredOperationKHR(device, hOp, pCallbacks); ---- The following example shows a subroutine which guarantees completion of a deferred operation, in the presence of multiple worker threads, and returns the result of the operation. [source,cpp] ---- VkResult FinishDeferredOperation(VkDeferredOperationKHR hOp) { // Attempt to join the operation until the implementation indicates that we should stop VkResult result = vkDeferredOperationJoinKHR(device, hOp); while( result == VK_THREAD_IDLE_KHR ) { std::this_thread::yield(); result = vkDeferredOperationJoinKHR(device, hOp); } switch( result ) { case VK_SUCCESS: { // deferred operation has finished. Query its result result = vkGetDeferredOperationResultKHR(device, hOp); } break; case VK_THREAD_DONE_KHR: { // deferred operation is being wrapped up by another thread // wait for that thread to finish do { std::this_thread::yield(); result = vkGetDeferredOperationResultKHR(device, hOp); } while( result == VK_NOT_READY ); } break; default: assert(false); // other conditions are illegal. break; } return result; } ---- === Issues . Should this extension have a VkPhysicalDevice*FeaturesKHR structure? *RESOLVED*: No. This extension does not add any functionality on its own and requires a dependent extension to actually enable functionality and thus there is no value in adding a feature structure. If necessary, any dependent extension could add a feature boolean if it wanted to indicate that it is adding optional deferral support. === Version History * Revision 1, 2019-12-05 (Josh Barczak, Daniel Koch) ** Initial draft. * Revision 2, 2020-03-06 (Daniel Koch, Tobias Hector) ** Add missing VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR enum ** fix sample code ** Clarified deferred operation parameter lifetimes (#2018,!3647) * Revision 3, 2020-05-15 (Josh Barczak) ** Clarify behavior of vkGetDeferredOperationMaxConcurrencyKHR, allowing it to return 0 if the operation is complete (#2036,!3850) * Revision 4, 2020-11-12 (Tobias Hector, Daniel Koch) ** Remove VkDeferredOperationInfoKHR and change return value semantics when deferred host operations are in use (#2067,3813) ** clarify return value of vkGetDeferredOperationResultKHR (#2339,!4110)