blob: dc2220f718894c5e6a21e9b825ad6989694d0c2e [file] [log] [blame]
// Copyright 2014-2021 The Khronos Group, Inc.
//
// SPDX-License-Identifier: CC-BY-4.0
include::{generated}/meta/{refprefix}VK_KHR_deferred_host_operations.txt[]
=== 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.txt[]
=== Code Examples
The following examples will illustrate the concept of deferrable operations
using a hypothetical example.
The command ftext:vkDoSomethingExpensiveEXT denotes a deferrable command.
The structure stext:VkExpensiveOperationArgsEXT represents the arguments
which it would normally accept.
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<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.
[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)