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