1// Copyright 2014-2022 The Khronos Group Inc. 2// 3// SPDX-License-Identifier: CC-BY-4.0 4 5include::{generated}/meta/{refprefix}VK_KHR_deferred_host_operations.adoc[] 6 7=== Other Extension Metadata 8 9*Last Modified Date*:: 10 2020-11-12 11*IP Status*:: 12 No known IP claims. 13*Contributors*:: 14 - Joshua Barczak, Intel 15 - Jeff Bolz, NVIDIA 16 - Daniel Koch, NVIDIA 17 - Slawek Grajewski, Intel 18 - Tobias Hector, AMD 19 - Yuriy O'Donnell, Epic 20 - Eric Werness, NVIDIA 21 - Baldur Karlsson, Valve 22 - Jesse Barker, Unity 23 - Contributors to VK_KHR_acceleration_structure, 24 VK_KHR_ray_tracing_pipeline 25 26=== Description 27 28The `apiext:VK_KHR_deferred_host_operations` extension defines the 29infrastructure and usage patterns for deferrable commands, but does not 30specify any commands as deferrable. 31This is left to additional dependent extensions. 32Commands must: not be deferred unless the deferral is specifically allowed 33by another extension which depends on 34`apiext:VK_KHR_deferred_host_operations`. 35 36include::{generated}/interfaces/VK_KHR_deferred_host_operations.adoc[] 37 38=== Code Examples 39 40The following examples will illustrate the concept of deferrable operations 41using a hypothetical example. 42The command ftext:vkDoSomethingExpensive denotes a deferrable command. 43 44The following example illustrates how a vulkan application might request 45deferral of an expensive operation: 46 47[source,cpp] 48---- 49// create a deferred operation 50VkDeferredOperationKHR hOp; 51VkResult result = vkCreateDeferredOperationKHR(device, pCallbacks, &hOp); 52assert(result == VK_SUCCESS); 53 54result = vkDoSomethingExpensive(device, hOp, ...); 55assert( result == VK_OPERATION_DEFERRED_KHR ); 56 57// operation was deferred. Execute it asynchronously 58std::async::launch( 59 [ hOp ] ( ) 60 { 61 vkDeferredOperationJoinKHR(device, hOp); 62 63 result = vkGetDeferredOperationResultKHR(device, hOp); 64 65 // deferred operation is now complete. 'result' indicates success or failure 66 67 vkDestroyDeferredOperationKHR(device, hOp, pCallbacks); 68 } 69); 70 71---- 72 73The following example illustrates extracting concurrency from a single 74deferred operation: 75 76[source,cpp] 77---- 78 79// create a deferred operation 80VkDeferredOperationKHR hOp; 81VkResult result = vkCreateDeferredOperationKHR(device, pCallbacks, &hOp); 82assert(result == VK_SUCCESS); 83 84result = vkDoSomethingExpensive(device, hOp, ...); 85assert( result == VK_OPERATION_DEFERRED_KHR ); 86 87// Query the maximum amount of concurrency and clamp to the desired maximum 88uint32_t numLaunches = std::min(vkGetDeferredOperationMaxConcurrencyKHR(device, hOp), maxThreads); 89 90std::vector<std::future<void> > joins; 91 92for (uint32_t i = 0; i < numLaunches; i++) { 93 joins.emplace_back(std::async::launch( 94 [ hOp ] ( ) 95 { 96 vkDeferredOperationJoinKHR(device, hOp); 97 // in a job system, a return of VK_THREAD_IDLE_KHR should queue another 98 // job, but it is not functionally required 99 } 100 )); 101} 102 103for (auto &f : joins) { 104 f.get(); 105} 106 107result = vkGetDeferredOperationResultKHR(device, hOp); 108 109// deferred operation is now complete. 'result' indicates success or failure 110 111vkDestroyDeferredOperationKHR(device, hOp, pCallbacks); 112 113---- 114 115 116The following example shows a subroutine which guarantees completion of a 117deferred operation, in the presence of multiple worker threads, and returns 118the result of the operation. 119 120[source,cpp] 121---- 122 123VkResult FinishDeferredOperation(VkDeferredOperationKHR hOp) 124{ 125 // Attempt to join the operation until the implementation indicates that we should stop 126 127 VkResult result = vkDeferredOperationJoinKHR(device, hOp); 128 while( result == VK_THREAD_IDLE_KHR ) 129 { 130 std::this_thread::yield(); 131 result = vkDeferredOperationJoinKHR(device, hOp); 132 } 133 134 switch( result ) 135 { 136 case VK_SUCCESS: 137 { 138 // deferred operation has finished. Query its result 139 result = vkGetDeferredOperationResultKHR(device, hOp); 140 } 141 break; 142 143 case VK_THREAD_DONE_KHR: 144 { 145 // deferred operation is being wrapped up by another thread 146 // wait for that thread to finish 147 do 148 { 149 std::this_thread::yield(); 150 result = vkGetDeferredOperationResultKHR(device, hOp); 151 } while( result == VK_NOT_READY ); 152 } 153 break; 154 155 default: 156 assert(false); // other conditions are illegal. 157 break; 158 } 159 160 return result; 161} 162---- 163 164=== Issues 165 166. Should this extension have a VkPhysicalDevice*FeaturesKHR structure? 167 168*RESOLVED*: No. 169This extension does not add any functionality on its own and requires a 170dependent extension to actually enable functionality and thus there is no 171value in adding a feature structure. 172If necessary, any dependent extension could add a feature boolean if it 173wanted to indicate that it is adding optional deferral support. 174 175=== Version History 176 177 * Revision 1, 2019-12-05 (Josh Barczak, Daniel Koch) 178 ** Initial draft. 179 * Revision 2, 2020-03-06 (Daniel Koch, Tobias Hector) 180 ** Add missing VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR enum 181 ** fix sample code 182 ** Clarified deferred operation parameter lifetimes (#2018,!3647) 183 * Revision 3, 2020-05-15 (Josh Barczak) 184 ** Clarify behavior of vkGetDeferredOperationMaxConcurrencyKHR, allowing 185 it to return 0 if the operation is complete (#2036,!3850) 186 * Revision 4, 2020-11-12 (Tobias Hector, Daniel Koch) 187 ** Remove VkDeferredOperationInfoKHR and change return value semantics 188 when deferred host operations are in use (#2067,3813) 189 ** clarify return value of vkGetDeferredOperationResultKHR (#2339,!4110) 190