BsVulkanCommandBuffer.cpp 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345
  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. UINT32 imageInfoIdx = entry.second;
  142. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  143. ResourceUseHandle& useHandle = imageInfo.useHandle;
  144. assert(useHandle.used);
  145. entry.first->notifyUnbound();
  146. }
  147. for (auto& entry : mBuffers)
  148. {
  149. ResourceUseHandle& useHandle = entry.second.useHandle;
  150. assert(useHandle.used);
  151. entry.first->notifyUnbound();
  152. }
  153. }
  154. vkDestroyFence(device, mFence, gVulkanAllocator);
  155. vkDestroySemaphore(device, mSemaphore, gVulkanAllocator);
  156. vkFreeCommandBuffers(device, mPool, 1, &mCmdBuffer);
  157. bs_free(mDescriptorSetsTemp);
  158. }
  159. UINT32 VulkanCmdBuffer::getDeviceIdx() const
  160. {
  161. return mDevice.getIndex();
  162. }
  163. void VulkanCmdBuffer::begin()
  164. {
  165. assert(mState == State::Ready);
  166. VkCommandBufferBeginInfo beginInfo;
  167. beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  168. beginInfo.pNext = nullptr;
  169. beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  170. beginInfo.pInheritanceInfo = nullptr;
  171. VkResult result = vkBeginCommandBuffer(mCmdBuffer, &beginInfo);
  172. assert(result == VK_SUCCESS);
  173. mState = State::Recording;
  174. }
  175. void VulkanCmdBuffer::end()
  176. {
  177. assert(mState == State::Recording);
  178. VkResult result = vkEndCommandBuffer(mCmdBuffer);
  179. assert(result == VK_SUCCESS);
  180. mState = State::RecordingDone;
  181. }
  182. void VulkanCmdBuffer::beginRenderPass()
  183. {
  184. assert(mState == State::Recording);
  185. if (mFramebuffer == nullptr)
  186. {
  187. LOGWRN("Attempting to begin a render pass but no render target is bound to the command buffer.");
  188. return;
  189. }
  190. // Perform any queued layout transitions
  191. auto createLayoutTransitionBarrier = [&](VulkanImage* image, ImageInfo& imageInfo)
  192. {
  193. mLayoutTransitionBarriersTemp.push_back(VkImageMemoryBarrier());
  194. VkImageMemoryBarrier& barrier = mLayoutTransitionBarriersTemp.back();
  195. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  196. barrier.pNext = nullptr;
  197. barrier.srcAccessMask = image->getAccessFlags(imageInfo.currentLayout);
  198. barrier.dstAccessMask = imageInfo.accessFlags;
  199. barrier.srcQueueFamilyIndex = mQueueFamily;
  200. barrier.dstQueueFamilyIndex = mQueueFamily;
  201. barrier.oldLayout = imageInfo.currentLayout;
  202. barrier.newLayout = imageInfo.requiredLayout;
  203. barrier.image = image->getHandle();
  204. barrier.subresourceRange = imageInfo.range;
  205. imageInfo.currentLayout = imageInfo.requiredLayout;
  206. };
  207. for (auto& entry : mQueuedLayoutTransitions)
  208. {
  209. UINT32 imageInfoIdx = entry.second;
  210. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  211. createLayoutTransitionBarrier(entry.first, imageInfo);
  212. }
  213. mQueuedLayoutTransitions.clear();
  214. vkCmdPipelineBarrier(mCmdBuffer,
  215. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // Note: VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT might be more correct here, according to the spec
  216. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
  217. 0, 0, nullptr,
  218. 0, nullptr,
  219. (UINT32)mLayoutTransitionBarriersTemp.size(), mLayoutTransitionBarriersTemp.data());
  220. mLayoutTransitionBarriersTemp.clear();
  221. // Check if any frame-buffer attachments are also used as shader inputs, in which case we make them read-only
  222. RenderSurfaceMask readMask = RT_NONE;
  223. UINT32 numColorAttachments = mFramebuffer->getNumColorAttachments();
  224. for(UINT32 i = 0; i < numColorAttachments; i++)
  225. {
  226. VulkanImage* image = mFramebuffer->getColorAttachment(i).image;
  227. UINT32 imageInfoIdx = mImages[image];
  228. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  229. bool readOnly = imageInfo.isShaderInput;
  230. if(readOnly)
  231. readMask.set((RenderSurfaceMaskBits)(1 << i));
  232. }
  233. if(mFramebuffer->hasDepthAttachment())
  234. {
  235. VulkanImage* image = mFramebuffer->getDepthStencilAttachment().image;
  236. UINT32 imageInfoIdx = mImages[image];
  237. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  238. bool readOnly = imageInfo.isShaderInput;
  239. if (readOnly)
  240. readMask.set(RT_DEPTH);
  241. }
  242. VkRenderPassBeginInfo renderPassBeginInfo;
  243. renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  244. renderPassBeginInfo.pNext = nullptr;
  245. renderPassBeginInfo.framebuffer = mFramebuffer->getFramebuffer(mRenderTargetLoadMask, readMask);
  246. renderPassBeginInfo.renderPass = mFramebuffer->getRenderPass(mRenderTargetLoadMask, readMask);
  247. renderPassBeginInfo.renderArea.offset.x = 0;
  248. renderPassBeginInfo.renderArea.offset.y = 0;
  249. renderPassBeginInfo.renderArea.extent.width = mRenderTargetWidth;
  250. renderPassBeginInfo.renderArea.extent.height = mRenderTargetHeight;
  251. renderPassBeginInfo.clearValueCount = 0;
  252. renderPassBeginInfo.pClearValues = nullptr;
  253. vkCmdBeginRenderPass(mCmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
  254. mState = State::RecordingRenderPass;
  255. }
  256. void VulkanCmdBuffer::endRenderPass()
  257. {
  258. assert(mState == State::RecordingRenderPass);
  259. vkCmdEndRenderPass(mCmdBuffer);
  260. mState = State::Recording;
  261. }
  262. void VulkanCmdBuffer::submit(VulkanQueue* queue, UINT32 queueIdx, UINT32 syncMask)
  263. {
  264. assert(isReadyForSubmit());
  265. // Issue pipeline barriers for queue transitions (need to happen on original queue first, then on new queue)
  266. for (auto& entry : mBuffers)
  267. {
  268. VulkanBuffer* resource = static_cast<VulkanBuffer*>(entry.first);
  269. if (!resource->isExclusive())
  270. continue;
  271. UINT32 currentQueueFamily = resource->getQueueFamily();
  272. if (currentQueueFamily != mQueueFamily)
  273. {
  274. Vector<VkBufferMemoryBarrier>& barriers = mTransitionInfoTemp[currentQueueFamily].bufferBarriers;
  275. barriers.push_back(VkBufferMemoryBarrier());
  276. VkBufferMemoryBarrier& barrier = barriers.back();
  277. barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
  278. barrier.pNext = nullptr;
  279. barrier.srcAccessMask = entry.second.accessFlags;
  280. barrier.dstAccessMask = entry.second.accessFlags;
  281. barrier.srcQueueFamilyIndex = currentQueueFamily;
  282. barrier.dstQueueFamilyIndex = mQueueFamily;
  283. barrier.buffer = resource->getHandle();
  284. barrier.offset = 0;
  285. barrier.size = VK_WHOLE_SIZE;
  286. }
  287. }
  288. for (auto& entry : mImages)
  289. {
  290. VulkanImage* resource = static_cast<VulkanImage*>(entry.first);
  291. ImageInfo& imageInfo = mImageInfos[entry.second];
  292. UINT32 currentQueueFamily = resource->getQueueFamily();
  293. bool queueMismatch = resource->isExclusive() && currentQueueFamily != mQueueFamily;
  294. if (queueMismatch || imageInfo.currentLayout != imageInfo.requiredLayout)
  295. {
  296. Vector<VkImageMemoryBarrier>& barriers = mTransitionInfoTemp[currentQueueFamily].imageBarriers;
  297. barriers.push_back(VkImageMemoryBarrier());
  298. VkImageMemoryBarrier& barrier = barriers.back();
  299. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  300. barrier.pNext = nullptr;
  301. barrier.srcAccessMask = imageInfo.accessFlags;
  302. barrier.dstAccessMask = imageInfo.accessFlags;
  303. barrier.srcQueueFamilyIndex = currentQueueFamily;
  304. barrier.dstQueueFamilyIndex = mQueueFamily;
  305. barrier.oldLayout = imageInfo.currentLayout;
  306. barrier.newLayout = imageInfo.requiredLayout;
  307. barrier.image = resource->getHandle();
  308. barrier.subresourceRange = imageInfo.range;
  309. imageInfo.currentLayout = imageInfo.requiredLayout;
  310. resource->setLayout(imageInfo.finalLayout);
  311. }
  312. }
  313. VulkanDevice& device = queue->getDevice();
  314. for (auto& entry : mTransitionInfoTemp)
  315. {
  316. bool empty = entry.second.imageBarriers.size() == 0 && entry.second.bufferBarriers.size() == 0;
  317. if (empty)
  318. continue;
  319. UINT32 entryQueueFamily = entry.first;
  320. // No queue transition needed for entries on this queue (this entry is most likely an image layout transition)
  321. if (entryQueueFamily == mQueueFamily)
  322. continue;
  323. VulkanCmdBuffer* cmdBuffer = device.getCmdBufferPool().getBuffer(entryQueueFamily, false);
  324. VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
  325. TransitionInfo& barriers = entry.second;
  326. UINT32 numImgBarriers = (UINT32)barriers.imageBarriers.size();
  327. UINT32 numBufferBarriers = (UINT32)barriers.bufferBarriers.size();
  328. vkCmdPipelineBarrier(vkCmdBuffer,
  329. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // Note: VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT might be more correct here, according to the spec
  330. 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.
  331. 0, 0, nullptr,
  332. numBufferBarriers, barriers.bufferBarriers.data(),
  333. numImgBarriers, barriers.imageBarriers.data());
  334. // Find an appropriate queue to execute on
  335. UINT32 otherQueueIdx = 0;
  336. VulkanQueue* otherQueue = nullptr;
  337. GpuQueueType otherQueueType = GQT_GRAPHICS;
  338. for (UINT32 i = 0; i < GQT_COUNT; i++)
  339. {
  340. if (device.getQueueFamily((GpuQueueType)i) != entryQueueFamily)
  341. continue;
  342. UINT32 numQueues = device.getNumQueues(otherQueueType);
  343. for (UINT32 j = 0; j < numQueues; j++)
  344. {
  345. // Try to find a queue not currently executing
  346. VulkanQueue* curQueue = device.getQueue(otherQueueType, j);
  347. if (!curQueue->isExecuting())
  348. {
  349. otherQueue = curQueue;
  350. otherQueueIdx = j;
  351. }
  352. }
  353. // Can't find empty one, use the first one then
  354. if (otherQueue == nullptr)
  355. {
  356. otherQueue = device.getQueue(otherQueueType, 0);
  357. otherQueueIdx = 0;
  358. }
  359. otherQueueType = (GpuQueueType)i;
  360. break;
  361. }
  362. syncMask |= CommandSyncMask::getGlobalQueueMask(otherQueueType, otherQueueIdx);
  363. cmdBuffer->end();
  364. cmdBuffer->submit(otherQueue, otherQueueIdx, 0);
  365. // If there are any layout transitions, reset them as we don't need them for the second pipeline barrier
  366. for (auto& barrierEntry : barriers.imageBarriers)
  367. barrierEntry.oldLayout = barrierEntry.newLayout;
  368. }
  369. UINT32 deviceIdx = device.getIndex();
  370. VulkanCommandBufferManager& cbm = static_cast<VulkanCommandBufferManager&>(CommandBufferManager::instance());
  371. UINT32 numSemaphores;
  372. cbm.getSyncSemaphores(deviceIdx, syncMask, mSemaphoresTemp, numSemaphores);
  373. // Wait on present (i.e. until the back buffer becomes available), if we're rendering to a window
  374. if (mPresentSemaphore != VK_NULL_HANDLE)
  375. {
  376. mSemaphoresTemp[numSemaphores] = mPresentSemaphore;
  377. numSemaphores++;
  378. }
  379. // Issue second part of transition pipeline barriers (on this queue)
  380. for (auto& entry : mTransitionInfoTemp)
  381. {
  382. bool empty = entry.second.imageBarriers.size() == 0 && entry.second.bufferBarriers.size() == 0;
  383. if (empty)
  384. continue;
  385. VulkanCmdBuffer* cmdBuffer = device.getCmdBufferPool().getBuffer(mQueueFamily, false);
  386. VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
  387. TransitionInfo& barriers = entry.second;
  388. UINT32 numImgBarriers = (UINT32)barriers.imageBarriers.size();
  389. UINT32 numBufferBarriers = (UINT32)barriers.bufferBarriers.size();
  390. vkCmdPipelineBarrier(vkCmdBuffer,
  391. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, // Note: VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT might be more correct here, according to the spec
  392. VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
  393. 0, 0, nullptr,
  394. numBufferBarriers, barriers.bufferBarriers.data(),
  395. numImgBarriers, barriers.imageBarriers.data());
  396. cmdBuffer->end();
  397. queue->submit(cmdBuffer, mSemaphoresTemp, numSemaphores);
  398. numSemaphores = 0; // Semaphores are only needed the first time, since we're adding the buffers on the same queue
  399. }
  400. queue->submit(this, mSemaphoresTemp, numSemaphores);
  401. mGlobalQueueIdx = CommandSyncMask::getGlobalQueueIdx(queue->getType(), queueIdx);
  402. for (auto& entry : mResources)
  403. {
  404. ResourceUseHandle& useHandle = entry.second;
  405. assert(!useHandle.used);
  406. useHandle.used = true;
  407. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  408. }
  409. for (auto& entry : mImages)
  410. {
  411. UINT32 imageInfoIdx = entry.second;
  412. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  413. ResourceUseHandle& useHandle = imageInfo.useHandle;
  414. assert(!useHandle.used);
  415. useHandle.used = true;
  416. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  417. }
  418. for (auto& entry : mBuffers)
  419. {
  420. ResourceUseHandle& useHandle = entry.second.useHandle;
  421. assert(!useHandle.used);
  422. useHandle.used = true;
  423. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  424. }
  425. // Note: Uncommented for debugging only, prevents any device concurrency issues.
  426. // vkQueueWaitIdle(queue->getHandle());
  427. mState = State::Submitted;
  428. cbm.setActiveBuffer(queue->getType(), deviceIdx, queueIdx, this);
  429. // Clear vectors but don't clear the actual map, as we want to re-use the memory since we expect queue family
  430. // indices to be the same
  431. for (auto& entry : mTransitionInfoTemp)
  432. {
  433. entry.second.imageBarriers.clear();
  434. entry.second.bufferBarriers.clear();
  435. }
  436. mGraphicsPipeline = nullptr;
  437. mComputePipeline = nullptr;
  438. mGfxPipelineRequiresBind = true;
  439. mCmpPipelineRequiresBind = true;
  440. mFramebuffer = nullptr;
  441. mDescriptorSetsBindState = DescriptorSetBindFlag::Graphics | DescriptorSetBindFlag::Compute;
  442. mQueuedLayoutTransitions.clear();
  443. }
  444. void VulkanCmdBuffer::refreshFenceStatus()
  445. {
  446. VkResult result = vkGetFenceStatus(mDevice.getLogical(), mFence);
  447. assert(result == VK_SUCCESS || result == VK_NOT_READY);
  448. bool signaled = result == VK_SUCCESS;
  449. if (mState == State::Submitted)
  450. {
  451. if(signaled)
  452. {
  453. mState = State::Ready;
  454. vkResetCommandBuffer(mCmdBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); // Note: Maybe better not to release resources?
  455. result = vkResetFences(mDevice.getLogical(), 1, &mFence);
  456. assert(result == VK_SUCCESS);
  457. mFenceCounter++;
  458. for (auto& entry : mResources)
  459. {
  460. ResourceUseHandle& useHandle = entry.second;
  461. assert(useHandle.used);
  462. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  463. }
  464. for (auto& entry : mImages)
  465. {
  466. UINT32 imageInfoIdx = entry.second;
  467. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  468. ResourceUseHandle& useHandle = imageInfo.useHandle;
  469. assert(useHandle.used);
  470. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  471. }
  472. for (auto& entry : mBuffers)
  473. {
  474. ResourceUseHandle& useHandle = entry.second.useHandle;
  475. assert(useHandle.used);
  476. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  477. }
  478. mResources.clear();
  479. mImages.clear();
  480. mBuffers.clear();
  481. mImageInfos.clear();
  482. }
  483. }
  484. else
  485. assert(!signaled); // We reset the fence along with mState so this shouldn't be possible
  486. }
  487. void VulkanCmdBuffer::setRenderTarget(const SPtr<RenderTargetCore>& rt, bool readOnlyDepthStencil,
  488. RenderSurfaceMask loadMask)
  489. {
  490. assert(mState != State::RecordingRenderPass && mState != State::Submitted);
  491. VulkanFramebuffer* oldFramebuffer = mFramebuffer;
  492. if(rt == nullptr)
  493. {
  494. mFramebuffer = nullptr;
  495. mPresentSemaphore = VK_NULL_HANDLE;
  496. mRenderTargetWidth = 0;
  497. mRenderTargetHeight = 0;
  498. mRenderTargetDepthReadOnly = false;
  499. mRenderTargetLoadMask = RT_NONE;
  500. }
  501. else
  502. {
  503. rt->getCustomAttribute("FB", &mFramebuffer);
  504. if (rt->getProperties().isWindow())
  505. rt->getCustomAttribute("PS", &mPresentSemaphore);
  506. else
  507. mPresentSemaphore = VK_NULL_HANDLE;
  508. mRenderTargetWidth = rt->getProperties().getWidth();
  509. mRenderTargetHeight = rt->getProperties().getHeight();
  510. mRenderTargetDepthReadOnly = readOnlyDepthStencil;
  511. mRenderTargetLoadMask = loadMask;
  512. }
  513. // If anything changed
  514. if(oldFramebuffer != mFramebuffer)
  515. {
  516. if (isInRenderPass())
  517. endRenderPass();
  518. // Reset flags that signal image usage
  519. for (auto& entry : mImages)
  520. {
  521. UINT32 imageInfoIdx = entry.second;
  522. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  523. imageInfo.isFBAttachment = false;
  524. imageInfo.isShaderInput = false;
  525. }
  526. setGpuParams(nullptr);
  527. registerResource(mFramebuffer, VulkanUseFlag::Write);
  528. mGfxPipelineRequiresBind = true;
  529. }
  530. }
  531. void VulkanCmdBuffer::clearViewport(const Rect2I& area, UINT32 buffers, const Color& color, float depth, UINT16 stencil,
  532. UINT8 targetMask)
  533. {
  534. if (buffers == 0 || mFramebuffer == nullptr)
  535. return;
  536. VkClearAttachment attachments[BS_MAX_MULTIPLE_RENDER_TARGETS + 1];
  537. UINT32 baseLayer = 0;
  538. UINT32 attachmentIdx = 0;
  539. if ((buffers & FBT_COLOR) != 0)
  540. {
  541. UINT32 numColorAttachments = mFramebuffer->getNumColorAttachments();
  542. for (UINT32 i = 0; i < numColorAttachments; i++)
  543. {
  544. const VulkanFramebufferAttachment& attachment = mFramebuffer->getColorAttachment(i);
  545. if (((1 << attachment.index) & targetMask) == 0)
  546. continue;
  547. attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  548. attachments[attachmentIdx].colorAttachment = i;
  549. VkClearColorValue& colorValue = attachments[attachmentIdx].clearValue.color;
  550. colorValue.float32[0] = color.r;
  551. colorValue.float32[1] = color.g;
  552. colorValue.float32[2] = color.b;
  553. colorValue.float32[3] = color.a;
  554. UINT32 curBaseLayer = attachment.baseLayer;
  555. if (attachmentIdx == 0)
  556. baseLayer = curBaseLayer;
  557. else
  558. {
  559. if(baseLayer != curBaseLayer)
  560. {
  561. // Note: This could be supported relatively easily: we would need to issue multiple separate
  562. // clear commands for such framebuffers.
  563. LOGERR("Attempting to clear a texture that has multiple multi-layer surfaces with mismatching "
  564. "starting layers. This is currently not supported.");
  565. }
  566. }
  567. attachmentIdx++;
  568. }
  569. }
  570. if ((buffers & FBT_DEPTH) != 0 || (buffers & FBT_STENCIL) != 0)
  571. {
  572. if (mFramebuffer->hasDepthAttachment())
  573. {
  574. if ((buffers & FBT_DEPTH) != 0)
  575. {
  576. attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
  577. attachments[attachmentIdx].clearValue.depthStencil.depth = depth;
  578. }
  579. if ((buffers & FBT_STENCIL) != 0)
  580. {
  581. attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
  582. attachments[attachmentIdx].clearValue.depthStencil.stencil = stencil;
  583. }
  584. attachments[attachmentIdx].colorAttachment = 0;
  585. UINT32 curBaseLayer = mFramebuffer->getDepthStencilAttachment().baseLayer;
  586. if (attachmentIdx == 0)
  587. baseLayer = curBaseLayer;
  588. else
  589. {
  590. if (baseLayer != curBaseLayer)
  591. {
  592. // Note: This could be supported relatively easily: we would need to issue multiple separate
  593. // clear commands for such framebuffers.
  594. LOGERR("Attempting to clear a texture that has multiple multi-layer surfaces with mismatching "
  595. "starting layers. This is currently not supported.");
  596. }
  597. }
  598. attachmentIdx++;
  599. }
  600. }
  601. VkClearRect clearRect;
  602. clearRect.baseArrayLayer = baseLayer;
  603. clearRect.layerCount = mFramebuffer->getNumLayers();
  604. clearRect.rect.offset.x = area.x;
  605. clearRect.rect.offset.y = area.y;
  606. clearRect.rect.extent.width = area.width;
  607. clearRect.rect.extent.height = area.height;
  608. UINT32 numAttachments = attachmentIdx;
  609. vkCmdClearAttachments(mCmdBuffer, numAttachments, attachments, 1, &clearRect);
  610. }
  611. void VulkanCmdBuffer::clearRenderTarget(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask)
  612. {
  613. Rect2I area(0, 0, mRenderTargetWidth, mRenderTargetHeight);
  614. clearViewport(area, buffers, color, depth, stencil, targetMask);
  615. }
  616. void VulkanCmdBuffer::clearViewport(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask)
  617. {
  618. Rect2I area;
  619. area.x = (UINT32)(mViewport.x * mRenderTargetWidth);
  620. area.y = (UINT32)(mViewport.y * mRenderTargetHeight);
  621. area.width = (UINT32)(mViewport.width * mRenderTargetWidth);
  622. area.height = (UINT32)(mViewport.height * mRenderTargetHeight);
  623. clearViewport(area, buffers, color, depth, stencil, targetMask);
  624. }
  625. void VulkanCmdBuffer::setPipelineState(const SPtr<GraphicsPipelineStateCore>& state)
  626. {
  627. if (mGraphicsPipeline == state)
  628. return;
  629. mGraphicsPipeline = std::static_pointer_cast<VulkanGraphicsPipelineStateCore>(state);
  630. mGfxPipelineRequiresBind = true;
  631. }
  632. void VulkanCmdBuffer::setPipelineState(const SPtr<ComputePipelineStateCore>& state)
  633. {
  634. if (mComputePipeline == state)
  635. return;
  636. mComputePipeline = std::static_pointer_cast<VulkanComputePipelineStateCore>(state);
  637. mCmpPipelineRequiresBind = true;
  638. }
  639. void VulkanCmdBuffer::setGpuParams(const SPtr<GpuParamsCore>& gpuParams)
  640. {
  641. SPtr<VulkanGpuParams> vulkanGpuParams = std::static_pointer_cast<VulkanGpuParams>(gpuParams);
  642. if(vulkanGpuParams != nullptr)
  643. {
  644. mNumBoundDescriptorSets = vulkanGpuParams->getNumSets();
  645. vulkanGpuParams->prepareForBind(*this, mDescriptorSetsTemp);
  646. }
  647. else
  648. {
  649. mNumBoundDescriptorSets = 0;
  650. }
  651. mDescriptorSetsBindState = DescriptorSetBindFlag::Graphics | DescriptorSetBindFlag::Compute;
  652. }
  653. void VulkanCmdBuffer::setViewport(const Rect2& area)
  654. {
  655. if (mViewport == area)
  656. return;
  657. mViewport = area;
  658. mViewportRequiresBind = true;
  659. }
  660. void VulkanCmdBuffer::setScissorRect(const Rect2I& value)
  661. {
  662. if (mScissor == value)
  663. return;
  664. mScissor = value;
  665. mScissorRequiresBind = true;
  666. }
  667. void VulkanCmdBuffer::setStencilRef(UINT32 value)
  668. {
  669. if (mStencilRef == value)
  670. return;
  671. mStencilRef = value;
  672. mStencilRefRequiresBind = true;
  673. }
  674. void VulkanCmdBuffer::setDrawOp(DrawOperationType drawOp)
  675. {
  676. if (mDrawOp == drawOp)
  677. return;
  678. mDrawOp = drawOp;
  679. mGfxPipelineRequiresBind = true;
  680. }
  681. void VulkanCmdBuffer::setVertexBuffers(UINT32 index, SPtr<VertexBufferCore>* buffers, UINT32 numBuffers)
  682. {
  683. if (numBuffers == 0)
  684. return;
  685. for(UINT32 i = 0; i < numBuffers; i++)
  686. {
  687. VulkanVertexBufferCore* vertexBuffer = static_cast<VulkanVertexBufferCore*>(buffers[i].get());
  688. if (vertexBuffer != nullptr)
  689. {
  690. VulkanBuffer* resource = vertexBuffer->getResource(mDevice.getIndex());
  691. if (resource != nullptr)
  692. {
  693. mVertexBuffersTemp[i] = resource->getHandle();
  694. registerResource(resource, VulkanUseFlag::Read);
  695. }
  696. else
  697. mVertexBuffersTemp[i] = VK_NULL_HANDLE;
  698. }
  699. else
  700. mVertexBuffersTemp[i] = VK_NULL_HANDLE;
  701. }
  702. vkCmdBindVertexBuffers(mCmdBuffer, index, numBuffers, mVertexBuffersTemp, mVertexBufferOffsetsTemp);
  703. }
  704. void VulkanCmdBuffer::setIndexBuffer(const SPtr<IndexBufferCore>& buffer)
  705. {
  706. VulkanIndexBufferCore* indexBuffer = static_cast<VulkanIndexBufferCore*>(buffer.get());
  707. VkBuffer vkBuffer = VK_NULL_HANDLE;
  708. VkIndexType indexType = VK_INDEX_TYPE_UINT32;
  709. if (indexBuffer != nullptr)
  710. {
  711. VulkanBuffer* resource = indexBuffer->getResource(mDevice.getIndex());
  712. if (resource != nullptr)
  713. {
  714. vkBuffer = resource->getHandle();
  715. indexType = VulkanUtility::getIndexType(buffer->getProperties().getType());
  716. registerResource(resource, VulkanUseFlag::Read);
  717. }
  718. }
  719. vkCmdBindIndexBuffer(mCmdBuffer, vkBuffer, 0, indexType);
  720. }
  721. void VulkanCmdBuffer::setVertexDeclaration(const SPtr<VertexDeclarationCore>& decl)
  722. {
  723. if (mVertexDecl == decl)
  724. return;
  725. mVertexDecl = decl;
  726. mGfxPipelineRequiresBind = true;
  727. }
  728. bool VulkanCmdBuffer::isReadyForRender()
  729. {
  730. if (mGraphicsPipeline == nullptr)
  731. return false;
  732. SPtr<VertexDeclarationCore> inputDecl = mGraphicsPipeline->getInputDeclaration();
  733. if (inputDecl == nullptr)
  734. return false;
  735. return mFramebuffer != nullptr && mVertexDecl != nullptr;
  736. }
  737. bool VulkanCmdBuffer::bindGraphicsPipeline()
  738. {
  739. SPtr<VertexDeclarationCore> inputDecl = mGraphicsPipeline->getInputDeclaration();
  740. SPtr<VulkanVertexInput> vertexInput = VulkanVertexInputManager::instance().getVertexInfo(mVertexDecl, inputDecl);
  741. VulkanPipeline* pipeline = mGraphicsPipeline->getPipeline(mDevice.getIndex(), mFramebuffer,
  742. mRenderTargetDepthReadOnly, mRenderTargetLoadMask,
  743. RT_NONE, mDrawOp, vertexInput);
  744. if (pipeline == nullptr)
  745. return false;
  746. // Check that pipeline matches the read-only state of any framebuffer attachments
  747. UINT32 numColorAttachments = mFramebuffer->getNumColorAttachments();
  748. for (UINT32 i = 0; i < numColorAttachments; i++)
  749. {
  750. VulkanImage* image = mFramebuffer->getColorAttachment(i).image;
  751. UINT32 imageInfoIdx = mImages[image];
  752. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  753. if (imageInfo.isShaderInput && !pipeline->isColorReadOnly(i))
  754. {
  755. LOGWRN("Framebuffer attachment also used as a shader input, but color writes aren't disabled. This will"
  756. " result in undefined behavior.");
  757. }
  758. }
  759. if (mFramebuffer->hasDepthAttachment())
  760. {
  761. VulkanImage* image = mFramebuffer->getDepthStencilAttachment().image;
  762. UINT32 imageInfoIdx = mImages[image];
  763. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  764. if (imageInfo.isShaderInput && !pipeline->isDepthStencilReadOnly())
  765. {
  766. LOGWRN("Framebuffer attachment also used as a shader input, but depth/stencil writes aren't disabled. "
  767. "This will result in undefined behavior.");
  768. }
  769. }
  770. mGraphicsPipeline->registerPipelineResources(this);
  771. registerResource(pipeline, VulkanUseFlag::Read);
  772. vkCmdBindPipeline(mCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getHandle());
  773. bindDynamicStates(true);
  774. mGfxPipelineRequiresBind = false;
  775. return true;
  776. }
  777. void VulkanCmdBuffer::bindDynamicStates(bool forceAll)
  778. {
  779. if (mViewportRequiresBind || forceAll)
  780. {
  781. VkViewport viewport;
  782. viewport.x = mViewport.x * mRenderTargetWidth;
  783. viewport.y = mViewport.y * mRenderTargetHeight;
  784. viewport.width = mViewport.width * mRenderTargetWidth;
  785. viewport.height = mViewport.height * mRenderTargetHeight;
  786. viewport.minDepth = 0.0f;
  787. viewport.maxDepth = 1.0f;
  788. vkCmdSetViewport(mCmdBuffer, 0, 1, &viewport);
  789. mViewportRequiresBind = false;
  790. }
  791. if(mStencilRefRequiresBind || forceAll)
  792. {
  793. vkCmdSetStencilReference(mCmdBuffer, VK_STENCIL_FRONT_AND_BACK, mStencilRef);
  794. mStencilRefRequiresBind = false;
  795. }
  796. if(mScissorRequiresBind || forceAll)
  797. {
  798. VkRect2D scissorRect;
  799. if(mGraphicsPipeline->isScissorEnabled())
  800. {
  801. scissorRect.offset.x = mScissor.x;
  802. scissorRect.offset.y = mScissor.y;
  803. scissorRect.extent.width = mScissor.width;
  804. scissorRect.extent.height = mScissor.height;
  805. }
  806. else
  807. {
  808. scissorRect.offset.x = 0;
  809. scissorRect.offset.y = 0;
  810. scissorRect.extent.width = mRenderTargetWidth;
  811. scissorRect.extent.height = mRenderTargetHeight;
  812. }
  813. vkCmdSetScissor(mCmdBuffer, 0, 1, &scissorRect);
  814. mScissorRequiresBind = false;
  815. }
  816. }
  817. void VulkanCmdBuffer::draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount)
  818. {
  819. if (!isReadyForRender())
  820. return;
  821. if (!isInRenderPass())
  822. beginRenderPass();
  823. if (mGfxPipelineRequiresBind)
  824. {
  825. if (!bindGraphicsPipeline())
  826. return;
  827. }
  828. else
  829. bindDynamicStates(false);
  830. if (mDescriptorSetsBindState.isSet(DescriptorSetBindFlag::Graphics))
  831. {
  832. UINT32 deviceIdx = mDevice.getIndex();
  833. VkPipelineLayout pipelineLayout = mGraphicsPipeline->getPipelineLayout(deviceIdx);
  834. vkCmdBindDescriptorSets(mCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0,
  835. mNumBoundDescriptorSets, mDescriptorSetsTemp, 0, nullptr);
  836. mDescriptorSetsBindState.unset(DescriptorSetBindFlag::Graphics);
  837. }
  838. vkCmdDraw(mCmdBuffer, vertexCount, instanceCount, vertexOffset, 0);
  839. }
  840. void VulkanCmdBuffer::drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 instanceCount)
  841. {
  842. if (!isReadyForRender())
  843. return;
  844. if (!isInRenderPass())
  845. beginRenderPass();
  846. if (mGfxPipelineRequiresBind)
  847. {
  848. if (!bindGraphicsPipeline())
  849. return;
  850. }
  851. else
  852. bindDynamicStates(false);
  853. if (mDescriptorSetsBindState.isSet(DescriptorSetBindFlag::Graphics))
  854. {
  855. UINT32 deviceIdx = mDevice.getIndex();
  856. VkPipelineLayout pipelineLayout = mGraphicsPipeline->getPipelineLayout(deviceIdx);
  857. vkCmdBindDescriptorSets(mCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0,
  858. mNumBoundDescriptorSets, mDescriptorSetsTemp, 0, nullptr);
  859. mDescriptorSetsBindState.unset(DescriptorSetBindFlag::Graphics);
  860. }
  861. vkCmdDrawIndexed(mCmdBuffer, indexCount, instanceCount, startIndex, vertexOffset, 0);
  862. }
  863. void VulkanCmdBuffer::dispatch(UINT32 numGroupsX, UINT32 numGroupsY, UINT32 numGroupsZ)
  864. {
  865. if (mComputePipeline == nullptr)
  866. return;
  867. if (isInRenderPass())
  868. endRenderPass();
  869. UINT32 deviceIdx = mDevice.getIndex();
  870. if(mCmpPipelineRequiresBind)
  871. {
  872. VulkanPipeline* pipeline = mComputePipeline->getPipeline(deviceIdx);
  873. if (pipeline == nullptr)
  874. return;
  875. registerResource(pipeline, VulkanUseFlag::Read);
  876. mComputePipeline->registerPipelineResources(this);
  877. vkCmdBindPipeline(mCmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->getHandle());
  878. mCmpPipelineRequiresBind = false;
  879. }
  880. if(mDescriptorSetsBindState.isSet(DescriptorSetBindFlag::Compute))
  881. {
  882. VkPipelineLayout pipelineLayout = mComputePipeline->getPipelineLayout(deviceIdx);
  883. vkCmdBindDescriptorSets(mCmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0,
  884. mNumBoundDescriptorSets, mDescriptorSetsTemp, 0, nullptr);
  885. mDescriptorSetsBindState.unset(DescriptorSetBindFlag::Compute);
  886. }
  887. vkCmdDispatch(mCmdBuffer, numGroupsX, numGroupsY, numGroupsZ);
  888. }
  889. void VulkanCmdBuffer::registerResource(VulkanResource* res, VulkanUseFlags flags)
  890. {
  891. auto insertResult = mResources.insert(std::make_pair(res, ResourceUseHandle()));
  892. if(insertResult.second) // New element
  893. {
  894. ResourceUseHandle& useHandle = insertResult.first->second;
  895. useHandle.used = false;
  896. useHandle.flags = flags;
  897. res->notifyBound();
  898. }
  899. else // Existing element
  900. {
  901. ResourceUseHandle& useHandle = insertResult.first->second;
  902. assert(!useHandle.used);
  903. useHandle.flags |= flags;
  904. }
  905. }
  906. void VulkanCmdBuffer::registerResource(VulkanImage* res, VkAccessFlags accessFlags, VkImageLayout layout,
  907. VulkanUseFlags flags, bool isFBAttachment)
  908. {
  909. // Note: I currently always perform pipeline barriers (layout transitions and similar), over the entire image.
  910. // In the case of render and storage images, the case is often that only a specific subresource requires
  911. // it. However this makes grouping and tracking of current image layouts much more difficult.
  912. // If this is ever requires we'll need to track image layout per-subresource instead per-image, and we
  913. // might also need a smart way to group layout transitions for multiple sub-resources on the same image.
  914. VkImageSubresourceRange range = res->getRange();
  915. UINT32 nextImageInfoIdx = (UINT32)mImageInfos.size();
  916. auto insertResult = mImages.insert(std::make_pair(res, nextImageInfoIdx));
  917. if (insertResult.second) // New element
  918. {
  919. UINT32 imageInfoIdx = insertResult.first->second;
  920. mImageInfos.push_back(ImageInfo());
  921. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  922. imageInfo.accessFlags = accessFlags;
  923. imageInfo.currentLayout = res->getLayout();
  924. imageInfo.requiredLayout = layout;
  925. imageInfo.finalLayout = layout;
  926. imageInfo.range = range;
  927. imageInfo.isFBAttachment = isFBAttachment;
  928. imageInfo.isShaderInput = !isFBAttachment;
  929. imageInfo.useHandle.used = false;
  930. imageInfo.useHandle.flags = flags;
  931. res->notifyBound();
  932. if (imageInfo.currentLayout != imageInfo.requiredLayout)
  933. mQueuedLayoutTransitions[res] = imageInfoIdx;
  934. }
  935. else // Existing element
  936. {
  937. UINT32 imageInfoIdx = insertResult.first->second;
  938. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  939. assert(!imageInfo.useHandle.used);
  940. imageInfo.useHandle.flags |= flags;
  941. imageInfo.accessFlags |= accessFlags;
  942. // Check if the same image is used with different layouts, in which case we need to transfer to the general
  943. // layout
  944. if (imageInfo.requiredLayout != layout)
  945. imageInfo.requiredLayout = VK_IMAGE_LAYOUT_GENERAL;
  946. // If attached to FB, then the final layout is set by the FB (provided as layout param here), otherwise its
  947. // the same as required layout
  948. if(!isFBAttachment && !imageInfo.isFBAttachment)
  949. imageInfo.finalLayout = imageInfo.requiredLayout;
  950. else
  951. {
  952. if (isFBAttachment)
  953. imageInfo.finalLayout = layout;
  954. }
  955. if (imageInfo.currentLayout != imageInfo.requiredLayout)
  956. mQueuedLayoutTransitions[res] = imageInfoIdx;
  957. // If a FB attachment was just bound as a shader input, we might need to restart the render pass with a FB
  958. // attachment that supports read-only attachments using the GENERAL layout
  959. bool requiresReadOnlyFB = false;
  960. if (isFBAttachment)
  961. {
  962. if (!imageInfo.isFBAttachment)
  963. {
  964. imageInfo.isFBAttachment = true;
  965. requiresReadOnlyFB = imageInfo.isShaderInput;
  966. }
  967. }
  968. else
  969. {
  970. if (!imageInfo.isShaderInput)
  971. {
  972. imageInfo.isShaderInput = true;
  973. requiresReadOnlyFB = imageInfo.isFBAttachment;
  974. }
  975. }
  976. // If we need to switch frame-buffers, end current render pass
  977. if (requiresReadOnlyFB && isInRenderPass())
  978. endRenderPass();
  979. }
  980. // Register any sub-resources
  981. for(UINT32 i = 0; i < range.layerCount; i++)
  982. {
  983. for(UINT32 j = 0; j < range.levelCount; j++)
  984. {
  985. UINT32 layer = range.baseArrayLayer + i;
  986. UINT32 mipLevel = range.baseMipLevel + j;
  987. registerResource(res->getSubresource(layer, mipLevel), flags);
  988. }
  989. }
  990. }
  991. void VulkanCmdBuffer::registerResource(VulkanBuffer* res, VkAccessFlags accessFlags, VulkanUseFlags flags)
  992. {
  993. auto insertResult = mBuffers.insert(std::make_pair(res, BufferInfo()));
  994. if (insertResult.second) // New element
  995. {
  996. BufferInfo& bufferInfo = insertResult.first->second;
  997. bufferInfo.accessFlags = accessFlags;
  998. bufferInfo.useHandle.used = false;
  999. bufferInfo.useHandle.flags = flags;
  1000. res->notifyBound();
  1001. }
  1002. else // Existing element
  1003. {
  1004. BufferInfo& bufferInfo = insertResult.first->second;
  1005. assert(!bufferInfo.useHandle.used);
  1006. bufferInfo.useHandle.flags |= flags;
  1007. bufferInfo.accessFlags |= accessFlags;
  1008. }
  1009. }
  1010. void VulkanCmdBuffer::registerResource(VulkanFramebuffer* res, VulkanUseFlags flags)
  1011. {
  1012. auto insertResult = mResources.insert(std::make_pair(res, ResourceUseHandle()));
  1013. if (insertResult.second) // New element
  1014. {
  1015. ResourceUseHandle& useHandle = insertResult.first->second;
  1016. useHandle.used = false;
  1017. useHandle.flags = flags;
  1018. res->notifyBound();
  1019. }
  1020. else // Existing element
  1021. {
  1022. ResourceUseHandle& useHandle = insertResult.first->second;
  1023. assert(!useHandle.used);
  1024. useHandle.flags |= flags;
  1025. }
  1026. // Register any sub-resources
  1027. UINT32 numColorAttachments = res->getNumColorAttachments();
  1028. for (UINT32 i = 0; i < numColorAttachments; i++)
  1029. {
  1030. const VulkanFramebufferAttachment& attachment = res->getColorAttachment(i);
  1031. registerResource(attachment.image, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT,
  1032. attachment.finalLayout, VulkanUseFlag::Write, true);
  1033. }
  1034. if(res->hasDepthAttachment())
  1035. {
  1036. const VulkanFramebufferAttachment& attachment = res->getDepthStencilAttachment();
  1037. registerResource(attachment.image,
  1038. VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT,
  1039. attachment.finalLayout, VulkanUseFlag::Write, true);
  1040. }
  1041. }
  1042. VulkanCommandBuffer::VulkanCommandBuffer(VulkanDevice& device, GpuQueueType type, UINT32 deviceIdx,
  1043. UINT32 queueIdx, bool secondary)
  1044. : CommandBuffer(type, deviceIdx, queueIdx, secondary), mBuffer(nullptr)
  1045. , mDevice(device), mQueue(nullptr), mIdMask(0)
  1046. {
  1047. UINT32 numQueues = device.getNumQueues(mType);
  1048. if (numQueues == 0) // Fall back to graphics queue
  1049. {
  1050. mType = GQT_GRAPHICS;
  1051. numQueues = device.getNumQueues(GQT_GRAPHICS);
  1052. }
  1053. mQueue = device.getQueue(mType, mQueueIdx % numQueues);
  1054. mIdMask = device.getQueueMask(mType, mQueueIdx);
  1055. acquireNewBuffer();
  1056. }
  1057. void VulkanCommandBuffer::acquireNewBuffer()
  1058. {
  1059. VulkanCmdBufferPool& pool = mDevice.getCmdBufferPool();
  1060. if (mBuffer != nullptr)
  1061. assert(mBuffer->isSubmitted());
  1062. UINT32 queueFamily = mDevice.getQueueFamily(mType);
  1063. mBuffer = pool.getBuffer(queueFamily, mIsSecondary);
  1064. }
  1065. void VulkanCommandBuffer::submit(UINT32 syncMask)
  1066. {
  1067. // Ignore myself
  1068. syncMask &= ~mIdMask;
  1069. if (mBuffer->isInRenderPass())
  1070. mBuffer->endRenderPass();
  1071. if (mBuffer->isRecording())
  1072. mBuffer->end();
  1073. if (!mBuffer->isReadyForSubmit()) // Possibly nothing was recorded in the buffer
  1074. return;
  1075. mBuffer->submit(mQueue, mQueueIdx, syncMask);
  1076. gVulkanCBManager().refreshStates(mDeviceIdx);
  1077. acquireNewBuffer();
  1078. }
  1079. }