HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
VE_CommandPool.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: VE_CommandPool.h
7  *
8  * COMMENTS: Wraps a vulkan command pool
9  */
10 
11 #ifndef __VE_COMMANDPOOL_H__
12 #define __VE_COMMANDPOOL_H__
13 
14 #include "VE_API.h"
15 #include "VE_VK.h"
16 #include "VE_Result.h"
17 #include "VE_Device.h"
18 #include <UT/UT_NonCopyable.h>
19 
21 VEcreateCommandPool(VkDevice device, uint32_t queue_family_index, VkCommandPoolCreateFlags flags);
22 
23 void
24 VEdestroyCommandPool(VkDevice device, VkCommandPool pool);
25 
27 {
28  INITIAL,
29  RECORDING,
30  EXECUTABLE,
31  PENDING,
32  RETIRED,
34 };
35 
37 {
38 protected:
39  VkCommandBuffer myCb;
40 
41 protected:
42  void begin();
43  void end();
44 
45 public:
46  VE_CommandBuffer(VkCommandBuffer cb)
47  : myCb(cb)
48  {}
49 
50  void fillBuffer(VkBuffer, VkDeviceSize offset, uint32_t value);
51  void copyBuffer(VkBuffer src, VkBuffer dst, uint64_t src_offset, uint64_t dst_offset, uint64_t size);
52  void beginRenderPass(const VkRenderPassBeginInfo &);
53  void endRenderPass();
54 
55  VkCommandBuffer commandBuffer() { return myCb; }
56 };
57 
59 {
60  // maintain a reference to a state for tracking
61  CommandBufferState *myState = nullptr;
62 
63 public:
64  VE_CommandBufferHandle(VkCommandBuffer cb, CommandBufferState &state)
65  : VE_CommandBuffer(cb)
66  , myState(&state)
67  {
69  begin();
71  }
72 
74  {
75  end();
77  }
78 
80 
82  : VE_CommandBuffer(rhs)
83  {
84  *this = std::move(rhs);
85  }
86 
88  {
89  std::swap(myState, rhs.myState);
90  std::swap(myCb, rhs.myCb);
91  return *this;
92  }
93 
95  {
99  }
100 
102  {
106  }
107 };
108 
109 /// This internal helper function ensures mutual exclusion. It's used by the
110 /// header-only VE_CommandPool template: it should not be called directly.
112 
113 template <int CB_COUNT>
115 {
116  VkCommandPool myPool;
117  VkCommandBuffer myCommandBuffers[CB_COUNT];
118  CommandBufferState myCommandBufferStates[CB_COUNT];
119  VkFence myFence;
120 
121 public:
123  VE_Device &device,
125  {
126  auto r = VEcreateCommandPool(device.handle(), device.universalQueueFamilyIndex(), flags);
127  if (!r.ok())
128  return r.error();
129 
130  myPool = r.unpack();
131 
134  /*.pNext =*/nullptr,
135  /*.commandPool =*/myPool,
137  /*.commandBufferCount =*/CB_COUNT,
138  };
139 
140  VkResult res = vkAllocateCommandBuffers(device.handle(), &ai, myCommandBuffers);
141 
142  if (res != VK_SUCCESS)
143  return VE_Error(res);
144 
145  VkFenceCreateInfo fi = {};
147 
148  res = vkCreateFence(device.handle(), &fi, nullptr, &myFence);
149  if (res != VK_SUCCESS)
150  return VE_Error(res);
151 
152  for (int i = 0; i < CB_COUNT; ++i) {
153  myCommandBufferStates[i] = CommandBufferState::INITIAL;
154  }
155 
156  return VEvoidSuccess();
157  }
158 
159  void destroy(VkDevice device)
160  {
161  UT_ASSERT(!hasPendingWork());
162  vkDestroyCommandPool(device, myPool, nullptr);
163  vkDestroyFence(device, myFence, nullptr);
164  }
165 
166  template <int I>
167  VkCommandBuffer getVkCommandBuffer()
168  {
169  static_assert(I < CB_COUNT);
170  return myCommandBuffers[I];
171  }
172 
173  // The handle contains references into this command pool, so this must be
174  // called on an L-Value instance.
176  {
177  return VE_CommandBufferHandle(myCommandBuffers[0], myCommandBufferStates[0]);
178  }
179 
181  {
182  uint32_t exe_buf_count = 0;
183  VkCommandBuffer executable_bufs[CB_COUNT];
184 
185  for (int i = 0; i < CB_COUNT; ++i)
186  {
187  if (myCommandBufferStates[i] != CommandBufferState::EXECUTABLE)
188  continue;
189  executable_bufs[exe_buf_count++] = myCommandBuffers[i];
190  myCommandBufferStates[i] = CommandBufferState::PENDING;
191  }
192 
193  if (exe_buf_count == 0)
194  return VEvoidSuccess();
195 
196  VkSubmitInfo si = {
197  /*.sType =*/VK_STRUCTURE_TYPE_SUBMIT_INFO,
198  /*.pNext =*/nullptr,
199  /*.waitSemaphoreCount =*/0,
200  /*.pWaitSemaphores =*/nullptr,
201  /*.pWaitDstStageMask =*/nullptr,
202  /*.commandBufferCount =*/exe_buf_count,
203  /*.pCommandBuffers =*/executable_bufs,
204  /*.signalSemaphoreCount =*/0,
205  /*.pSignalSemaphores =*/nullptr
206  };
207 
208  VkResult r = VEsubmitToQueueInternal(queue, si, myFence);
209  if (r != VK_SUCCESS)
210  return VE_Error(r);
211 
212  return VEvoidSuccess();
213  }
214 
215  bool hasExecutableWork() const
216  {
217  for (int i = 0; i < CB_COUNT; ++i)
218  {
219  if (myCommandBufferStates[i] == CommandBufferState::EXECUTABLE)
220  return true;
221  }
222  return false;
223  }
224 
225  bool hasPendingWork() const
226  {
227  for (int i = 0; i < CB_COUNT; ++i)
228  {
229  if (myCommandBufferStates[i] == CommandBufferState::PENDING)
230  return true;
231  }
232  return false;
233  }
234 
236  {
237  // no work is pending
238  if (!hasPendingWork())
239  return VEvoidSuccess();
240 
241  // wait for up to 10 seconds. if we aren't done by then its likely
242  // something went very wrong.
243  VkResult r = vkWaitForFences(device, 1, &myFence, VK_TRUE, 10'000'000'000);
244  if (r != VK_SUCCESS)
245  return VE_Error(r);
246 
247  for (int i = 0; i < CB_COUNT; ++i)
248  {
249  if (myCommandBufferStates[i] == CommandBufferState::PENDING)
250  myCommandBufferStates[i] = CommandBufferState::RETIRED;
251  }
252 
253  return VEvoidSuccess();
254  }
255 };
256 
257 template <int CB_COUNT>
258 class VE_API VE_CommandPoolTransient : public VE_CommandPool<CB_COUNT>
259 {
260 public:
261  static VE_Result<VE_CommandPoolTransient> create(
262  VE_Device &device)
263  {
264  VE_CommandPoolTransient pool;
265  auto r = pool.init(device, VK_COMMAND_POOL_CREATE_TRANSIENT_BIT);
266  if (!r.ok())
267  return r.error();
268 
269  return pool;
270  }
271 };
272 
273 class VE_API VE_CommandBufferSingleUse
274 {
275  using CmdPool = VE_CommandPoolTransient<1>;
276 
277  CmdPool myPool;
278  VkQueue myQueue;
279  VkDevice myDevice = nullptr;
280 
281  VE_CommandBufferSingleUse(CmdPool &&pool, VkDevice d, VkQueue q) : myPool(pool), myDevice(d), myQueue(q) {}
282 public:
283  ~VE_CommandBufferSingleUse()
284  {
285  if (!myDevice)
286  return;
287 
288  if (myPool.hasExecutableWork())
289  {
290  auto r = submitAndWait();
291  UT_ASSERT(r.ok());
292  }
293  myPool.destroy(myDevice);
294  }
295 
296  static VE_Result<VE_CommandBufferSingleUse> create(VE_Device &device)
297  {
298  auto r = CmdPool::create(device);
299  if (!r.ok())
300  return r.error();
301 
302  VE_CommandBufferSingleUse buf(r.unpack(), device.handle(), device.universalQueue());
303 
304  return buf;
305  }
306 
307  VE_CommandBufferHandle commandBuffer() & { return myPool.commandBuffer(); }
308 
309  VE_VoidResult submitAndWait()
310  {
311  auto r = myPool.submitToQueue(myQueue);
312  if (!r.ok())
313  return r.error();
314 
315  r = myPool.waitOnInFlightCommands(myDevice);
316  if (!r.ok())
317  return r.error();
318 
319  return VEvoidSuccess();
320  }
321 
322  UT_NON_COPYABLE(VE_CommandBufferSingleUse);
323 
324  VE_CommandBufferSingleUse(VE_CommandBufferSingleUse &&rhs) noexcept
325  {
326  *this = std::move(rhs);
327  }
328 
329  VE_CommandBufferSingleUse &operator=(VE_CommandBufferSingleUse &&rhs) noexcept
330  {
331  std::swap(myDevice, rhs.myDevice);
332  myQueue = rhs.myQueue;
333  myPool = rhs.myPool;
334  return *this;
335  }
336 };
337 
338 
339 #endif
VE_CommandBufferHandle(VkCommandBuffer cb, CommandBufferState &state)
GLbitfield flags
Definition: glcorearb.h:1596
uint32_t universalQueueFamilyIndex() const
VkResult
Definition: vulkan_core.h:139
VE_API VkResult VEsubmitToQueueInternal(VkQueue &, VkSubmitInfo &, VkFence &)
#define VK_TRUE
Definition: vulkan_core.h:130
void swap(UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &a, UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &b)
Definition: UT_ArraySet.h:1639
VkStructureType sType
Definition: vulkan_core.h:3312
VKAPI_ATTR VkResult VKAPI_CALL vkCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence)
VE_API VE_Result< VkCommandPool > VEcreateCommandPool(VkDevice device, uint32_t queue_family_index, VkCommandPoolCreateFlags flags)
VKAPI_ATTR void VKAPI_CALL vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocationCallbacks *pAllocator)
VKAPI_ATTR void VKAPI_CALL vkDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator)
GLintptr offset
Definition: glcorearb.h:665
VE_VoidResult init(VE_Device &device, VkCommandPoolCreateFlags flags)
#define VE_API
Definition: VE_API.h:20
VKAPI_ATTR VkResult VKAPI_CALL vkWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout)
bool hasPendingWork() const
GLuint GLuint end
Definition: glcorearb.h:475
VkCommandBuffer myCb
VE_VoidResult waitOnInFlightCommands(VkDevice device)
#define UT_NON_COPYABLE(CLASS)
Define deleted copy constructor and assignment operator inside a class.
VkFlags VkCommandPoolCreateFlags
Definition: vulkan_core.h:2747
VkDevice handle() const
Definition: VE_Device.h:113
*get result *(waiting if necessary)*A common idiom is to fire a bunch of sub tasks at the queue
Definition: thread.h:623
VE_CommandBufferHandle(VE_CommandBufferHandle &&rhs) noexcept
void beginRenderPass(const VkRenderPassBeginInfo &bi)
GLsizeiptr size
Definition: glcorearb.h:664
GLenum GLenum dst
Definition: glcorearb.h:1793
VE_CommandBuffer(VkCommandBuffer cb)
VE_CommandBufferHandle & operator=(VE_CommandBufferHandle &&rhs) noexcept
void beginRenderPass(const VkRenderPassBeginInfo &)
VE_VoidResult submitToQueue(VkQueue queue)
VKAPI_ATTR VkResult VKAPI_CALL vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo *pAllocateInfo, VkCommandBuffer *pCommandBuffers)
void destroy(VkDevice device)
void VEdestroyCommandPool(VkDevice device, VkCommandPool pool)
uint64_t VkDeviceSize
Definition: vulkan_core.h:95
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
Definition: core.h:1131
GLboolean r
Definition: glcorearb.h:1222
bool hasExecutableWork() const
VE_CommandBufferHandle commandBuffer()&
VkCommandBuffer getVkCommandBuffer()
VkCommandBuffer commandBuffer()
**Note that the tasks the is the thread number *for the pool
Definition: thread.h:637
CommandBufferState
GLenum src
Definition: glcorearb.h:1793
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:558