BsVulkanCommandBuffer.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsVulkanCommandBuffer.h"
  4. #include "BsVulkanCommandBufferManager.h"
  5. #include "BsVulkanUtility.h"
  6. #include "BsVulkanDevice.h"
  7. #include "BsVulkanGpuParams.h"
  8. #include "BsVulkanQueue.h"
  9. #include "BsVulkanTexture.h"
  10. #include "BsVulkanHardwareBuffer.h"
  11. namespace BansheeEngine
  12. {
  13. VulkanCmdBufferPool::VulkanCmdBufferPool(VulkanDevice& device)
  14. :mDevice(device), mNextId(1)
  15. {
  16. for (UINT32 i = 0; i < GQT_COUNT; i++)
  17. {
  18. UINT32 familyIdx = device.getQueueFamily((GpuQueueType)i);
  19. if (familyIdx == (UINT32)-1)
  20. continue;
  21. VkCommandPoolCreateInfo poolCI;
  22. poolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
  23. poolCI.pNext = nullptr;
  24. poolCI.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
  25. poolCI.queueFamilyIndex = familyIdx;
  26. PoolInfo& poolInfo = mPools[familyIdx];
  27. poolInfo.queueFamily = familyIdx;
  28. memset(poolInfo.buffers, 0, sizeof(poolInfo.buffers));
  29. vkCreateCommandPool(device.getLogical(), &poolCI, gVulkanAllocator, &poolInfo.pool);
  30. }
  31. }
  32. VulkanCmdBufferPool::~VulkanCmdBufferPool()
  33. {
  34. // Note: Shutdown should be the only place command buffers are destroyed at, as the system relies on the fact that
  35. // they won't be destroyed during normal operation.
  36. for(auto& entry : mPools)
  37. {
  38. PoolInfo& poolInfo = entry.second;
  39. for (UINT32 i = 0; i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY; i++)
  40. {
  41. VulkanCmdBuffer* buffer = poolInfo.buffers[i];
  42. if (buffer == nullptr)
  43. break;
  44. bs_delete(buffer);
  45. }
  46. vkDestroyCommandPool(mDevice.getLogical(), poolInfo.pool, gVulkanAllocator);
  47. }
  48. }
  49. VulkanCmdBuffer* VulkanCmdBufferPool::getBuffer(UINT32 queueFamily, bool secondary)
  50. {
  51. auto iterFind = mPools.find(queueFamily);
  52. if (iterFind != mPools.end())
  53. return nullptr;
  54. VulkanCmdBuffer** buffers = iterFind->second.buffers;
  55. UINT32 i = 0;
  56. for(; i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY; i++)
  57. {
  58. if (buffers[i] == nullptr)
  59. break;
  60. if(buffers[i]->mState == VulkanCmdBuffer::State::Ready)
  61. {
  62. buffers[i]->begin();
  63. return buffers[i];
  64. }
  65. }
  66. assert(i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY &&
  67. "Too many command buffers allocated. Increment BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY to a higher value. ");
  68. buffers[i] = createBuffer(queueFamily, secondary);
  69. buffers[i]->begin();
  70. return buffers[i];
  71. }
  72. VulkanCmdBuffer* VulkanCmdBufferPool::createBuffer(UINT32 queueFamily, bool secondary)
  73. {
  74. auto iterFind = mPools.find(queueFamily);
  75. if (iterFind != mPools.end())
  76. return nullptr;
  77. const PoolInfo& poolInfo = iterFind->second;
  78. return bs_new<VulkanCmdBuffer>(mDevice, mNextId++, poolInfo.pool, poolInfo.queueFamily, secondary);
  79. }
  80. VulkanCmdBuffer::VulkanCmdBuffer(VulkanDevice& device, UINT32 id, VkCommandPool pool, UINT32 queueFamily, bool secondary)
  81. : mId(id), mQueueFamily(queueFamily), mState(State::Ready), mDevice(device), mPool(pool), mFenceCounter(0)
  82. , mFramebuffer(VK_NULL_HANDLE), mRenderPass(VK_NULL_HANDLE), mPresentSemaphore(VK_NULL_HANDLE)
  83. , mRenderTargetWidth(0), mRenderTargetHeight(0), mGlobalQueueIdx(-1)
  84. {
  85. VkCommandBufferAllocateInfo cmdBufferAllocInfo;
  86. cmdBufferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  87. cmdBufferAllocInfo.pNext = nullptr;
  88. cmdBufferAllocInfo.commandPool = pool;
  89. cmdBufferAllocInfo.level = secondary ? VK_COMMAND_BUFFER_LEVEL_SECONDARY : VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  90. cmdBufferAllocInfo.commandBufferCount = 1;
  91. VkResult result = vkAllocateCommandBuffers(mDevice.getLogical(), &cmdBufferAllocInfo, &mCmdBuffer);
  92. assert(result == VK_SUCCESS);
  93. VkFenceCreateInfo fenceCI;
  94. fenceCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
  95. fenceCI.pNext = nullptr;
  96. fenceCI.flags = 0;
  97. result = vkCreateFence(mDevice.getLogical(), &fenceCI, gVulkanAllocator, &mFence);
  98. assert(result == VK_SUCCESS);
  99. VkSemaphoreCreateInfo semaphoreCI;
  100. semaphoreCI.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
  101. semaphoreCI.pNext = nullptr;
  102. semaphoreCI.flags = 0;
  103. result = vkCreateSemaphore(mDevice.getLogical(), &semaphoreCI, gVulkanAllocator, &mSemaphore);
  104. assert(result == VK_SUCCESS);
  105. }
  106. VulkanCmdBuffer::~VulkanCmdBuffer()
  107. {
  108. VkDevice device = mDevice.getLogical();
  109. if(mState == State::Submitted)
  110. {
  111. // Wait 1s
  112. UINT64 waitTime = 1000 * 1000 * 1000;
  113. VkResult result = vkWaitForFences(device, 1, &mFence, true, waitTime);
  114. assert(result == VK_SUCCESS || result == VK_TIMEOUT);
  115. if (result == VK_TIMEOUT)
  116. LOGWRN("Freeing a command buffer before done executing because fence wait expired!");
  117. // Resources have been marked as used, make sure to notify them we're done with them
  118. refreshFenceStatus();
  119. }
  120. else if(mState != State::Ready)
  121. {
  122. // Notify any resources that they are no longer bound
  123. for (auto& entry : mResources)
  124. {
  125. ResourceUseHandle& useHandle = entry.second;
  126. assert(useHandle.used);
  127. entry.first->notifyUnbound();
  128. }
  129. for (auto& entry : mImages)
  130. {
  131. ResourceUseHandle& useHandle = entry.second.useHandle;
  132. assert(useHandle.used);
  133. entry.first->notifyUnbound();
  134. }
  135. for (auto& entry : mBuffers)
  136. {
  137. ResourceUseHandle& useHandle = entry.second.useHandle;
  138. assert(useHandle.used);
  139. entry.first->notifyUnbound();
  140. }
  141. }
  142. vkDestroyFence(device, mFence, gVulkanAllocator);
  143. vkDestroySemaphore(device, mSemaphore, gVulkanAllocator);
  144. vkFreeCommandBuffers(device, mPool, 1, &mCmdBuffer);
  145. }
  146. UINT32 VulkanCmdBuffer::getDeviceIdx() const
  147. {
  148. return mDevice.getIndex();
  149. }
  150. void VulkanCmdBuffer::begin()
  151. {
  152. assert(mState == State::Ready);
  153. VkCommandBufferBeginInfo beginInfo;
  154. beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  155. beginInfo.pNext = nullptr;
  156. beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  157. beginInfo.pInheritanceInfo = nullptr;
  158. VkResult result = vkBeginCommandBuffer(mCmdBuffer, &beginInfo);
  159. assert(result == VK_SUCCESS);
  160. mState = State::Recording;
  161. }
  162. void VulkanCmdBuffer::end()
  163. {
  164. assert(mState == State::Recording);
  165. VkResult result = vkEndCommandBuffer(mCmdBuffer);
  166. assert(result == VK_SUCCESS);
  167. mState = State::RecordingDone;
  168. }
  169. void VulkanCmdBuffer::beginRenderPass()
  170. {
  171. assert(mState == State::Recording);
  172. if (mFramebuffer == VK_NULL_HANDLE || mRenderPass == VK_NULL_HANDLE)
  173. {
  174. LOGWRN("Attempting to begin a render pass but no render target is bound to the command buffer.");
  175. return;
  176. }
  177. VkRenderPassBeginInfo renderPassBeginInfo;
  178. renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  179. renderPassBeginInfo.pNext = nullptr;
  180. renderPassBeginInfo.framebuffer = mFramebuffer;
  181. renderPassBeginInfo.renderPass = mRenderPass;
  182. renderPassBeginInfo.renderArea.offset.x = 0;
  183. renderPassBeginInfo.renderArea.offset.y = 0;
  184. renderPassBeginInfo.renderArea.extent.width = mRenderTargetWidth;
  185. renderPassBeginInfo.renderArea.extent.height = mRenderTargetHeight;
  186. // TODO: Handle clears (if provided) here. See VulkanRenderAPI::clearRenderTarget.
  187. // - Potential problem is that we might need different framebuffers depending on whether we use load or clear
  188. // ops during render pass start.
  189. renderPassBeginInfo.clearValueCount = 0; // TODO
  190. renderPassBeginInfo.pClearValues = nullptr; // TODO
  191. vkCmdBeginRenderPass(mCmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
  192. mState = State::RecordingRenderPass;
  193. }
  194. void VulkanCmdBuffer::endRenderPass()
  195. {
  196. assert(mState == State::RecordingRenderPass);
  197. vkCmdEndRenderPass(mCmdBuffer);
  198. mState = State::Recording;
  199. }
  200. void VulkanCmdBuffer::submit(VulkanQueue* queue, UINT32 queueIdx, UINT32 syncMask)
  201. {
  202. assert(isReadyForSubmit());
  203. // Issue pipeline barriers for queue transitions (need to happen on original queue first, then on new queue)
  204. for (auto& entry : mBuffers)
  205. {
  206. VulkanBuffer* resource = static_cast<VulkanBuffer*>(entry.first);
  207. if (!resource->isExclusive())
  208. continue;
  209. UINT32 currentQueueFamily = resource->getQueueFamily();
  210. if (currentQueueFamily != mQueueFamily)
  211. {
  212. Vector<VkBufferMemoryBarrier>& barriers = mTransitionInfoTemp[currentQueueFamily].bufferBarriers;
  213. barriers.push_back(VkBufferMemoryBarrier());
  214. VkBufferMemoryBarrier& barrier = barriers.back();
  215. barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
  216. barrier.pNext = nullptr;
  217. barrier.srcAccessMask = entry.second.accessFlags;
  218. barrier.dstAccessMask = entry.second.accessFlags;
  219. barrier.srcQueueFamilyIndex = currentQueueFamily;
  220. barrier.dstQueueFamilyIndex = mQueueFamily;
  221. barrier.buffer = resource->getHandle();
  222. barrier.offset = 0;
  223. barrier.size = VK_WHOLE_SIZE;
  224. }
  225. }
  226. for (auto& entry : mImages)
  227. {
  228. VulkanImage* resource = static_cast<VulkanImage*>(entry.first);
  229. UINT32 currentQueueFamily = resource->getQueueFamily();
  230. bool queueMismatch = resource->isExclusive() && currentQueueFamily != mQueueFamily;
  231. if (queueMismatch || resource->getLayout() != entry.second.layout)
  232. {
  233. Vector<VkImageMemoryBarrier>& barriers = mTransitionInfoTemp[currentQueueFamily].imageBarriers;
  234. barriers.push_back(VkImageMemoryBarrier());
  235. VkImageMemoryBarrier& barrier = barriers.back();
  236. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  237. barrier.pNext = nullptr;
  238. barrier.srcAccessMask = entry.second.accessFlags;
  239. barrier.dstAccessMask = entry.second.accessFlags;
  240. barrier.srcQueueFamilyIndex = currentQueueFamily;
  241. barrier.dstQueueFamilyIndex = mQueueFamily;
  242. barrier.oldLayout = resource->getLayout();
  243. barrier.newLayout = entry.second.layout;
  244. barrier.image = resource->getHandle();
  245. barrier.subresourceRange = entry.second.range;
  246. resource->setLayout(entry.second.layout);
  247. }
  248. }
  249. VulkanDevice& device = queue->getDevice();
  250. for (auto& entry : mTransitionInfoTemp)
  251. {
  252. bool empty = entry.second.imageBarriers.size() == 0 && entry.second.bufferBarriers.size() == 0;
  253. if (empty)
  254. continue;
  255. UINT32 entryQueueFamily = entry.first;
  256. // No queue transition needed for entries on this queue (this entry is most likely an in image layout transition)
  257. if (entryQueueFamily == mQueueFamily)
  258. continue;
  259. VulkanCmdBuffer* cmdBuffer = device.getCmdBufferPool().getBuffer(entryQueueFamily, false);
  260. VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
  261. TransitionInfo& barriers = entry.second;
  262. UINT32 numImgBarriers = (UINT32)barriers.imageBarriers.size();
  263. UINT32 numBufferBarriers = (UINT32)barriers.bufferBarriers.size();
  264. vkCmdPipelineBarrier(vkCmdBuffer,
  265. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // Note: VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT might be more correct here, according to the spec
  266. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // The main idea is that the barrier executes before the semaphore triggers, no actual stage dependencies are needed.
  267. 0, 0, nullptr,
  268. numBufferBarriers, barriers.bufferBarriers.data(),
  269. numImgBarriers, barriers.imageBarriers.data());
  270. // Find an appropriate queue to execute on
  271. UINT32 otherQueueIdx = 0;
  272. VulkanQueue* otherQueue = nullptr;
  273. GpuQueueType otherQueueType = GQT_GRAPHICS;
  274. for (UINT32 i = 0; i < GQT_COUNT; i++)
  275. {
  276. if (device.getQueueFamily((GpuQueueType)i) != entryQueueFamily)
  277. continue;
  278. UINT32 numQueues = device.getNumQueues(otherQueueType);
  279. for (UINT32 j = 0; j < numQueues; j++)
  280. {
  281. // Try to find a queue not currently executing
  282. VulkanQueue* curQueue = device.getQueue(otherQueueType, j);
  283. if (!curQueue->isExecuting())
  284. {
  285. otherQueue = curQueue;
  286. otherQueueIdx = j;
  287. }
  288. }
  289. // Can't find empty one, use the first one then
  290. if (otherQueue == nullptr)
  291. {
  292. otherQueue = device.getQueue(otherQueueType, 0);
  293. otherQueueIdx = 0;
  294. }
  295. otherQueueType = (GpuQueueType)i;
  296. break;
  297. }
  298. syncMask |= CommandSyncMask::getGlobalQueueMask(otherQueueType, otherQueueIdx);
  299. cmdBuffer->end();
  300. cmdBuffer->submit(otherQueue, otherQueueIdx, 0);
  301. // If there are any layout transitions, reset them as we don't need them for the second pipeline barrier
  302. for (auto& barrierEntry : barriers.imageBarriers)
  303. barrierEntry.oldLayout = barrierEntry.newLayout;
  304. }
  305. UINT32 deviceIdx = device.getIndex();
  306. VulkanCommandBufferManager& cbm = static_cast<VulkanCommandBufferManager&>(CommandBufferManager::instance());
  307. UINT32 numSemaphores;
  308. cbm.getSyncSemaphores(deviceIdx, syncMask, mSemaphoresTemp, numSemaphores);
  309. // Wait on present (i.e. until the back buffer becomes available), if we're rendering to a window
  310. if (mPresentSemaphore != VK_NULL_HANDLE)
  311. {
  312. mSemaphoresTemp[numSemaphores] = mPresentSemaphore;
  313. numSemaphores++;
  314. }
  315. // Issue second part of transition pipeline barriers (on this queue)
  316. for (auto& entry : mTransitionInfoTemp)
  317. {
  318. bool empty = entry.second.imageBarriers.size() == 0 && entry.second.bufferBarriers.size() == 0;
  319. if (empty)
  320. continue;
  321. VulkanCmdBuffer* cmdBuffer = device.getCmdBufferPool().getBuffer(mQueueFamily, false);
  322. VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
  323. TransitionInfo& barriers = entry.second;
  324. UINT32 numImgBarriers = (UINT32)barriers.imageBarriers.size();
  325. UINT32 numBufferBarriers = (UINT32)barriers.bufferBarriers.size();
  326. vkCmdPipelineBarrier(vkCmdBuffer,
  327. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // Note: VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT might be more correct here, according to the spec
  328. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
  329. 0, 0, nullptr,
  330. numBufferBarriers, barriers.bufferBarriers.data(),
  331. numImgBarriers, barriers.imageBarriers.data());
  332. cmdBuffer->end();
  333. queue->submit(cmdBuffer, mSemaphoresTemp, numSemaphores);
  334. numSemaphores = 0; // Semaphores are only needed the first time, since we're adding the buffers on the same queue
  335. }
  336. queue->submit(this, mSemaphoresTemp, numSemaphores);
  337. mGlobalQueueIdx = CommandSyncMask::getGlobalQueueIdx(queue->getType(), queueIdx);
  338. for (auto& entry : mResources)
  339. {
  340. ResourceUseHandle& useHandle = entry.second;
  341. assert(!useHandle.used);
  342. useHandle.used = true;
  343. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  344. }
  345. for (auto& entry : mImages)
  346. {
  347. ResourceUseHandle& useHandle = entry.second.useHandle;
  348. assert(!useHandle.used);
  349. useHandle.used = true;
  350. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  351. }
  352. for (auto& entry : mBuffers)
  353. {
  354. ResourceUseHandle& useHandle = entry.second.useHandle;
  355. assert(!useHandle.used);
  356. useHandle.used = true;
  357. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  358. }
  359. // Note: Uncommented for debugging only, prevents any device concurrency issues.
  360. // vkQueueWaitIdle(queue->getHandle());
  361. mState = State::Submitted;
  362. cbm.setActiveBuffer(queue->getType(), deviceIdx, queueIdx, this);
  363. // Clear vectors but don't clear the actual map, as we want to re-use the memory since we expect queue family
  364. // indices to be the same
  365. for (auto& entry : mTransitionInfoTemp)
  366. {
  367. entry.second.imageBarriers.clear();
  368. entry.second.bufferBarriers.clear();
  369. }
  370. }
  371. void VulkanCmdBuffer::refreshFenceStatus()
  372. {
  373. VkResult result = vkGetFenceStatus(mDevice.getLogical(), mFence);
  374. assert(result == VK_SUCCESS || result == VK_NOT_READY);
  375. bool signaled = result == VK_SUCCESS;
  376. if (mState == State::Submitted)
  377. {
  378. if(signaled)
  379. {
  380. mState = State::Ready;
  381. vkResetCommandBuffer(mCmdBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); // Note: Maybe better not to release resources?
  382. result = vkResetFences(mDevice.getLogical(), 1, &mFence);
  383. assert(result == VK_SUCCESS);
  384. mFenceCounter++;
  385. for (auto& entry : mResources)
  386. {
  387. ResourceUseHandle& useHandle = entry.second;
  388. assert(useHandle.used);
  389. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  390. }
  391. for (auto& entry : mImages)
  392. {
  393. ResourceUseHandle& useHandle = entry.second.useHandle;
  394. assert(useHandle.used);
  395. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  396. }
  397. for (auto& entry : mBuffers)
  398. {
  399. ResourceUseHandle& useHandle = entry.second.useHandle;
  400. assert(useHandle.used);
  401. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  402. }
  403. mResources.clear();
  404. mImages.clear();
  405. mBuffers.clear();
  406. }
  407. }
  408. else
  409. assert(!signaled); // We reset the fence along with mState so this shouldn't be possible
  410. }
  411. void VulkanCmdBuffer::setRenderTarget(const SPtr<RenderTargetCore>& rt)
  412. {
  413. assert(mState != State::RecordingRenderPass && mState != State::Submitted);
  414. if(rt == nullptr)
  415. {
  416. mFramebuffer = VK_NULL_HANDLE;
  417. mRenderPass = VK_NULL_HANDLE;
  418. mPresentSemaphore = VK_NULL_HANDLE;
  419. mRenderTargetWidth = 0;
  420. mRenderTargetHeight = 0;
  421. }
  422. else
  423. {
  424. rt->getCustomAttribute("FB", &mFramebuffer);
  425. rt->getCustomAttribute("RP", &mRenderPass);
  426. if (rt->getProperties().isWindow())
  427. rt->getCustomAttribute("PS", &mPresentSemaphore);
  428. else
  429. mPresentSemaphore = VK_NULL_HANDLE;
  430. mRenderTargetWidth = rt->getProperties().getWidth();
  431. mRenderTargetHeight = rt->getProperties().getHeight();
  432. }
  433. // TODO
  434. }
  435. void VulkanCmdBuffer::registerResource(VulkanResource* res, VulkanUseFlags flags)
  436. {
  437. auto insertResult = mResources.insert(std::make_pair(res, ResourceUseHandle()));
  438. if(insertResult.second) // New element
  439. {
  440. ResourceUseHandle& useHandle = insertResult.first->second;
  441. useHandle.used = false;
  442. useHandle.flags = flags;
  443. res->notifyBound();
  444. }
  445. else // Existing element
  446. {
  447. ResourceUseHandle& useHandle = insertResult.first->second;
  448. assert(!useHandle.used);
  449. useHandle.flags |= flags;
  450. }
  451. }
  452. void VulkanCmdBuffer::registerResource(VulkanImage* res, VkAccessFlags accessFlags, VkImageLayout layout,
  453. const VkImageSubresourceRange& range, VulkanUseFlags flags)
  454. {
  455. auto insertResult = mImages.insert(std::make_pair(res, ImageInfo()));
  456. if (insertResult.second) // New element
  457. {
  458. ImageInfo& imageInfo = insertResult.first->second;
  459. imageInfo.accessFlags = accessFlags;
  460. imageInfo.layout = layout;
  461. imageInfo.range = range;
  462. imageInfo.useHandle.used = false;
  463. imageInfo.useHandle.flags = flags;
  464. res->notifyBound();
  465. }
  466. else // Existing element
  467. {
  468. ImageInfo& imageInfo = insertResult.first->second;
  469. assert(!imageInfo.useHandle.used);
  470. imageInfo.useHandle.flags |= flags;
  471. assert(imageInfo.layout == layout && "Cannot bind the same image with two different layouts on the same command buffer.");
  472. imageInfo.accessFlags |= accessFlags;
  473. imageInfo.range = range;
  474. }
  475. }
  476. void VulkanCmdBuffer::registerResource(VulkanBuffer* res, VkAccessFlags accessFlags, VulkanUseFlags flags)
  477. {
  478. auto insertResult = mBuffers.insert(std::make_pair(res, BufferInfo()));
  479. if (insertResult.second) // New element
  480. {
  481. BufferInfo& bufferInfo = insertResult.first->second;
  482. bufferInfo.accessFlags = accessFlags;
  483. bufferInfo.useHandle.used = false;
  484. bufferInfo.useHandle.flags = flags;
  485. res->notifyBound();
  486. }
  487. else // Existing element
  488. {
  489. BufferInfo& bufferInfo = insertResult.first->second;
  490. assert(!bufferInfo.useHandle.used);
  491. bufferInfo.useHandle.flags |= flags;
  492. bufferInfo.accessFlags |= accessFlags;
  493. }
  494. }
  495. VulkanCommandBuffer::VulkanCommandBuffer(VulkanDevice& device, GpuQueueType type, UINT32 deviceIdx,
  496. UINT32 queueIdx, bool secondary)
  497. : CommandBuffer(type, deviceIdx, queueIdx, secondary), mBuffer(nullptr)
  498. , mDevice(device), mQueue(nullptr), mIdMask(0)
  499. {
  500. UINT32 numQueues = device.getNumQueues(mType);
  501. if (numQueues == 0) // Fall back to graphics queue
  502. {
  503. mType = GQT_GRAPHICS;
  504. numQueues = device.getNumQueues(GQT_GRAPHICS);
  505. }
  506. mQueue = device.getQueue(mType, mQueueIdx % numQueues);
  507. mIdMask = device.getQueueMask(mType, mQueueIdx);
  508. acquireNewBuffer();
  509. }
  510. void VulkanCommandBuffer::acquireNewBuffer()
  511. {
  512. VulkanCmdBufferPool& pool = mDevice.getCmdBufferPool();
  513. if (mBuffer != nullptr)
  514. assert(mBuffer->isSubmitted());
  515. UINT32 queueFamily = mDevice.getQueueFamily(mType);
  516. mBuffer = pool.getBuffer(queueFamily, mIsSecondary);
  517. }
  518. void VulkanCommandBuffer::submit(UINT32 syncMask)
  519. {
  520. // Ignore myself
  521. syncMask &= ~mIdMask;
  522. mBuffer->submit(mQueue, mQueueIdx, syncMask);
  523. gVulkanCBManager().refreshStates(mDeviceIdx);
  524. acquireNewBuffer();
  525. }
  526. }