• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2014-2023 The Khronos Group Inc.
2//
3// SPDX-License-Identifier: CC-BY-4.0
4
5[[deferred-host-operations]]
6= Deferred Host Operations
7
8Certain Vulkan commands are inherently expensive for the host CPU to
9execute.
10It is often desirable to offload such work onto background threads, and to
11parallelize the work across multiple CPUs.
12The concept of _deferred operations_ allows applications and drivers to
13coordinate the execution of expensive host commands using an
14application-managed thread pool.
15
16The `apiext:VK_KHR_deferred_host_operations` extension defines the
17infrastructure and usage patterns for _deferrable commands_, but does not
18specify any commands as deferrable.
19This is left to additional dependent extensions.
20Commands must: not be deferred unless the deferral is specifically allowed
21by another extension which depends on
22`apiext:VK_KHR_deferred_host_operations`.
23This specification will refer to such extensions as _deferral extensions_.
24
25
26[[deferred-host-operations-requesting]]
27== Requesting Deferral
28
29When an application requests an operation deferral, the implementation may:
30defer the operation.
31When deferral is requested and the implementation defers any operation, the
32implementation must: return ename:VK_OPERATION_DEFERRED_KHR as the success
33code if no errors occurred.
34When deferral is requested, the implementation should: defer the operation
35when the workload is significant, however if the implementation chooses not
36to defer any of the requested operations and instead executes all of them
37immediately, the implementation must: return
38ename:VK_OPERATION_NOT_DEFERRED_KHR as the success code if no errors
39occurred.
40
41A deferred operation is created _complete_ with an initial result value of
42ename:VK_SUCCESS.
43The deferred operation becomes _pending_ when an operation has been
44successfully deferred with that deferred operation object.
45
46A deferred operation is considered pending until the deferred operation
47completes.
48A pending deferred operation becomes _complete_ when it has been fully
49executed by one or more threads.
50Pending deferred operations will never complete until they are _joined_ by
51an application thread, using flink:vkDeferredOperationJoinKHR.
52Applications can: join multiple threads to the same deferred operation,
53enabling concurrent execution of subtasks within that operation.
54
55The application can: query the status of a slink:VkDeferredOperationKHR
56using the flink:vkGetDeferredOperationMaxConcurrencyKHR or
57flink:vkGetDeferredOperationResultKHR commands.
58
59Parameters to the command requesting a deferred operation may: be accessed
60by the implementation at any time until the deferred operation enters the
61complete state.
62The application must: obey the following rules while a deferred operation is
63pending:
64
65  * Externally synchronized parameters must: not be accessed.
66  * Pointer parameters must: not be modified (e.g. reallocated/freed).
67  * The contents of pointer parameters which may: be read by the command
68    must: not be modified.
69  * The contents of pointer parameters which may: be written by the command
70    must: not be read.
71  * Vulkan object parameters must: not be passed as externally synchronized
72    parameters to any other command.
73
74When the deferred operation is complete, the application should: call
75flink:vkGetDeferredOperationResultKHR to obtain the elink:VkResult
76indicating success or failure of the operation.
77The elink:VkResult value returned will be one of the values that the command
78requesting the deferred operation is able to return.
79Writes to output parameters of the requesting command will happen-before the
80deferred operation is complete.
81
82When a deferral is requested for a command, the implementation may: perform
83memory management operations on the allocator supplied to
84flink:vkCreateDeferredOperationKHR for the deferred operation object, as
85described in the <<memory-allocation,Memory Allocation>> chapter.
86Such allocations must: occur on the thread which requests deferral.
87
88If an allocator was supplied for the deferred command at the time of the
89deferral request, then the implementation may: perform memory management
90operations on this allocator during the execution of
91flink:vkDeferredOperationJoinKHR.
92These operations may: occur concurrently and may: be performed by any joined
93thread.
94The application must: ensure that the supplied allocator is able to operate
95correctly under these conditions.
96
97
98== Deferred Host Operations API
99
100[open,refpage='VkDeferredOperationKHR',desc='A deferred operation',type='handles']
101--
102The sname:VkDeferredOperationKHR handle is defined as:
103
104include::{generated}/api/handles/VkDeferredOperationKHR.adoc[]
105
106This handle refers to a tracking structure which manages the execution state
107for a deferred command.
108--
109
110[open,refpage='vkCreateDeferredOperationKHR',desc='Create a deferred operation handle',type='protos']
111--
112:refpage: vkCreateDeferredOperationKHR
113
114To construct the tracking object for a deferred command, call:
115
116include::{generated}/api/protos/vkCreateDeferredOperationKHR.adoc[]
117
118  * pname:device is the device which owns pname:operation.
119  * pname:pAllocator controls host memory allocation as described in the
120    <<memory-allocation,Memory Allocation>> chapter.
121  * pname:pDeferredOperation is a pointer to a handle in which the created
122    slink:VkDeferredOperationKHR is returned.
123
124include::{generated}/validity/protos/vkCreateDeferredOperationKHR.adoc[]
125--
126
127[open,refpage='vkDeferredOperationJoinKHR',desc='Assign a thread to a deferred operation',type='protos']
128--
129:refpage: vkDeferredOperationJoinKHR
130
131To assign a thread to a deferred operation, call:
132
133include::{generated}/api/protos/vkDeferredOperationJoinKHR.adoc[]
134
135  * pname:device is the device which owns pname:operation.
136  * pname:operation is the deferred operation that the calling thread should
137    work on.
138
139The fname:vkDeferredOperationJoinKHR command will execute a portion of the
140deferred operation on the calling thread.
141
142The return value will be one of the following:
143
144  * A return value of ename:VK_SUCCESS indicates that pname:operation is
145    complete.
146    The application should: use flink:vkGetDeferredOperationResultKHR to
147    retrieve the result of pname:operation.
148  * A return value of ename:VK_THREAD_DONE_KHR indicates that the deferred
149    operation is not complete, but there is no work remaining to assign to
150    threads.
151    Future calls to flink:vkDeferredOperationJoinKHR are not necessary and
152    will simply harm performance.
153    This situation may: occur when other threads executing
154    flink:vkDeferredOperationJoinKHR are about to complete pname:operation,
155    and the implementation is unable to partition the workload any further.
156  * A return value of ename:VK_THREAD_IDLE_KHR indicates that the deferred
157    operation is not complete, and there is no work for the thread to do at
158    the time of the call.
159    This situation may: occur if the operation encounters a temporary
160    reduction in parallelism.
161    By returning ename:VK_THREAD_IDLE_KHR, the implementation is signaling
162    that it expects that more opportunities for parallelism will emerge as
163    execution progresses, and that future calls to
164    flink:vkDeferredOperationJoinKHR can: be beneficial.
165    In the meantime, the application can: perform other work on the calling
166    thread.
167
168Implementations must: guarantee forward progress by enforcing the following
169invariants:
170
171  1. If only one thread has invoked flink:vkDeferredOperationJoinKHR on a
172     given operation, that thread must: execute the operation to completion
173     and return ename:VK_SUCCESS.
174  2. If multiple threads have concurrently invoked
175     flink:vkDeferredOperationJoinKHR on the same operation, then at least
176     one of them must: complete the operation and return ename:VK_SUCCESS.
177
178include::{generated}/validity/protos/vkDeferredOperationJoinKHR.adoc[]
179--
180
181[open,refpage='vkDestroyDeferredOperationKHR',desc='Destroy a deferred operation handle',type='protos']
182--
183:refpage: vkDestroyDeferredOperationKHR
184
185When a deferred operation is completed, the application can: destroy the
186tracking object by calling:
187
188include::{generated}/api/protos/vkDestroyDeferredOperationKHR.adoc[]
189
190  * pname:device is the device which owns pname:operation.
191  * pname:operation is the completed operation to be destroyed.
192  * pname:pAllocator controls host memory allocation as described in the
193    <<memory-allocation,Memory Allocation>> chapter.
194
195.Valid Usage
196****
197ifndef::VKSC_VERSION_1_0[]
198  * [[VUID-vkDestroyDeferredOperationKHR-operation-03434]]
199    If sname:VkAllocationCallbacks were provided when pname:operation was
200    created, a compatible set of callbacks must: be provided here
201  * [[VUID-vkDestroyDeferredOperationKHR-operation-03435]]
202    If no sname:VkAllocationCallbacks were provided when pname:operation was
203    created, pname:pAllocator must: be `NULL`
204endif::VKSC_VERSION_1_0[]
205  * [[VUID-vkDestroyDeferredOperationKHR-operation-03436]]
206    pname:operation must: be completed
207****
208include::{generated}/validity/protos/vkDestroyDeferredOperationKHR.adoc[]
209--
210
211[open,refpage='vkGetDeferredOperationMaxConcurrencyKHR',desc='Query the maximum concurrency on a deferred operation',type='protos']
212--
213:refpage: vkGetDeferredOperationMaxConcurrencyKHR
214
215To query the number of additional threads that can usefully be joined to a
216deferred operation, call:
217
218include::{generated}/api/protos/vkGetDeferredOperationMaxConcurrencyKHR.adoc[]
219
220  * pname:device is the device which owns pname:operation.
221  * pname:operation is the deferred operation to be queried.
222
223The returned value is the maximum number of threads that can usefully
224execute a deferred operation concurrently, reported for the state of the
225deferred operation at the point this command is called.
226This value is intended to be used to better schedule work onto available
227threads.
228Applications can: join any number of threads to the deferred operation and
229expect it to eventually complete, though excessive joins may: return
230ename:VK_THREAD_DONE_KHR immediately, performing no useful work.
231
232If pname:operation is complete,
233fname:vkGetDeferredOperationMaxConcurrencyKHR returns zero.
234
235If pname:operation is currently joined to any threads, the value returned by
236this command may: immediately be out of date.
237
238If pname:operation is pending, implementations must: not return zero unless
239at least one thread is currently executing flink:vkDeferredOperationJoinKHR
240on pname:operation.
241If there are such threads, the implementation should: return an estimate of
242the number of additional threads which it could profitably use.
243
244Implementations may: return [eq]#2^32^-1# to indicate that the maximum
245concurrency is unknown and cannot be easily derived.
246Implementations may: return values larger than the maximum concurrency
247available on the host CPU.
248In these situations, an application should: clamp the return value rather
249than oversubscribing the machine.
250
251[NOTE]
252.Note
253====
254The recommended usage pattern for applications is to query this value once,
255after deferral, and schedule no more than the specified number of threads to
256join the operation.
257Each time a joined thread receives ename:VK_THREAD_IDLE_KHR, the application
258should schedule an additional join at some point in the future, but is not
259required to do so.
260====
261
262include::{generated}/validity/protos/vkGetDeferredOperationMaxConcurrencyKHR.adoc[]
263--
264
265[open,refpage='vkGetDeferredOperationResultKHR',desc='Query the result of a deferred operation',type='protos']
266--
267:refpage: vkGetDeferredOperationResultKHR
268
269The fname:vkGetDeferredOperationResultKHR function is defined as:
270
271include::{generated}/api/protos/vkGetDeferredOperationResultKHR.adoc[]
272
273  * pname:device is the device which owns pname:operation.
274  * pname:operation is the operation whose deferred result is being queried.
275
276If no command has been deferred on pname:operation,
277fname:vkGetDeferredOperationResultKHR returns ename:VK_SUCCESS.
278
279If the deferred operation is pending, fname:vkGetDeferredOperationResultKHR
280returns ename:VK_NOT_READY.
281
282If the deferred operation is complete, it returns the appropriate return
283value from the original command.
284This value must: be one of the elink:VkResult values which could have been
285returned by the original command if the operation had not been deferred.
286
287include::{generated}/validity/protos/vkGetDeferredOperationResultKHR.adoc[]
288--
289
290