BsVulkanCommandBuffer.cpp 34 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159
  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 "BsVulkanIndexBuffer.h"
  11. #include "BsVulkanVertexBuffer.h"
  12. #include "BsVulkanHardwareBuffer.h"
  13. #include "BsVulkanFramebuffer.h"
  14. #include "BsVulkanVertexInputManager.h"
  15. namespace bs
  16. {
  17. VulkanCmdBufferPool::VulkanCmdBufferPool(VulkanDevice& device)
  18. :mDevice(device), mNextId(1)
  19. {
  20. for (UINT32 i = 0; i < GQT_COUNT; i++)
  21. {
  22. UINT32 familyIdx = device.getQueueFamily((GpuQueueType)i);
  23. if (familyIdx == (UINT32)-1)
  24. continue;
  25. VkCommandPoolCreateInfo poolCI;
  26. poolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
  27. poolCI.pNext = nullptr;
  28. poolCI.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
  29. poolCI.queueFamilyIndex = familyIdx;
  30. PoolInfo& poolInfo = mPools[familyIdx];
  31. poolInfo.queueFamily = familyIdx;
  32. memset(poolInfo.buffers, 0, sizeof(poolInfo.buffers));
  33. vkCreateCommandPool(device.getLogical(), &poolCI, gVulkanAllocator, &poolInfo.pool);
  34. }
  35. }
  36. VulkanCmdBufferPool::~VulkanCmdBufferPool()
  37. {
  38. // Note: Shutdown should be the only place command buffers are destroyed at, as the system relies on the fact that
  39. // they won't be destroyed during normal operation.
  40. for(auto& entry : mPools)
  41. {
  42. PoolInfo& poolInfo = entry.second;
  43. for (UINT32 i = 0; i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY; i++)
  44. {
  45. VulkanCmdBuffer* buffer = poolInfo.buffers[i];
  46. if (buffer == nullptr)
  47. break;
  48. bs_delete(buffer);
  49. }
  50. vkDestroyCommandPool(mDevice.getLogical(), poolInfo.pool, gVulkanAllocator);
  51. }
  52. }
  53. VulkanCmdBuffer* VulkanCmdBufferPool::getBuffer(UINT32 queueFamily, bool secondary)
  54. {
  55. auto iterFind = mPools.find(queueFamily);
  56. if (iterFind != mPools.end())
  57. return nullptr;
  58. VulkanCmdBuffer** buffers = iterFind->second.buffers;
  59. UINT32 i = 0;
  60. for(; i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY; i++)
  61. {
  62. if (buffers[i] == nullptr)
  63. break;
  64. if(buffers[i]->mState == VulkanCmdBuffer::State::Ready)
  65. {
  66. buffers[i]->begin();
  67. return buffers[i];
  68. }
  69. }
  70. assert(i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY &&
  71. "Too many command buffers allocated. Increment BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY to a higher value. ");
  72. buffers[i] = createBuffer(queueFamily, secondary);
  73. buffers[i]->begin();
  74. return buffers[i];
  75. }
  76. VulkanCmdBuffer* VulkanCmdBufferPool::createBuffer(UINT32 queueFamily, bool secondary)
  77. {
  78. auto iterFind = mPools.find(queueFamily);
  79. if (iterFind != mPools.end())
  80. return nullptr;
  81. const PoolInfo& poolInfo = iterFind->second;
  82. return bs_new<VulkanCmdBuffer>(mDevice, mNextId++, poolInfo.pool, poolInfo.queueFamily, secondary);
  83. }
  84. VulkanCmdBuffer::VulkanCmdBuffer(VulkanDevice& device, UINT32 id, VkCommandPool pool, UINT32 queueFamily, bool secondary)
  85. : mId(id), mQueueFamily(queueFamily), mState(State::Ready), mDevice(device), mPool(pool), mFenceCounter(0)
  86. , mFramebuffer(nullptr), mPresentSemaphore(VK_NULL_HANDLE), mRenderTargetWidth(0), mRenderTargetHeight(0)
  87. , mRenderTargetDepthReadOnly(false), mRenderTargetLoadMask(RT_NONE), mGlobalQueueIdx(-1)
  88. , mViewport(0.0f, 0.0f, 1.0f, 1.0f), mScissor(0, 0, 0, 0), mStencilRef(0), mDrawOp(DOT_TRIANGLE_LIST)
  89. , mNumBoundDescriptorSets(0), mGfxPipelineRequiresBind(true), mCmpPipelineRequiresBind(true)
  90. , mViewportRequiresBind(true), mStencilRefRequiresBind(true), mScissorRequiresBind(true), mVertexBuffersTemp()
  91. , mVertexBufferOffsetsTemp()
  92. {
  93. UINT32 maxBoundDescriptorSets = device.getDeviceProperties().limits.maxBoundDescriptorSets;
  94. mDescriptorSetsTemp = (VkDescriptorSet*)bs_alloc(sizeof(VkDescriptorSet) * maxBoundDescriptorSets);
  95. VkCommandBufferAllocateInfo cmdBufferAllocInfo;
  96. cmdBufferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  97. cmdBufferAllocInfo.pNext = nullptr;
  98. cmdBufferAllocInfo.commandPool = pool;
  99. cmdBufferAllocInfo.level = secondary ? VK_COMMAND_BUFFER_LEVEL_SECONDARY : VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  100. cmdBufferAllocInfo.commandBufferCount = 1;
  101. VkResult result = vkAllocateCommandBuffers(mDevice.getLogical(), &cmdBufferAllocInfo, &mCmdBuffer);
  102. assert(result == VK_SUCCESS);
  103. VkFenceCreateInfo fenceCI;
  104. fenceCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
  105. fenceCI.pNext = nullptr;
  106. fenceCI.flags = 0;
  107. result = vkCreateFence(mDevice.getLogical(), &fenceCI, gVulkanAllocator, &mFence);
  108. assert(result == VK_SUCCESS);
  109. VkSemaphoreCreateInfo semaphoreCI;
  110. semaphoreCI.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
  111. semaphoreCI.pNext = nullptr;
  112. semaphoreCI.flags = 0;
  113. result = vkCreateSemaphore(mDevice.getLogical(), &semaphoreCI, gVulkanAllocator, &mSemaphore);
  114. assert(result == VK_SUCCESS);
  115. }
  116. VulkanCmdBuffer::~VulkanCmdBuffer()
  117. {
  118. VkDevice device = mDevice.getLogical();
  119. if(mState == State::Submitted)
  120. {
  121. // Wait 1s
  122. UINT64 waitTime = 1000 * 1000 * 1000;
  123. VkResult result = vkWaitForFences(device, 1, &mFence, true, waitTime);
  124. assert(result == VK_SUCCESS || result == VK_TIMEOUT);
  125. if (result == VK_TIMEOUT)
  126. LOGWRN("Freeing a command buffer before done executing because fence wait expired!");
  127. // Resources have been marked as used, make sure to notify them we're done with them
  128. refreshFenceStatus();
  129. }
  130. else if(mState != State::Ready)
  131. {
  132. // Notify any resources that they are no longer bound
  133. for (auto& entry : mResources)
  134. {
  135. ResourceUseHandle& useHandle = entry.second;
  136. assert(useHandle.used);
  137. entry.first->notifyUnbound();
  138. }
  139. for (auto& entry : mImages)
  140. {
  141. ResourceUseHandle& useHandle = entry.second.useHandle;
  142. assert(useHandle.used);
  143. entry.first->notifyUnbound();
  144. }
  145. for (auto& entry : mBuffers)
  146. {
  147. ResourceUseHandle& useHandle = entry.second.useHandle;
  148. assert(useHandle.used);
  149. entry.first->notifyUnbound();
  150. }
  151. }
  152. vkDestroyFence(device, mFence, gVulkanAllocator);
  153. vkDestroySemaphore(device, mSemaphore, gVulkanAllocator);
  154. vkFreeCommandBuffers(device, mPool, 1, &mCmdBuffer);
  155. bs_free(mDescriptorSetsTemp);
  156. }
  157. UINT32 VulkanCmdBuffer::getDeviceIdx() const
  158. {
  159. return mDevice.getIndex();
  160. }
  161. void VulkanCmdBuffer::begin()
  162. {
  163. assert(mState == State::Ready);
  164. VkCommandBufferBeginInfo beginInfo;
  165. beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  166. beginInfo.pNext = nullptr;
  167. beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  168. beginInfo.pInheritanceInfo = nullptr;
  169. VkResult result = vkBeginCommandBuffer(mCmdBuffer, &beginInfo);
  170. assert(result == VK_SUCCESS);
  171. mState = State::Recording;
  172. }
  173. void VulkanCmdBuffer::end()
  174. {
  175. assert(mState == State::Recording);
  176. VkResult result = vkEndCommandBuffer(mCmdBuffer);
  177. assert(result == VK_SUCCESS);
  178. mState = State::RecordingDone;
  179. }
  180. void VulkanCmdBuffer::beginRenderPass()
  181. {
  182. assert(mState == State::Recording);
  183. if (mFramebuffer == nullptr)
  184. {
  185. LOGWRN("Attempting to begin a render pass but no render target is bound to the command buffer.");
  186. return;
  187. }
  188. VkRenderPassBeginInfo renderPassBeginInfo;
  189. renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  190. renderPassBeginInfo.pNext = nullptr;
  191. renderPassBeginInfo.framebuffer = mFramebuffer->getFramebuffer(mRenderTargetLoadMask, RT_NONE);
  192. renderPassBeginInfo.renderPass = mFramebuffer->getRenderPass(mRenderTargetLoadMask, RT_NONE);
  193. renderPassBeginInfo.renderArea.offset.x = 0;
  194. renderPassBeginInfo.renderArea.offset.y = 0;
  195. renderPassBeginInfo.renderArea.extent.width = mRenderTargetWidth;
  196. renderPassBeginInfo.renderArea.extent.height = mRenderTargetHeight;
  197. renderPassBeginInfo.clearValueCount = 0;
  198. renderPassBeginInfo.pClearValues = nullptr;
  199. vkCmdBeginRenderPass(mCmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
  200. mState = State::RecordingRenderPass;
  201. }
  202. void VulkanCmdBuffer::endRenderPass()
  203. {
  204. assert(mState == State::RecordingRenderPass);
  205. vkCmdEndRenderPass(mCmdBuffer);
  206. mState = State::Recording;
  207. }
  208. void VulkanCmdBuffer::submit(VulkanQueue* queue, UINT32 queueIdx, UINT32 syncMask)
  209. {
  210. assert(isReadyForSubmit());
  211. // Issue pipeline barriers for queue transitions (need to happen on original queue first, then on new queue)
  212. for (auto& entry : mBuffers)
  213. {
  214. VulkanBuffer* resource = static_cast<VulkanBuffer*>(entry.first);
  215. if (!resource->isExclusive())
  216. continue;
  217. UINT32 currentQueueFamily = resource->getQueueFamily();
  218. if (currentQueueFamily != mQueueFamily)
  219. {
  220. Vector<VkBufferMemoryBarrier>& barriers = mTransitionInfoTemp[currentQueueFamily].bufferBarriers;
  221. barriers.push_back(VkBufferMemoryBarrier());
  222. VkBufferMemoryBarrier& barrier = barriers.back();
  223. barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
  224. barrier.pNext = nullptr;
  225. barrier.srcAccessMask = entry.second.accessFlags;
  226. barrier.dstAccessMask = entry.second.accessFlags;
  227. barrier.srcQueueFamilyIndex = currentQueueFamily;
  228. barrier.dstQueueFamilyIndex = mQueueFamily;
  229. barrier.buffer = resource->getHandle();
  230. barrier.offset = 0;
  231. barrier.size = VK_WHOLE_SIZE;
  232. }
  233. }
  234. for (auto& entry : mImages)
  235. {
  236. VulkanImage* resource = static_cast<VulkanImage*>(entry.first);
  237. UINT32 currentQueueFamily = resource->getQueueFamily();
  238. bool queueMismatch = resource->isExclusive() && currentQueueFamily != mQueueFamily;
  239. if (queueMismatch || resource->getLayout() != entry.second.layout)
  240. {
  241. Vector<VkImageMemoryBarrier>& barriers = mTransitionInfoTemp[currentQueueFamily].imageBarriers;
  242. barriers.push_back(VkImageMemoryBarrier());
  243. VkImageMemoryBarrier& barrier = barriers.back();
  244. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  245. barrier.pNext = nullptr;
  246. barrier.srcAccessMask = entry.second.accessFlags;
  247. barrier.dstAccessMask = entry.second.accessFlags;
  248. barrier.srcQueueFamilyIndex = currentQueueFamily;
  249. barrier.dstQueueFamilyIndex = mQueueFamily;
  250. barrier.oldLayout = resource->getLayout();
  251. barrier.newLayout = entry.second.layout;
  252. barrier.image = resource->getHandle();
  253. barrier.subresourceRange = entry.second.range;
  254. resource->setLayout(entry.second.layout);
  255. }
  256. }
  257. VulkanDevice& device = queue->getDevice();
  258. for (auto& entry : mTransitionInfoTemp)
  259. {
  260. bool empty = entry.second.imageBarriers.size() == 0 && entry.second.bufferBarriers.size() == 0;
  261. if (empty)
  262. continue;
  263. UINT32 entryQueueFamily = entry.first;
  264. // No queue transition needed for entries on this queue (this entry is most likely an image layout transition)
  265. if (entryQueueFamily == mQueueFamily)
  266. continue;
  267. VulkanCmdBuffer* cmdBuffer = device.getCmdBufferPool().getBuffer(entryQueueFamily, false);
  268. VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
  269. TransitionInfo& barriers = entry.second;
  270. UINT32 numImgBarriers = (UINT32)barriers.imageBarriers.size();
  271. UINT32 numBufferBarriers = (UINT32)barriers.bufferBarriers.size();
  272. vkCmdPipelineBarrier(vkCmdBuffer,
  273. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // Note: VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT might be more correct here, according to the spec
  274. 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.
  275. 0, 0, nullptr,
  276. numBufferBarriers, barriers.bufferBarriers.data(),
  277. numImgBarriers, barriers.imageBarriers.data());
  278. // Find an appropriate queue to execute on
  279. UINT32 otherQueueIdx = 0;
  280. VulkanQueue* otherQueue = nullptr;
  281. GpuQueueType otherQueueType = GQT_GRAPHICS;
  282. for (UINT32 i = 0; i < GQT_COUNT; i++)
  283. {
  284. if (device.getQueueFamily((GpuQueueType)i) != entryQueueFamily)
  285. continue;
  286. UINT32 numQueues = device.getNumQueues(otherQueueType);
  287. for (UINT32 j = 0; j < numQueues; j++)
  288. {
  289. // Try to find a queue not currently executing
  290. VulkanQueue* curQueue = device.getQueue(otherQueueType, j);
  291. if (!curQueue->isExecuting())
  292. {
  293. otherQueue = curQueue;
  294. otherQueueIdx = j;
  295. }
  296. }
  297. // Can't find empty one, use the first one then
  298. if (otherQueue == nullptr)
  299. {
  300. otherQueue = device.getQueue(otherQueueType, 0);
  301. otherQueueIdx = 0;
  302. }
  303. otherQueueType = (GpuQueueType)i;
  304. break;
  305. }
  306. syncMask |= CommandSyncMask::getGlobalQueueMask(otherQueueType, otherQueueIdx);
  307. cmdBuffer->end();
  308. cmdBuffer->submit(otherQueue, otherQueueIdx, 0);
  309. // If there are any layout transitions, reset them as we don't need them for the second pipeline barrier
  310. for (auto& barrierEntry : barriers.imageBarriers)
  311. barrierEntry.oldLayout = barrierEntry.newLayout;
  312. }
  313. UINT32 deviceIdx = device.getIndex();
  314. VulkanCommandBufferManager& cbm = static_cast<VulkanCommandBufferManager&>(CommandBufferManager::instance());
  315. UINT32 numSemaphores;
  316. cbm.getSyncSemaphores(deviceIdx, syncMask, mSemaphoresTemp, numSemaphores);
  317. // Wait on present (i.e. until the back buffer becomes available), if we're rendering to a window
  318. if (mPresentSemaphore != VK_NULL_HANDLE)
  319. {
  320. mSemaphoresTemp[numSemaphores] = mPresentSemaphore;
  321. numSemaphores++;
  322. }
  323. // Issue second part of transition pipeline barriers (on this queue)
  324. for (auto& entry : mTransitionInfoTemp)
  325. {
  326. bool empty = entry.second.imageBarriers.size() == 0 && entry.second.bufferBarriers.size() == 0;
  327. if (empty)
  328. continue;
  329. VulkanCmdBuffer* cmdBuffer = device.getCmdBufferPool().getBuffer(mQueueFamily, false);
  330. VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
  331. TransitionInfo& barriers = entry.second;
  332. UINT32 numImgBarriers = (UINT32)barriers.imageBarriers.size();
  333. UINT32 numBufferBarriers = (UINT32)barriers.bufferBarriers.size();
  334. vkCmdPipelineBarrier(vkCmdBuffer,
  335. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // Note: VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT might be more correct here, according to the spec
  336. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
  337. 0, 0, nullptr,
  338. numBufferBarriers, barriers.bufferBarriers.data(),
  339. numImgBarriers, barriers.imageBarriers.data());
  340. cmdBuffer->end();
  341. queue->submit(cmdBuffer, mSemaphoresTemp, numSemaphores);
  342. numSemaphores = 0; // Semaphores are only needed the first time, since we're adding the buffers on the same queue
  343. }
  344. queue->submit(this, mSemaphoresTemp, numSemaphores);
  345. mGlobalQueueIdx = CommandSyncMask::getGlobalQueueIdx(queue->getType(), queueIdx);
  346. for (auto& entry : mResources)
  347. {
  348. ResourceUseHandle& useHandle = entry.second;
  349. assert(!useHandle.used);
  350. useHandle.used = true;
  351. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  352. }
  353. for (auto& entry : mImages)
  354. {
  355. ResourceUseHandle& useHandle = entry.second.useHandle;
  356. assert(!useHandle.used);
  357. useHandle.used = true;
  358. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  359. }
  360. for (auto& entry : mBuffers)
  361. {
  362. ResourceUseHandle& useHandle = entry.second.useHandle;
  363. assert(!useHandle.used);
  364. useHandle.used = true;
  365. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  366. }
  367. // Note: Uncommented for debugging only, prevents any device concurrency issues.
  368. // vkQueueWaitIdle(queue->getHandle());
  369. mState = State::Submitted;
  370. cbm.setActiveBuffer(queue->getType(), deviceIdx, queueIdx, this);
  371. // Clear vectors but don't clear the actual map, as we want to re-use the memory since we expect queue family
  372. // indices to be the same
  373. for (auto& entry : mTransitionInfoTemp)
  374. {
  375. entry.second.imageBarriers.clear();
  376. entry.second.bufferBarriers.clear();
  377. }
  378. mGraphicsPipeline = nullptr;
  379. mComputePipeline = nullptr;
  380. mGfxPipelineRequiresBind = true;
  381. mCmpPipelineRequiresBind = true;
  382. mFramebuffer = nullptr;
  383. mDescriptorSetsBindState = DescriptorSetBindFlag::Graphics | DescriptorSetBindFlag::Compute;
  384. }
  385. void VulkanCmdBuffer::refreshFenceStatus()
  386. {
  387. VkResult result = vkGetFenceStatus(mDevice.getLogical(), mFence);
  388. assert(result == VK_SUCCESS || result == VK_NOT_READY);
  389. bool signaled = result == VK_SUCCESS;
  390. if (mState == State::Submitted)
  391. {
  392. if(signaled)
  393. {
  394. mState = State::Ready;
  395. vkResetCommandBuffer(mCmdBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); // Note: Maybe better not to release resources?
  396. result = vkResetFences(mDevice.getLogical(), 1, &mFence);
  397. assert(result == VK_SUCCESS);
  398. mFenceCounter++;
  399. for (auto& entry : mResources)
  400. {
  401. ResourceUseHandle& useHandle = entry.second;
  402. assert(useHandle.used);
  403. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  404. }
  405. for (auto& entry : mImages)
  406. {
  407. ResourceUseHandle& useHandle = entry.second.useHandle;
  408. assert(useHandle.used);
  409. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  410. }
  411. for (auto& entry : mBuffers)
  412. {
  413. ResourceUseHandle& useHandle = entry.second.useHandle;
  414. assert(useHandle.used);
  415. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  416. }
  417. mResources.clear();
  418. mImages.clear();
  419. mBuffers.clear();
  420. }
  421. }
  422. else
  423. assert(!signaled); // We reset the fence along with mState so this shouldn't be possible
  424. }
  425. void VulkanCmdBuffer::setRenderTarget(const SPtr<RenderTargetCore>& rt, bool readOnlyDepthStencil,
  426. RenderSurfaceMask loadMask)
  427. {
  428. assert(mState != State::RecordingRenderPass && mState != State::Submitted);
  429. VulkanFramebuffer* oldFramebuffer = mFramebuffer;
  430. if(rt == nullptr)
  431. {
  432. mFramebuffer = nullptr;
  433. mPresentSemaphore = VK_NULL_HANDLE;
  434. mRenderTargetWidth = 0;
  435. mRenderTargetHeight = 0;
  436. mRenderTargetDepthReadOnly = false;
  437. mRenderTargetLoadMask = RT_NONE;
  438. }
  439. else
  440. {
  441. rt->getCustomAttribute("FB", &mFramebuffer);
  442. if (rt->getProperties().isWindow())
  443. rt->getCustomAttribute("PS", &mPresentSemaphore);
  444. else
  445. mPresentSemaphore = VK_NULL_HANDLE;
  446. mRenderTargetWidth = rt->getProperties().getWidth();
  447. mRenderTargetHeight = rt->getProperties().getHeight();
  448. mRenderTargetDepthReadOnly = readOnlyDepthStencil;
  449. mRenderTargetLoadMask = loadMask;
  450. registerResource(mFramebuffer, VulkanUseFlag::Write);
  451. }
  452. // If anything changed
  453. if(oldFramebuffer != mFramebuffer)
  454. {
  455. if (isInRenderPass())
  456. endRenderPass();
  457. mGfxPipelineRequiresBind = true;
  458. }
  459. }
  460. void VulkanCmdBuffer::clearViewport(const Rect2I& area, UINT32 buffers, const Color& color, float depth, UINT16 stencil,
  461. UINT8 targetMask)
  462. {
  463. if (buffers == 0 || mFramebuffer == nullptr)
  464. return;
  465. VkClearAttachment attachments[BS_MAX_MULTIPLE_RENDER_TARGETS + 1];
  466. UINT32 baseLayer = 0;
  467. UINT32 attachmentIdx = 0;
  468. if ((buffers & FBT_COLOR) != 0)
  469. {
  470. UINT32 numColorAttachments = mFramebuffer->getNumColorAttachments();
  471. for (UINT32 i = 0; i < numColorAttachments; i++)
  472. {
  473. if (((1 << i) & targetMask) == 0)
  474. continue;
  475. attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  476. attachments[attachmentIdx].colorAttachment = i;
  477. VkClearColorValue& colorValue = attachments[attachmentIdx].clearValue.color;
  478. colorValue.float32[0] = color.r;
  479. colorValue.float32[1] = color.g;
  480. colorValue.float32[2] = color.b;
  481. colorValue.float32[3] = color.a;
  482. UINT32 curBaseLayer = mFramebuffer->getColorBaseLayer(i);
  483. if (attachmentIdx == 0)
  484. baseLayer = curBaseLayer;
  485. else
  486. {
  487. if(baseLayer != curBaseLayer)
  488. {
  489. // Note: This could be supported relatively easily: we would need to issue multiple separate
  490. // clear commands for such framebuffers.
  491. LOGERR("Attempting to clear a texture that has multiple multi-layer surfaces with mismatching "
  492. "starting layers. This is currently not supported.");
  493. }
  494. }
  495. attachmentIdx++;
  496. }
  497. }
  498. if ((buffers & FBT_DEPTH) != 0 || (buffers & FBT_STENCIL) != 0)
  499. {
  500. if (mFramebuffer->hasDepthAttachment())
  501. {
  502. if ((buffers & FBT_DEPTH) != 0)
  503. {
  504. attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
  505. attachments[attachmentIdx].clearValue.depthStencil.depth = depth;
  506. }
  507. if ((buffers & FBT_STENCIL) != 0)
  508. {
  509. attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
  510. attachments[attachmentIdx].clearValue.depthStencil.stencil = stencil;
  511. }
  512. attachments[attachmentIdx].colorAttachment = 0;
  513. UINT32 curBaseLayer = mFramebuffer->getDepthStencilBaseLayer();
  514. if (attachmentIdx == 0)
  515. baseLayer = curBaseLayer;
  516. else
  517. {
  518. if (baseLayer != curBaseLayer)
  519. {
  520. // Note: This could be supported relatively easily: we would need to issue multiple separate
  521. // clear commands for such framebuffers.
  522. LOGERR("Attempting to clear a texture that has multiple multi-layer surfaces with mismatching "
  523. "starting layers. This is currently not supported.");
  524. }
  525. }
  526. attachmentIdx++;
  527. }
  528. }
  529. VkClearRect clearRect;
  530. clearRect.baseArrayLayer = baseLayer;
  531. clearRect.layerCount = mFramebuffer->getNumLayers();
  532. clearRect.rect.offset.x = area.x;
  533. clearRect.rect.offset.y = area.y;
  534. clearRect.rect.extent.width = area.width;
  535. clearRect.rect.extent.height = area.height;
  536. UINT32 numAttachments = attachmentIdx;
  537. vkCmdClearAttachments(mCmdBuffer, numAttachments, attachments, 1, &clearRect);
  538. }
  539. void VulkanCmdBuffer::clearRenderTarget(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask)
  540. {
  541. Rect2I area(0, 0, mRenderTargetWidth, mRenderTargetHeight);
  542. clearViewport(area, buffers, color, depth, stencil, targetMask);
  543. }
  544. void VulkanCmdBuffer::clearViewport(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask)
  545. {
  546. Rect2I area;
  547. area.x = (UINT32)(mViewport.x * mRenderTargetWidth);
  548. area.y = (UINT32)(mViewport.y * mRenderTargetHeight);
  549. area.width = (UINT32)(mViewport.width * mRenderTargetWidth);
  550. area.height = (UINT32)(mViewport.height * mRenderTargetHeight);
  551. clearViewport(area, buffers, color, depth, stencil, targetMask);
  552. }
  553. void VulkanCmdBuffer::setPipelineState(const SPtr<GraphicsPipelineStateCore>& state)
  554. {
  555. if (mGraphicsPipeline == state)
  556. return;
  557. mGraphicsPipeline = std::static_pointer_cast<VulkanGraphicsPipelineStateCore>(state);
  558. mGfxPipelineRequiresBind = true;
  559. }
  560. void VulkanCmdBuffer::setPipelineState(const SPtr<ComputePipelineStateCore>& state)
  561. {
  562. if (mComputePipeline == state)
  563. return;
  564. mComputePipeline = std::static_pointer_cast<VulkanComputePipelineStateCore>(state);
  565. mCmpPipelineRequiresBind = true;
  566. }
  567. void VulkanCmdBuffer::setGpuParams(const SPtr<GpuParamsCore>& gpuParams)
  568. {
  569. SPtr<VulkanGpuParams> vulkanGpuParams = std::static_pointer_cast<VulkanGpuParams>(gpuParams);
  570. if(vulkanGpuParams != nullptr)
  571. {
  572. mNumBoundDescriptorSets = vulkanGpuParams->getNumSets();
  573. vulkanGpuParams->prepareForBind(*this, mDescriptorSetsTemp);
  574. }
  575. else
  576. {
  577. mNumBoundDescriptorSets = 0;
  578. }
  579. mDescriptorSetsBindState = DescriptorSetBindFlag::Graphics | DescriptorSetBindFlag::Compute;
  580. }
  581. void VulkanCmdBuffer::setViewport(const Rect2& area)
  582. {
  583. if (mViewport == area)
  584. return;
  585. mViewport = area;
  586. mViewportRequiresBind = true;
  587. }
  588. void VulkanCmdBuffer::setScissorRect(const Rect2I& value)
  589. {
  590. if (mScissor == value)
  591. return;
  592. mScissor = value;
  593. mScissorRequiresBind = true;
  594. }
  595. void VulkanCmdBuffer::setStencilRef(UINT32 value)
  596. {
  597. if (mStencilRef == value)
  598. return;
  599. mStencilRef = value;
  600. mStencilRefRequiresBind = true;
  601. }
  602. void VulkanCmdBuffer::setDrawOp(DrawOperationType drawOp)
  603. {
  604. if (mDrawOp == drawOp)
  605. return;
  606. mDrawOp = drawOp;
  607. mGfxPipelineRequiresBind = true;
  608. }
  609. void VulkanCmdBuffer::setVertexBuffers(UINT32 index, SPtr<VertexBufferCore>* buffers, UINT32 numBuffers)
  610. {
  611. if (numBuffers == 0)
  612. return;
  613. for(UINT32 i = 0; i < numBuffers; i++)
  614. {
  615. VulkanVertexBufferCore* vertexBuffer = static_cast<VulkanVertexBufferCore*>(buffers[i].get());
  616. if (vertexBuffer != nullptr)
  617. {
  618. VulkanBuffer* resource = vertexBuffer->getResource(mDevice.getIndex());
  619. if (resource != nullptr)
  620. {
  621. mVertexBuffersTemp[i] = resource->getHandle();
  622. registerResource(resource, VulkanUseFlag::Read);
  623. }
  624. else
  625. mVertexBuffersTemp[i] = VK_NULL_HANDLE;
  626. }
  627. else
  628. mVertexBuffersTemp[i] = VK_NULL_HANDLE;
  629. }
  630. vkCmdBindVertexBuffers(mCmdBuffer, index, numBuffers, mVertexBuffersTemp, mVertexBufferOffsetsTemp);
  631. }
  632. void VulkanCmdBuffer::setIndexBuffer(const SPtr<IndexBufferCore>& buffer)
  633. {
  634. VulkanIndexBufferCore* indexBuffer = static_cast<VulkanIndexBufferCore*>(buffer.get());
  635. VkBuffer vkBuffer = VK_NULL_HANDLE;
  636. VkIndexType indexType = VK_INDEX_TYPE_UINT32;
  637. if (indexBuffer != nullptr)
  638. {
  639. VulkanBuffer* resource = indexBuffer->getResource(mDevice.getIndex());
  640. if (resource != nullptr)
  641. {
  642. vkBuffer = resource->getHandle();
  643. indexType = VulkanUtility::getIndexType(buffer->getProperties().getType());
  644. registerResource(resource, VulkanUseFlag::Read);
  645. }
  646. }
  647. vkCmdBindIndexBuffer(mCmdBuffer, vkBuffer, 0, indexType);
  648. }
  649. void VulkanCmdBuffer::setVertexDeclaration(const SPtr<VertexDeclarationCore>& decl)
  650. {
  651. if (mVertexDecl == decl)
  652. return;
  653. mVertexDecl = decl;
  654. mGfxPipelineRequiresBind = true;
  655. }
  656. bool VulkanCmdBuffer::isReadyForRender()
  657. {
  658. if (mGraphicsPipeline == nullptr)
  659. return false;
  660. SPtr<VertexDeclarationCore> inputDecl = mGraphicsPipeline->getInputDeclaration();
  661. if (inputDecl == nullptr)
  662. return false;
  663. return mFramebuffer != nullptr && mVertexDecl != nullptr;
  664. }
  665. bool VulkanCmdBuffer::bindGraphicsPipeline()
  666. {
  667. SPtr<VertexDeclarationCore> inputDecl = mGraphicsPipeline->getInputDeclaration();
  668. SPtr<VulkanVertexInput> vertexInput = VulkanVertexInputManager::instance().getVertexInfo(mVertexDecl, inputDecl);
  669. VulkanPipeline* pipeline = mGraphicsPipeline->getPipeline(mDevice.getIndex(), mFramebuffer,
  670. mRenderTargetDepthReadOnly, mRenderTargetLoadMask,
  671. RT_NONE, mDrawOp, vertexInput);
  672. if (pipeline == nullptr)
  673. return false;
  674. mGraphicsPipeline->registerPipelineResources(this);
  675. registerResource(pipeline, VulkanUseFlag::Read);
  676. vkCmdBindPipeline(mCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getHandle());
  677. bindDynamicStates(true);
  678. mGfxPipelineRequiresBind = false;
  679. return true;
  680. }
  681. void VulkanCmdBuffer::bindDynamicStates(bool forceAll)
  682. {
  683. if (mViewportRequiresBind || forceAll)
  684. {
  685. VkViewport viewport;
  686. viewport.x = mViewport.x * mRenderTargetWidth;
  687. viewport.y = mViewport.y * mRenderTargetHeight;
  688. viewport.width = mViewport.width * mRenderTargetWidth;
  689. viewport.height = mViewport.height * mRenderTargetHeight;
  690. viewport.minDepth = 0.0f;
  691. viewport.maxDepth = 1.0f;
  692. vkCmdSetViewport(mCmdBuffer, 0, 1, &viewport);
  693. mViewportRequiresBind = false;
  694. }
  695. if(mStencilRefRequiresBind || forceAll)
  696. {
  697. vkCmdSetStencilReference(mCmdBuffer, VK_STENCIL_FRONT_AND_BACK, mStencilRef);
  698. mStencilRefRequiresBind = false;
  699. }
  700. if(mScissorRequiresBind || forceAll)
  701. {
  702. VkRect2D scissorRect;
  703. if(mGraphicsPipeline->isScissorEnabled())
  704. {
  705. scissorRect.offset.x = mScissor.x;
  706. scissorRect.offset.y = mScissor.y;
  707. scissorRect.extent.width = mScissor.width;
  708. scissorRect.extent.height = mScissor.height;
  709. }
  710. else
  711. {
  712. scissorRect.offset.x = 0;
  713. scissorRect.offset.y = 0;
  714. scissorRect.extent.width = mRenderTargetWidth;
  715. scissorRect.extent.height = mRenderTargetHeight;
  716. }
  717. vkCmdSetScissor(mCmdBuffer, 0, 1, &scissorRect);
  718. mScissorRequiresBind = false;
  719. }
  720. }
  721. void VulkanCmdBuffer::draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount)
  722. {
  723. if (!isReadyForRender())
  724. return;
  725. if (!isInRenderPass())
  726. beginRenderPass();
  727. if (mGfxPipelineRequiresBind)
  728. {
  729. if (!bindGraphicsPipeline())
  730. return;
  731. }
  732. else
  733. bindDynamicStates(false);
  734. if (mDescriptorSetsBindState.isSet(DescriptorSetBindFlag::Graphics))
  735. {
  736. UINT32 deviceIdx = mDevice.getIndex();
  737. VkPipelineLayout pipelineLayout = mGraphicsPipeline->getPipelineLayout(deviceIdx);
  738. vkCmdBindDescriptorSets(mCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0,
  739. mNumBoundDescriptorSets, mDescriptorSetsTemp, 0, nullptr);
  740. mDescriptorSetsBindState.unset(DescriptorSetBindFlag::Graphics);
  741. }
  742. vkCmdDraw(mCmdBuffer, vertexCount, instanceCount, vertexOffset, 0);
  743. }
  744. void VulkanCmdBuffer::drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 instanceCount)
  745. {
  746. if (!isReadyForRender())
  747. return;
  748. if (!isInRenderPass())
  749. beginRenderPass();
  750. if (mGfxPipelineRequiresBind)
  751. {
  752. if (!bindGraphicsPipeline())
  753. return;
  754. }
  755. else
  756. bindDynamicStates(false);
  757. if (mDescriptorSetsBindState.isSet(DescriptorSetBindFlag::Graphics))
  758. {
  759. UINT32 deviceIdx = mDevice.getIndex();
  760. VkPipelineLayout pipelineLayout = mGraphicsPipeline->getPipelineLayout(deviceIdx);
  761. vkCmdBindDescriptorSets(mCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0,
  762. mNumBoundDescriptorSets, mDescriptorSetsTemp, 0, nullptr);
  763. mDescriptorSetsBindState.unset(DescriptorSetBindFlag::Graphics);
  764. }
  765. vkCmdDrawIndexed(mCmdBuffer, indexCount, instanceCount, startIndex, vertexOffset, 0);
  766. }
  767. void VulkanCmdBuffer::dispatch(UINT32 numGroupsX, UINT32 numGroupsY, UINT32 numGroupsZ)
  768. {
  769. if (mComputePipeline == nullptr)
  770. return;
  771. if (isInRenderPass())
  772. endRenderPass();
  773. UINT32 deviceIdx = mDevice.getIndex();
  774. if(mCmpPipelineRequiresBind)
  775. {
  776. VulkanPipeline* pipeline = mComputePipeline->getPipeline(deviceIdx);
  777. if (pipeline == nullptr)
  778. return;
  779. registerResource(pipeline, VulkanUseFlag::Read);
  780. mComputePipeline->registerPipelineResources(this);
  781. vkCmdBindPipeline(mCmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->getHandle());
  782. mCmpPipelineRequiresBind = false;
  783. }
  784. if(mDescriptorSetsBindState.isSet(DescriptorSetBindFlag::Compute))
  785. {
  786. VkPipelineLayout pipelineLayout = mComputePipeline->getPipelineLayout(deviceIdx);
  787. vkCmdBindDescriptorSets(mCmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0,
  788. mNumBoundDescriptorSets, mDescriptorSetsTemp, 0, nullptr);
  789. mDescriptorSetsBindState.unset(DescriptorSetBindFlag::Compute);
  790. }
  791. vkCmdDispatch(mCmdBuffer, numGroupsX, numGroupsY, numGroupsZ);
  792. }
  793. void VulkanCmdBuffer::registerResource(VulkanResource* res, VulkanUseFlags flags)
  794. {
  795. auto insertResult = mResources.insert(std::make_pair(res, ResourceUseHandle()));
  796. if(insertResult.second) // New element
  797. {
  798. ResourceUseHandle& useHandle = insertResult.first->second;
  799. useHandle.used = false;
  800. useHandle.flags = flags;
  801. res->notifyBound();
  802. }
  803. else // Existing element
  804. {
  805. ResourceUseHandle& useHandle = insertResult.first->second;
  806. assert(!useHandle.used);
  807. useHandle.flags |= flags;
  808. }
  809. }
  810. void VulkanCmdBuffer::registerResource(VulkanImage* res, VkAccessFlags accessFlags, VkImageLayout layout,
  811. const VkImageSubresourceRange& range, VulkanUseFlags flags)
  812. {
  813. auto insertResult = mImages.insert(std::make_pair(res, ImageInfo()));
  814. if (insertResult.second) // New element
  815. {
  816. ImageInfo& imageInfo = insertResult.first->second;
  817. imageInfo.accessFlags = accessFlags;
  818. imageInfo.layout = layout;
  819. imageInfo.range = range;
  820. imageInfo.useHandle.used = false;
  821. imageInfo.useHandle.flags = flags;
  822. res->notifyBound();
  823. }
  824. else // Existing element
  825. {
  826. ImageInfo& imageInfo = insertResult.first->second;
  827. assert(!imageInfo.useHandle.used);
  828. imageInfo.useHandle.flags |= flags;
  829. assert(imageInfo.layout == layout && "Cannot bind the same image with two different layouts on the same command buffer.");
  830. imageInfo.accessFlags |= accessFlags;
  831. imageInfo.range = range;
  832. }
  833. // Register any sub-resources
  834. for(UINT32 i = 0; i < range.layerCount; i++)
  835. {
  836. for(UINT32 j = 0; j < range.levelCount; j++)
  837. {
  838. UINT32 layer = range.baseArrayLayer + i;
  839. UINT32 mipLevel = range.baseMipLevel + j;
  840. registerResource(res->getSubresource(layer, mipLevel), flags);
  841. }
  842. }
  843. }
  844. void VulkanCmdBuffer::registerResource(VulkanBuffer* res, VkAccessFlags accessFlags, VulkanUseFlags flags)
  845. {
  846. auto insertResult = mBuffers.insert(std::make_pair(res, BufferInfo()));
  847. if (insertResult.second) // New element
  848. {
  849. BufferInfo& bufferInfo = insertResult.first->second;
  850. bufferInfo.accessFlags = accessFlags;
  851. bufferInfo.useHandle.used = false;
  852. bufferInfo.useHandle.flags = flags;
  853. res->notifyBound();
  854. }
  855. else // Existing element
  856. {
  857. BufferInfo& bufferInfo = insertResult.first->second;
  858. assert(!bufferInfo.useHandle.used);
  859. bufferInfo.useHandle.flags |= flags;
  860. bufferInfo.accessFlags |= accessFlags;
  861. }
  862. }
  863. void VulkanCmdBuffer::registerResource(VulkanFramebuffer* res, VulkanUseFlags flags)
  864. {
  865. auto insertResult = mResources.insert(std::make_pair(res, ResourceUseHandle()));
  866. if (insertResult.second) // New element
  867. {
  868. ResourceUseHandle& useHandle = insertResult.first->second;
  869. useHandle.used = false;
  870. useHandle.flags = flags;
  871. res->notifyBound();
  872. }
  873. else // Existing element
  874. {
  875. ResourceUseHandle& useHandle = insertResult.first->second;
  876. assert(!useHandle.used);
  877. useHandle.flags |= flags;
  878. }
  879. // Register any sub-resources
  880. // (Purposely don't register them as images, as we will handle any layout transitions manually)
  881. UINT32 numColorAttachments = res->getNumColorAttachments();
  882. for (UINT32 i = 0; i < numColorAttachments; i++)
  883. {
  884. VulkanImage* image = res->getColorImage(i);
  885. registerResource(image, VulkanUseFlag::Write);
  886. }
  887. if(res->hasDepthAttachment())
  888. {
  889. VulkanImage* image = res->getDepthStencilImage();
  890. registerResource(image, VulkanUseFlag::Write);
  891. }
  892. }
  893. VulkanCommandBuffer::VulkanCommandBuffer(VulkanDevice& device, GpuQueueType type, UINT32 deviceIdx,
  894. UINT32 queueIdx, bool secondary)
  895. : CommandBuffer(type, deviceIdx, queueIdx, secondary), mBuffer(nullptr)
  896. , mDevice(device), mQueue(nullptr), mIdMask(0)
  897. {
  898. UINT32 numQueues = device.getNumQueues(mType);
  899. if (numQueues == 0) // Fall back to graphics queue
  900. {
  901. mType = GQT_GRAPHICS;
  902. numQueues = device.getNumQueues(GQT_GRAPHICS);
  903. }
  904. mQueue = device.getQueue(mType, mQueueIdx % numQueues);
  905. mIdMask = device.getQueueMask(mType, mQueueIdx);
  906. acquireNewBuffer();
  907. }
  908. void VulkanCommandBuffer::acquireNewBuffer()
  909. {
  910. VulkanCmdBufferPool& pool = mDevice.getCmdBufferPool();
  911. if (mBuffer != nullptr)
  912. assert(mBuffer->isSubmitted());
  913. UINT32 queueFamily = mDevice.getQueueFamily(mType);
  914. mBuffer = pool.getBuffer(queueFamily, mIsSecondary);
  915. }
  916. void VulkanCommandBuffer::submit(UINT32 syncMask)
  917. {
  918. // Ignore myself
  919. syncMask &= ~mIdMask;
  920. if (mBuffer->isInRenderPass())
  921. mBuffer->endRenderPass();
  922. if (mBuffer->isRecording())
  923. mBuffer->end();
  924. if (!mBuffer->isReadyForSubmit()) // Possibly nothing was recorded in the buffer
  925. return;
  926. mBuffer->submit(mQueue, mQueueIdx, syncMask);
  927. gVulkanCBManager().refreshStates(mDeviceIdx);
  928. acquireNewBuffer();
  929. }
  930. }