VK_KHR_deferred_host_operations
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 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 VK_KHR_deferred_host_operations.
New Object Types
New Commands
- vkCreateDeferredOperationKHR
- vkDeferredOperationJoinKHR
- vkDestroyDeferredOperationKHR
- vkGetDeferredOperationMaxConcurrencyKHR
- vkGetDeferredOperationResultKHR
New Enum Constants
VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME
VK_KHR_DEFERRED_HOST_OPERATIONS_SPEC_VERSION
- Extending VkObjectType:
VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR
- Extending VkResult:
VK_OPERATION_DEFERRED_KHR
VK_OPERATION_NOT_DEFERRED_KHR
VK_THREAD_DONE_KHR
VK_THREAD_IDLE_KHR
Code Examples
The following examples will illustrate the concept of deferrable operations
using a hypothetical example.
The command vkDoSomethingExpensive
denotes a deferrable command.
The following example illustrates how a vulkan application might request deferral of an expensive operation:
// 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:
// 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<std::future<void> > 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.
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)