BsVulkanCommandBuffer.cpp 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsVulkanCommandBuffer.h"
  4. #include "Managers/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 "Managers/BsVulkanVertexInputManager.h"
  15. #include "BsVulkanEventQuery.h"
  16. #include "Managers/BsVulkanQueryManager.h"
  17. #include "BsVulkanSwapChain.h"
  18. #include "BsVulkanTimerQuery.h"
  19. #include "BsVulkanOcclusionQuery.h"
  20. #if BS_PLATFORM == BS_PLATFORM_WIN32
  21. #include "Win32/BsWin32RenderWindow.h"
  22. #else
  23. static_assert(false, "Other platforms go here");
  24. #endif
  25. namespace bs { namespace ct
  26. {
  27. VulkanSemaphore::VulkanSemaphore(VulkanResourceManager* owner)
  28. :VulkanResource(owner, true)
  29. {
  30. VkSemaphoreCreateInfo semaphoreCI;
  31. semaphoreCI.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
  32. semaphoreCI.pNext = nullptr;
  33. semaphoreCI.flags = 0;
  34. VkResult result = vkCreateSemaphore(owner->getDevice().getLogical(), &semaphoreCI, gVulkanAllocator, &mSemaphore);
  35. assert(result == VK_SUCCESS);
  36. }
  37. VulkanSemaphore::~VulkanSemaphore()
  38. {
  39. vkDestroySemaphore(mOwner->getDevice().getLogical(), mSemaphore, gVulkanAllocator);
  40. }
  41. VulkanCmdBufferPool::VulkanCmdBufferPool(VulkanDevice& device)
  42. :mDevice(device), mNextId(1)
  43. {
  44. for (UINT32 i = 0; i < GQT_COUNT; i++)
  45. {
  46. UINT32 familyIdx = device.getQueueFamily((GpuQueueType)i);
  47. if (familyIdx == (UINT32)-1)
  48. continue;
  49. VkCommandPoolCreateInfo poolCI;
  50. poolCI.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
  51. poolCI.pNext = nullptr;
  52. poolCI.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
  53. poolCI.queueFamilyIndex = familyIdx;
  54. PoolInfo& poolInfo = mPools[familyIdx];
  55. poolInfo.queueFamily = familyIdx;
  56. memset(poolInfo.buffers, 0, sizeof(poolInfo.buffers));
  57. vkCreateCommandPool(device.getLogical(), &poolCI, gVulkanAllocator, &poolInfo.pool);
  58. }
  59. }
  60. VulkanCmdBufferPool::~VulkanCmdBufferPool()
  61. {
  62. // Note: Shutdown should be the only place command buffers are destroyed at, as the system relies on the fact that
  63. // they won't be destroyed during normal operation.
  64. for(auto& entry : mPools)
  65. {
  66. PoolInfo& poolInfo = entry.second;
  67. for (UINT32 i = 0; i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY; i++)
  68. {
  69. VulkanCmdBuffer* buffer = poolInfo.buffers[i];
  70. if (buffer == nullptr)
  71. break;
  72. bs_delete(buffer);
  73. }
  74. vkDestroyCommandPool(mDevice.getLogical(), poolInfo.pool, gVulkanAllocator);
  75. }
  76. }
  77. VulkanCmdBuffer* VulkanCmdBufferPool::getBuffer(UINT32 queueFamily, bool secondary)
  78. {
  79. auto iterFind = mPools.find(queueFamily);
  80. if (iterFind == mPools.end())
  81. return nullptr;
  82. VulkanCmdBuffer** buffers = iterFind->second.buffers;
  83. UINT32 i = 0;
  84. for(; i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY; i++)
  85. {
  86. if (buffers[i] == nullptr)
  87. break;
  88. if(buffers[i]->mState == VulkanCmdBuffer::State::Ready)
  89. {
  90. buffers[i]->begin();
  91. return buffers[i];
  92. }
  93. }
  94. assert(i < BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY &&
  95. "Too many command buffers allocated. Increment BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY to a higher value. ");
  96. buffers[i] = createBuffer(queueFamily, secondary);
  97. buffers[i]->begin();
  98. return buffers[i];
  99. }
  100. VulkanCmdBuffer* VulkanCmdBufferPool::createBuffer(UINT32 queueFamily, bool secondary)
  101. {
  102. auto iterFind = mPools.find(queueFamily);
  103. if (iterFind == mPools.end())
  104. return nullptr;
  105. const PoolInfo& poolInfo = iterFind->second;
  106. return bs_new<VulkanCmdBuffer>(mDevice, mNextId++, poolInfo.pool, poolInfo.queueFamily, secondary);
  107. }
  108. /** Returns a set of pipeline stages that can are allowed to be used for the specified set of access flags. */
  109. VkPipelineStageFlags getPipelineStageFlags(VkAccessFlags accessFlags)
  110. {
  111. VkPipelineStageFlags flags = 0;
  112. if ((accessFlags & VK_ACCESS_INDIRECT_COMMAND_READ_BIT) != 0)
  113. flags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
  114. if ((accessFlags & (VK_ACCESS_INDEX_READ_BIT | VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT)) != 0)
  115. flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
  116. if ((accessFlags & (VK_ACCESS_UNIFORM_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT)) != 0)
  117. {
  118. flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT;
  119. flags |= VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT | VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
  120. flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
  121. }
  122. if ((accessFlags & VK_ACCESS_INPUT_ATTACHMENT_READ_BIT) != 0)
  123. flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
  124. if ((accessFlags & (VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT)) != 0)
  125. flags |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  126. if ((accessFlags & (VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT)) != 0)
  127. flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
  128. if ((accessFlags & (VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT)) != 0)
  129. flags |= VK_PIPELINE_STAGE_TRANSFER_BIT;
  130. if ((accessFlags & (VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT)) != 0)
  131. flags |= VK_PIPELINE_STAGE_HOST_BIT;
  132. if (flags == 0)
  133. flags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
  134. return flags;
  135. }
  136. template<class T>
  137. void getPipelineStageFlags(const Vector<T>& barriers, VkPipelineStageFlags& src, VkPipelineStageFlags& dst)
  138. {
  139. for(auto& entry : barriers)
  140. {
  141. src |= getPipelineStageFlags(entry.srcAccessMask);
  142. dst |= getPipelineStageFlags(entry.dstAccessMask);
  143. }
  144. if (src == 0)
  145. src = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
  146. if (dst == 0)
  147. dst = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
  148. }
  149. VulkanCmdBuffer::VulkanCmdBuffer(VulkanDevice& device, UINT32 id, VkCommandPool pool, UINT32 queueFamily, bool secondary)
  150. : mId(id), mQueueFamily(queueFamily), mState(State::Ready), mDevice(device), mPool(pool)
  151. , mIntraQueueSemaphore(nullptr), mInterQueueSemaphores(), mNumUsedInterQueueSemaphores(0)
  152. , mFramebuffer(nullptr), mRenderTargetWidth(0)
  153. , mRenderTargetHeight(0), mRenderTargetReadOnlyFlags(0), mRenderTargetLoadMask(RT_NONE), mGlobalQueueIdx(-1)
  154. , mViewport(0.0f, 0.0f, 1.0f, 1.0f), mScissor(0, 0, 0, 0), mStencilRef(0), mDrawOp(DOT_TRIANGLE_LIST)
  155. , mNumBoundDescriptorSets(0), mGfxPipelineRequiresBind(true), mCmpPipelineRequiresBind(true)
  156. , mViewportRequiresBind(true), mStencilRefRequiresBind(true), mScissorRequiresBind(true), mBoundParamsDirty(false)
  157. , mClearValues(), mClearMask(), mSemaphoresTemp(BS_MAX_UNIQUE_QUEUES), mVertexBuffersTemp()
  158. , mVertexBufferOffsetsTemp()
  159. {
  160. UINT32 maxBoundDescriptorSets = device.getDeviceProperties().limits.maxBoundDescriptorSets;
  161. mDescriptorSetsTemp = (VkDescriptorSet*)bs_alloc(sizeof(VkDescriptorSet) * maxBoundDescriptorSets);
  162. VkCommandBufferAllocateInfo cmdBufferAllocInfo;
  163. cmdBufferAllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
  164. cmdBufferAllocInfo.pNext = nullptr;
  165. cmdBufferAllocInfo.commandPool = pool;
  166. cmdBufferAllocInfo.level = secondary ? VK_COMMAND_BUFFER_LEVEL_SECONDARY : VK_COMMAND_BUFFER_LEVEL_PRIMARY;
  167. cmdBufferAllocInfo.commandBufferCount = 1;
  168. VkResult result = vkAllocateCommandBuffers(mDevice.getLogical(), &cmdBufferAllocInfo, &mCmdBuffer);
  169. assert(result == VK_SUCCESS);
  170. VkFenceCreateInfo fenceCI;
  171. fenceCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
  172. fenceCI.pNext = nullptr;
  173. fenceCI.flags = 0;
  174. result = vkCreateFence(mDevice.getLogical(), &fenceCI, gVulkanAllocator, &mFence);
  175. assert(result == VK_SUCCESS);
  176. }
  177. VulkanCmdBuffer::~VulkanCmdBuffer()
  178. {
  179. VkDevice device = mDevice.getLogical();
  180. if(mState == State::Submitted)
  181. {
  182. // Wait 1s
  183. UINT64 waitTime = 1000 * 1000 * 1000;
  184. VkResult result = vkWaitForFences(device, 1, &mFence, true, waitTime);
  185. assert(result == VK_SUCCESS || result == VK_TIMEOUT);
  186. if (result == VK_TIMEOUT)
  187. LOGWRN("Freeing a command buffer before done executing because fence wait expired!");
  188. // Resources have been marked as used, make sure to notify them we're done with them
  189. reset();
  190. }
  191. else if(mState != State::Ready)
  192. {
  193. // Notify any resources that they are no longer bound
  194. for (auto& entry : mResources)
  195. {
  196. ResourceUseHandle& useHandle = entry.second;
  197. assert(!useHandle.used);
  198. entry.first->notifyUnbound();
  199. }
  200. for (auto& entry : mImages)
  201. {
  202. UINT32 imageInfoIdx = entry.second;
  203. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  204. ResourceUseHandle& useHandle = imageInfo.useHandle;
  205. assert(!useHandle.used);
  206. entry.first->notifyUnbound();
  207. }
  208. for (auto& entry : mBuffers)
  209. {
  210. ResourceUseHandle& useHandle = entry.second.useHandle;
  211. assert(!useHandle.used);
  212. entry.first->notifyUnbound();
  213. }
  214. }
  215. if (mIntraQueueSemaphore != nullptr)
  216. mIntraQueueSemaphore->destroy();
  217. for(UINT32 i = 0; i < BS_MAX_VULKAN_CB_DEPENDENCIES; i++)
  218. {
  219. if (mInterQueueSemaphores[i] != nullptr)
  220. mInterQueueSemaphores[i]->destroy();
  221. }
  222. vkDestroyFence(device, mFence, gVulkanAllocator);
  223. vkFreeCommandBuffers(device, mPool, 1, &mCmdBuffer);
  224. bs_free(mDescriptorSetsTemp);
  225. }
  226. UINT32 VulkanCmdBuffer::getDeviceIdx() const
  227. {
  228. return mDevice.getIndex();
  229. }
  230. void VulkanCmdBuffer::begin()
  231. {
  232. assert(mState == State::Ready);
  233. VkCommandBufferBeginInfo beginInfo;
  234. beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  235. beginInfo.pNext = nullptr;
  236. beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  237. beginInfo.pInheritanceInfo = nullptr;
  238. VkResult result = vkBeginCommandBuffer(mCmdBuffer, &beginInfo);
  239. assert(result == VK_SUCCESS);
  240. mState = State::Recording;
  241. }
  242. void VulkanCmdBuffer::end()
  243. {
  244. assert(mState == State::Recording);
  245. // If a clear is queued, execute the render pass with no additional instructions
  246. if (mClearMask)
  247. executeClearPass();
  248. VkResult result = vkEndCommandBuffer(mCmdBuffer);
  249. assert(result == VK_SUCCESS);
  250. mState = State::RecordingDone;
  251. }
  252. void VulkanCmdBuffer::beginRenderPass()
  253. {
  254. assert(mState == State::Recording);
  255. if (mFramebuffer == nullptr)
  256. {
  257. LOGWRN("Attempting to begin a render pass but no render target is bound to the command buffer.");
  258. return;
  259. }
  260. if(mClearMask != CLEAR_NONE)
  261. {
  262. // If a previous clear is queued, but it doesn't match the rendered area, need to execute a separate pass
  263. // just for it
  264. Rect2I rtArea(0, 0, mRenderTargetWidth, mRenderTargetHeight);
  265. if (mClearArea != rtArea)
  266. executeClearPass();
  267. }
  268. executeLayoutTransitions();
  269. // Check if any frame-buffer attachments are also used as shader inputs, in which case we make them read-only
  270. RenderSurfaceMask readMask = RT_NONE;
  271. UINT32 numColorAttachments = mFramebuffer->getNumColorAttachments();
  272. for(UINT32 i = 0; i < numColorAttachments; i++)
  273. {
  274. const VulkanFramebufferAttachment& fbAttachment = mFramebuffer->getColorAttachment(i);
  275. ImageSubresourceInfo& subresourceInfo = findSubresourceInfo(fbAttachment.image, fbAttachment.surface.arraySlice,
  276. fbAttachment.surface.mipLevel);
  277. bool readOnly = subresourceInfo.isShaderInput;
  278. if(readOnly)
  279. readMask.set((RenderSurfaceMaskBits)(1 << i));
  280. }
  281. if (mFramebuffer->hasDepthAttachment())
  282. {
  283. const VulkanFramebufferAttachment& fbAttachment = mFramebuffer->getDepthStencilAttachment();
  284. ImageSubresourceInfo& subresourceInfo = findSubresourceInfo(fbAttachment.image, fbAttachment.surface.arraySlice,
  285. fbAttachment.surface.mipLevel);
  286. bool readOnly = subresourceInfo.isShaderInput;
  287. if (readOnly)
  288. readMask.set(RT_DEPTH);
  289. if ((mRenderTargetReadOnlyFlags & FBT_DEPTH) != 0)
  290. readMask.set(RT_DEPTH);
  291. if ((mRenderTargetReadOnlyFlags & FBT_STENCIL) != 0)
  292. readMask.set(RT_STENCIL);
  293. }
  294. VkRenderPassBeginInfo renderPassBeginInfo;
  295. renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  296. renderPassBeginInfo.pNext = nullptr;
  297. renderPassBeginInfo.framebuffer = mFramebuffer->getFramebuffer(mRenderTargetLoadMask, readMask, mClearMask);
  298. renderPassBeginInfo.renderPass = mFramebuffer->getRenderPass(mRenderTargetLoadMask, readMask, mClearMask);
  299. renderPassBeginInfo.renderArea.offset.x = 0;
  300. renderPassBeginInfo.renderArea.offset.y = 0;
  301. renderPassBeginInfo.renderArea.extent.width = mRenderTargetWidth;
  302. renderPassBeginInfo.renderArea.extent.height = mRenderTargetHeight;
  303. renderPassBeginInfo.clearValueCount = mFramebuffer->getNumClearEntries(mClearMask);
  304. renderPassBeginInfo.pClearValues = mClearValues.data();
  305. vkCmdBeginRenderPass(mCmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
  306. mClearMask = CLEAR_NONE;
  307. mState = State::RecordingRenderPass;
  308. }
  309. void VulkanCmdBuffer::endRenderPass()
  310. {
  311. assert(mState == State::RecordingRenderPass);
  312. vkCmdEndRenderPass(mCmdBuffer);
  313. // Execute any queued events
  314. for(auto& entry : mQueuedEvents)
  315. vkCmdSetEvent(mCmdBuffer, entry->getHandle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  316. mQueuedEvents.clear();
  317. // Update any layout transitions that were performed by subpass dependencies, reset flags that signal image usage
  318. // and reset read-only state.
  319. for(auto& entry : mPassTouchedSubresourceInfos)
  320. {
  321. ImageSubresourceInfo& subresourceInfo = mSubresourceInfoStorage[entry];
  322. subresourceInfo.isShaderInput = false;
  323. subresourceInfo.isReadOnly = true;
  324. subresourceInfo.needsBarrier = false;
  325. }
  326. for (auto& entry : mBuffers)
  327. entry.second.needsBarrier = false;
  328. mPassTouchedSubresourceInfos.clear();
  329. updateFinalLayouts();
  330. mState = State::Recording;
  331. // In case the same GPU params from last pass get used, this makes sure the states we reset above, get re-applied
  332. mBoundParamsDirty = true;
  333. }
  334. void VulkanCmdBuffer::allocateSemaphores(VkSemaphore* semaphores)
  335. {
  336. if (mIntraQueueSemaphore != nullptr)
  337. mIntraQueueSemaphore->destroy();
  338. mIntraQueueSemaphore = mDevice.getResourceManager().create<VulkanSemaphore>();
  339. semaphores[0] = mIntraQueueSemaphore->getHandle();
  340. for (UINT32 i = 0; i < BS_MAX_VULKAN_CB_DEPENDENCIES; i++)
  341. {
  342. if (mInterQueueSemaphores[i] != nullptr)
  343. mInterQueueSemaphores[i]->destroy();
  344. mInterQueueSemaphores[i] = mDevice.getResourceManager().create<VulkanSemaphore>();
  345. semaphores[i + 1] = mInterQueueSemaphores[i]->getHandle();
  346. }
  347. mNumUsedInterQueueSemaphores = 0;
  348. }
  349. VulkanSemaphore* VulkanCmdBuffer::requestInterQueueSemaphore() const
  350. {
  351. if (mNumUsedInterQueueSemaphores >= BS_MAX_VULKAN_CB_DEPENDENCIES)
  352. return nullptr;
  353. return mInterQueueSemaphores[mNumUsedInterQueueSemaphores++];
  354. }
  355. void VulkanCmdBuffer::submit(VulkanQueue* queue, UINT32 queueIdx, UINT32 syncMask)
  356. {
  357. assert(isReadyForSubmit());
  358. // Make sure to reset the CB fence before we submit it
  359. VkResult result = vkResetFences(mDevice.getLogical(), 1, &mFence);
  360. assert(result == VK_SUCCESS);
  361. // If there are any query resets needed, execute those first
  362. VulkanDevice& device = queue->getDevice();
  363. if(!mQueuedQueryResets.empty())
  364. {
  365. VulkanCmdBuffer* cmdBuffer = device.getCmdBufferPool().getBuffer(mQueueFamily, false);
  366. VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
  367. for (auto& entry : mQueuedQueryResets)
  368. entry->reset(vkCmdBuffer);
  369. cmdBuffer->end();
  370. queue->queueSubmit(cmdBuffer, nullptr, 0);
  371. mQueuedQueryResets.clear();
  372. }
  373. // Issue pipeline barriers for queue transitions (need to happen on original queue first, then on new queue)
  374. for (auto& entry : mBuffers)
  375. {
  376. VulkanBuffer* resource = static_cast<VulkanBuffer*>(entry.first);
  377. if (!resource->isExclusive())
  378. continue;
  379. UINT32 currentQueueFamily = resource->getQueueFamily();
  380. if (currentQueueFamily != -1 && currentQueueFamily != mQueueFamily)
  381. {
  382. Vector<VkBufferMemoryBarrier>& barriers = mTransitionInfoTemp[currentQueueFamily].bufferBarriers;
  383. barriers.push_back(VkBufferMemoryBarrier());
  384. VkBufferMemoryBarrier& barrier = barriers.back();
  385. barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
  386. barrier.pNext = nullptr;
  387. barrier.srcAccessMask = entry.second.accessFlags;
  388. barrier.dstAccessMask = entry.second.accessFlags;
  389. barrier.srcQueueFamilyIndex = currentQueueFamily;
  390. barrier.dstQueueFamilyIndex = mQueueFamily;
  391. barrier.buffer = resource->getHandle();
  392. barrier.offset = 0;
  393. barrier.size = VK_WHOLE_SIZE;
  394. }
  395. }
  396. // For images issue queue transitions, as above. Also issue layout transitions to their inital layouts.
  397. Vector<VkImageMemoryBarrier>& localBarriers = mTransitionInfoTemp[mQueueFamily].imageBarriers;
  398. for (auto& entry : mImages)
  399. {
  400. VulkanImage* resource = static_cast<VulkanImage*>(entry.first);
  401. ImageInfo& imageInfo = mImageInfos[entry.second];
  402. UINT32 currentQueueFamily = resource->getQueueFamily();
  403. bool queueMismatch = resource->isExclusive() && currentQueueFamily != -1 && currentQueueFamily != mQueueFamily;
  404. ImageSubresourceInfo* subresourceInfos = &mSubresourceInfoStorage[imageInfo.subresourceInfoIdx];
  405. if (queueMismatch)
  406. {
  407. Vector<VkImageMemoryBarrier>& barriers = mTransitionInfoTemp[currentQueueFamily].imageBarriers;
  408. for (UINT32 i = 0; i < imageInfo.numSubresourceInfos; i++)
  409. {
  410. ImageSubresourceInfo& subresourceInfo = subresourceInfos[i];
  411. UINT32 startIdx = (UINT32)barriers.size();
  412. resource->getBarriers(subresourceInfo.range, barriers);
  413. for(UINT32 j = startIdx; j < (UINT32)barriers.size(); j++)
  414. {
  415. VkImageMemoryBarrier& barrier = barriers[j];
  416. barrier.dstAccessMask = resource->getAccessFlags(barrier.oldLayout);
  417. barrier.newLayout = barrier.oldLayout;
  418. barrier.srcQueueFamilyIndex = currentQueueFamily;
  419. barrier.dstQueueFamilyIndex = mQueueFamily;
  420. }
  421. }
  422. }
  423. for (UINT32 i = 0; i < imageInfo.numSubresourceInfos; i++)
  424. {
  425. ImageSubresourceInfo& subresourceInfo = subresourceInfos[i];
  426. VkImageLayout initialLayout = subresourceInfo.initialLayout;
  427. if (initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
  428. continue;
  429. const VkImageSubresourceRange& range = subresourceInfo.range;
  430. UINT32 mipEnd = range.baseMipLevel + range.levelCount;
  431. UINT32 faceEnd = range.baseArrayLayer + range.layerCount;
  432. bool layoutMismatch = false;
  433. for (UINT32 mip = range.baseMipLevel; mip < mipEnd; mip++)
  434. {
  435. for (UINT32 face = range.baseArrayLayer; face < faceEnd; face++)
  436. {
  437. VulkanImageSubresource* subresource = resource->getSubresource(face, mip);
  438. if(subresource->getLayout() != initialLayout)
  439. {
  440. layoutMismatch = true;
  441. break;
  442. }
  443. }
  444. if (layoutMismatch)
  445. break;
  446. }
  447. if(layoutMismatch)
  448. {
  449. UINT32 startIdx = (UINT32)localBarriers.size();
  450. resource->getBarriers(subresourceInfo.range, localBarriers);
  451. for (UINT32 j = startIdx; j < (UINT32)localBarriers.size(); j++)
  452. {
  453. VkImageMemoryBarrier& barrier = localBarriers[j];
  454. barrier.dstAccessMask = resource->getAccessFlags(initialLayout, subresourceInfo.isInitialReadOnly);
  455. barrier.newLayout = initialLayout;
  456. }
  457. }
  458. for (UINT32 mip = range.baseMipLevel; mip < mipEnd; mip++)
  459. {
  460. for (UINT32 face = range.baseArrayLayer; face < faceEnd; face++)
  461. {
  462. VulkanImageSubresource* subresource = resource->getSubresource(face, mip);
  463. subresource->setLayout(subresourceInfo.finalLayout);
  464. }
  465. }
  466. }
  467. }
  468. for (auto& entry : mTransitionInfoTemp)
  469. {
  470. bool empty = entry.second.imageBarriers.size() == 0 && entry.second.bufferBarriers.size() == 0;
  471. if (empty)
  472. continue;
  473. UINT32 entryQueueFamily = entry.first;
  474. // No queue transition needed for entries on this queue (this entry is most likely an image layout transition)
  475. if (entryQueueFamily == -1 || entryQueueFamily == mQueueFamily)
  476. continue;
  477. VulkanCmdBuffer* cmdBuffer = device.getCmdBufferPool().getBuffer(entryQueueFamily, false);
  478. VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
  479. TransitionInfo& barriers = entry.second;
  480. UINT32 numImgBarriers = (UINT32)barriers.imageBarriers.size();
  481. UINT32 numBufferBarriers = (UINT32)barriers.bufferBarriers.size();
  482. VkPipelineStageFlags srcStage = 0;
  483. VkPipelineStageFlags dstStage = 0;
  484. getPipelineStageFlags(barriers.imageBarriers, srcStage, dstStage);
  485. vkCmdPipelineBarrier(vkCmdBuffer,
  486. srcStage, dstStage,
  487. 0, 0, nullptr,
  488. numBufferBarriers, barriers.bufferBarriers.data(),
  489. numImgBarriers, barriers.imageBarriers.data());
  490. // Find an appropriate queue to execute on
  491. UINT32 otherQueueIdx = 0;
  492. VulkanQueue* otherQueue = nullptr;
  493. GpuQueueType otherQueueType = GQT_GRAPHICS;
  494. for (UINT32 i = 0; i < GQT_COUNT; i++)
  495. {
  496. otherQueueType = (GpuQueueType)i;
  497. if (device.getQueueFamily(otherQueueType) != entryQueueFamily)
  498. continue;
  499. UINT32 numQueues = device.getNumQueues(otherQueueType);
  500. for (UINT32 j = 0; j < numQueues; j++)
  501. {
  502. // Try to find a queue not currently executing
  503. VulkanQueue* curQueue = device.getQueue(otherQueueType, j);
  504. if (!curQueue->isExecuting())
  505. {
  506. otherQueue = curQueue;
  507. otherQueueIdx = j;
  508. }
  509. }
  510. // Can't find empty one, use the first one then
  511. if (otherQueue == nullptr)
  512. {
  513. otherQueue = device.getQueue(otherQueueType, 0);
  514. otherQueueIdx = 0;
  515. }
  516. break;
  517. }
  518. syncMask |= CommandSyncMask::getGlobalQueueMask(otherQueueType, otherQueueIdx);
  519. cmdBuffer->end();
  520. // Note: If I switch back to doing layout transitions here, I need to wait on present semaphore
  521. otherQueue->submit(cmdBuffer, nullptr, 0);
  522. }
  523. UINT32 deviceIdx = device.getIndex();
  524. VulkanCommandBufferManager& cbm = static_cast<VulkanCommandBufferManager&>(CommandBufferManager::instance());
  525. UINT32 numSemaphores;
  526. cbm.getSyncSemaphores(deviceIdx, syncMask, mSemaphoresTemp.data(), numSemaphores);
  527. // Wait on present (i.e. until the back buffer becomes available) for any swap chains
  528. for(auto& entry : mSwapChains)
  529. {
  530. const SwapChainSurface& surface = entry->getBackBuffer();
  531. if (surface.needsWait)
  532. {
  533. VulkanSemaphore* semaphore = entry->getBackBuffer().sync;
  534. if (numSemaphores >= (UINT32)mSemaphoresTemp.size())
  535. mSemaphoresTemp.push_back(semaphore);
  536. else
  537. mSemaphoresTemp[numSemaphores] = semaphore;
  538. numSemaphores++;
  539. entry->notifyBackBufferWaitIssued();
  540. }
  541. }
  542. // Issue second part of transition pipeline barriers (on this queue)
  543. for (auto& entry : mTransitionInfoTemp)
  544. {
  545. bool empty = entry.second.imageBarriers.size() == 0 && entry.second.bufferBarriers.size() == 0;
  546. if (empty)
  547. continue;
  548. VulkanCmdBuffer* cmdBuffer = device.getCmdBufferPool().getBuffer(mQueueFamily, false);
  549. VkCommandBuffer vkCmdBuffer = cmdBuffer->getHandle();
  550. TransitionInfo& barriers = entry.second;
  551. UINT32 numImgBarriers = (UINT32)barriers.imageBarriers.size();
  552. UINT32 numBufferBarriers = (UINT32)barriers.bufferBarriers.size();
  553. VkPipelineStageFlags srcStage = 0;
  554. VkPipelineStageFlags dstStage = 0;
  555. getPipelineStageFlags(barriers.imageBarriers, srcStage, dstStage);
  556. vkCmdPipelineBarrier(vkCmdBuffer,
  557. srcStage, dstStage,
  558. 0, 0, nullptr,
  559. numBufferBarriers, barriers.bufferBarriers.data(),
  560. numImgBarriers, barriers.imageBarriers.data());
  561. cmdBuffer->end();
  562. queue->queueSubmit(cmdBuffer, mSemaphoresTemp.data(), numSemaphores);
  563. numSemaphores = 0; // Semaphores are only needed the first time, since we're adding the buffers on the same queue
  564. }
  565. queue->queueSubmit(this, mSemaphoresTemp.data(), numSemaphores);
  566. queue->submitQueued();
  567. mGlobalQueueIdx = CommandSyncMask::getGlobalQueueIdx(queue->getType(), queueIdx);
  568. for (auto& entry : mResources)
  569. {
  570. ResourceUseHandle& useHandle = entry.second;
  571. assert(!useHandle.used);
  572. useHandle.used = true;
  573. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  574. }
  575. for (auto& entry : mImages)
  576. {
  577. UINT32 imageInfoIdx = entry.second;
  578. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  579. ResourceUseHandle& useHandle = imageInfo.useHandle;
  580. assert(!useHandle.used);
  581. useHandle.used = true;
  582. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  583. }
  584. for (auto& entry : mBuffers)
  585. {
  586. ResourceUseHandle& useHandle = entry.second.useHandle;
  587. assert(!useHandle.used);
  588. useHandle.used = true;
  589. entry.first->notifyUsed(mGlobalQueueIdx, mQueueFamily, useHandle.flags);
  590. }
  591. // Note: Uncomment for debugging only, prevents any device concurrency issues.
  592. // vkQueueWaitIdle(queue->getHandle());
  593. // Clear vectors but don't clear the actual map, as we want to re-use the memory since we expect queue family
  594. // indices to be the same
  595. for (auto& entry : mTransitionInfoTemp)
  596. {
  597. entry.second.imageBarriers.clear();
  598. entry.second.bufferBarriers.clear();
  599. }
  600. mGraphicsPipeline = nullptr;
  601. mComputePipeline = nullptr;
  602. mGfxPipelineRequiresBind = true;
  603. mCmpPipelineRequiresBind = true;
  604. mFramebuffer = nullptr;
  605. mDescriptorSetsBindState = DescriptorSetBindFlag::Graphics | DescriptorSetBindFlag::Compute;
  606. mQueuedLayoutTransitions.clear();
  607. mBoundParams = nullptr;
  608. mSwapChains.clear();
  609. }
  610. bool VulkanCmdBuffer::checkFenceStatus(bool block) const
  611. {
  612. VkResult result = vkWaitForFences(mDevice.getLogical(), 1, &mFence, true, block ? 1'000'000'000 : 0);
  613. assert(result == VK_SUCCESS || result == VK_TIMEOUT);
  614. return result == VK_SUCCESS;
  615. }
  616. void VulkanCmdBuffer::reset()
  617. {
  618. bool wasSubmitted = mState == State::Submitted;
  619. mState = State::Ready;
  620. vkResetCommandBuffer(mCmdBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); // Note: Maybe better not to release resources?
  621. if (wasSubmitted)
  622. {
  623. for (auto& entry : mResources)
  624. {
  625. ResourceUseHandle& useHandle = entry.second;
  626. assert(useHandle.used);
  627. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  628. }
  629. for (auto& entry : mImages)
  630. {
  631. UINT32 imageInfoIdx = entry.second;
  632. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  633. ResourceUseHandle& useHandle = imageInfo.useHandle;
  634. assert(useHandle.used);
  635. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  636. }
  637. for (auto& entry : mBuffers)
  638. {
  639. ResourceUseHandle& useHandle = entry.second.useHandle;
  640. assert(useHandle.used);
  641. entry.first->notifyDone(mGlobalQueueIdx, useHandle.flags);
  642. }
  643. }
  644. else
  645. {
  646. for (auto& entry : mResources)
  647. entry.first->notifyUnbound();
  648. for (auto& entry : mImages)
  649. entry.first->notifyUnbound();
  650. for (auto& entry : mBuffers)
  651. entry.first->notifyUnbound();
  652. }
  653. mResources.clear();
  654. mImages.clear();
  655. mBuffers.clear();
  656. mOcclusionQueries.clear();
  657. mTimerQueries.clear();
  658. mImageInfos.clear();
  659. mSubresourceInfoStorage.clear();
  660. mPassTouchedSubresourceInfos.clear();
  661. }
  662. void VulkanCmdBuffer::setRenderTarget(const SPtr<RenderTarget>& rt, UINT32 readOnlyFlags,
  663. RenderSurfaceMask loadMask)
  664. {
  665. assert(mState != State::Submitted);
  666. VulkanFramebuffer* newFB;
  667. if(rt != nullptr)
  668. {
  669. if (rt->getProperties().isWindow())
  670. {
  671. Win32RenderWindow* window = static_cast<Win32RenderWindow*>(rt.get());
  672. window->acquireBackBuffer();
  673. VulkanSwapChain* swapChain;
  674. rt->getCustomAttribute("SC", &swapChain);
  675. mSwapChains.insert(swapChain);
  676. }
  677. rt->getCustomAttribute("FB", &newFB);
  678. }
  679. else
  680. {
  681. newFB = nullptr;
  682. }
  683. // Warn if invalid load mask
  684. if (loadMask.isSet(RT_DEPTH) && !loadMask.isSet(RT_STENCIL))
  685. {
  686. LOGWRN("setRenderTarget() invalid load mask, depth enabled but stencil disabled. This is not supported. Both \
  687. will be loaded.");
  688. loadMask.set(RT_STENCIL);
  689. }
  690. if (!loadMask.isSet(RT_DEPTH) && loadMask.isSet(RT_STENCIL))
  691. {
  692. LOGWRN("setRenderTarget() invalid load mask, stencil enabled but depth disabled. This is not supported. Both \
  693. will be loaded.");
  694. loadMask.set(RT_DEPTH);
  695. }
  696. if (mFramebuffer == newFB && mRenderTargetReadOnlyFlags == readOnlyFlags && mRenderTargetLoadMask == loadMask)
  697. return;
  698. if (isInRenderPass())
  699. endRenderPass();
  700. else
  701. {
  702. // If a clear is queued for previous FB, execute the render pass with no additional instructions
  703. if (mClearMask)
  704. executeClearPass();
  705. }
  706. // Reset isFBAttachment flags for subresources from the old framebuffer
  707. if(mFramebuffer != nullptr)
  708. {
  709. UINT32 numColorAttachments = mFramebuffer->getNumColorAttachments();
  710. for(UINT32 i = 0; i < numColorAttachments; i++)
  711. {
  712. const VulkanFramebufferAttachment& fbAttachment = mFramebuffer->getColorAttachment(i);
  713. UINT32 imageInfoIdx = mImages[fbAttachment.image];
  714. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  715. ImageSubresourceInfo* subresourceInfos = &mSubresourceInfoStorage[imageInfo.subresourceInfoIdx];
  716. for(UINT32 j = 0; j < imageInfo.numSubresourceInfos; j++)
  717. {
  718. ImageSubresourceInfo& entry = subresourceInfos[j];
  719. entry.isFBAttachment = false;
  720. }
  721. }
  722. if(mFramebuffer->hasDepthAttachment())
  723. {
  724. const VulkanFramebufferAttachment& fbAttachment = mFramebuffer->getDepthStencilAttachment();
  725. UINT32 imageInfoIdx = mImages[fbAttachment.image];
  726. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  727. ImageSubresourceInfo* subresourceInfos = &mSubresourceInfoStorage[imageInfo.subresourceInfoIdx];
  728. for(UINT32 j = 0; j < imageInfo.numSubresourceInfos; j++)
  729. {
  730. ImageSubresourceInfo& entry = subresourceInfos[j];
  731. entry.isFBAttachment = false;
  732. }
  733. }
  734. }
  735. if(newFB == nullptr)
  736. {
  737. mFramebuffer = nullptr;
  738. mRenderTargetWidth = 0;
  739. mRenderTargetHeight = 0;
  740. mRenderTargetReadOnlyFlags = 0;
  741. mRenderTargetLoadMask = RT_NONE;
  742. }
  743. else
  744. {
  745. mFramebuffer = newFB;
  746. mRenderTargetWidth = rt->getProperties().getWidth();
  747. mRenderTargetHeight = rt->getProperties().getHeight();
  748. mRenderTargetReadOnlyFlags = readOnlyFlags;
  749. mRenderTargetLoadMask = loadMask;
  750. }
  751. // Re-set the params as they will need to be re-bound
  752. setGpuParams(mBoundParams);
  753. if (mFramebuffer != nullptr)
  754. registerResource(mFramebuffer, loadMask, readOnlyFlags);
  755. mGfxPipelineRequiresBind = true;
  756. }
  757. void VulkanCmdBuffer::clearViewport(const Rect2I& area, UINT32 buffers, const Color& color, float depth, UINT16 stencil,
  758. UINT8 targetMask)
  759. {
  760. if (buffers == 0 || mFramebuffer == nullptr)
  761. return;
  762. // Add clear command if currently in render pass
  763. if (isInRenderPass())
  764. {
  765. VkClearAttachment attachments[BS_MAX_MULTIPLE_RENDER_TARGETS + 1];
  766. UINT32 baseLayer = 0;
  767. UINT32 attachmentIdx = 0;
  768. if ((buffers & FBT_COLOR) != 0)
  769. {
  770. UINT32 numColorAttachments = mFramebuffer->getNumColorAttachments();
  771. for (UINT32 i = 0; i < numColorAttachments; i++)
  772. {
  773. const VulkanFramebufferAttachment& attachment = mFramebuffer->getColorAttachment(i);
  774. if (((1 << attachment.index) & targetMask) == 0)
  775. continue;
  776. attachments[attachmentIdx].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  777. attachments[attachmentIdx].colorAttachment = i;
  778. VkClearColorValue& colorValue = attachments[attachmentIdx].clearValue.color;
  779. colorValue.float32[0] = color.r;
  780. colorValue.float32[1] = color.g;
  781. colorValue.float32[2] = color.b;
  782. colorValue.float32[3] = color.a;
  783. UINT32 curBaseLayer = attachment.baseLayer;
  784. if (attachmentIdx == 0)
  785. baseLayer = curBaseLayer;
  786. else
  787. {
  788. if (baseLayer != curBaseLayer)
  789. {
  790. // Note: This could be supported relatively easily: we would need to issue multiple separate
  791. // clear commands for such framebuffers.
  792. LOGERR("Attempting to clear a texture that has multiple multi-layer surfaces with mismatching "
  793. "starting layers. This is currently not supported.");
  794. }
  795. }
  796. attachmentIdx++;
  797. }
  798. }
  799. if ((buffers & FBT_DEPTH) != 0 || (buffers & FBT_STENCIL) != 0)
  800. {
  801. if (mFramebuffer->hasDepthAttachment())
  802. {
  803. attachments[attachmentIdx].aspectMask = 0;
  804. if ((buffers & FBT_DEPTH) != 0)
  805. {
  806. attachments[attachmentIdx].aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
  807. attachments[attachmentIdx].clearValue.depthStencil.depth = depth;
  808. }
  809. if ((buffers & FBT_STENCIL) != 0)
  810. {
  811. attachments[attachmentIdx].aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
  812. attachments[attachmentIdx].clearValue.depthStencil.stencil = stencil;
  813. }
  814. attachments[attachmentIdx].colorAttachment = 0;
  815. UINT32 curBaseLayer = mFramebuffer->getDepthStencilAttachment().baseLayer;
  816. if (attachmentIdx == 0)
  817. baseLayer = curBaseLayer;
  818. else
  819. {
  820. if (baseLayer != curBaseLayer)
  821. {
  822. // Note: This could be supported relatively easily: we would need to issue multiple separate
  823. // clear commands for such framebuffers.
  824. LOGERR("Attempting to clear a texture that has multiple multi-layer surfaces with mismatching "
  825. "starting layers. This is currently not supported.");
  826. }
  827. }
  828. attachmentIdx++;
  829. }
  830. }
  831. UINT32 numAttachments = attachmentIdx;
  832. if (numAttachments == 0)
  833. return;
  834. VkClearRect clearRect;
  835. clearRect.baseArrayLayer = baseLayer;
  836. clearRect.layerCount = mFramebuffer->getNumLayers();
  837. clearRect.rect.offset.x = area.x;
  838. clearRect.rect.offset.y = area.y;
  839. clearRect.rect.extent.width = area.width;
  840. clearRect.rect.extent.height = area.height;
  841. vkCmdClearAttachments(mCmdBuffer, numAttachments, attachments, 1, &clearRect);
  842. }
  843. // Otherwise we use a render pass that performs a clear on begin
  844. else
  845. {
  846. ClearMask clearMask;
  847. std::array<VkClearValue, BS_MAX_MULTIPLE_RENDER_TARGETS + 1> clearValues = mClearValues;
  848. UINT32 numColorAttachments = mFramebuffer->getNumColorAttachments();
  849. if ((buffers & FBT_COLOR) != 0)
  850. {
  851. for (UINT32 i = 0; i < numColorAttachments; i++)
  852. {
  853. const VulkanFramebufferAttachment& attachment = mFramebuffer->getColorAttachment(i);
  854. if (((1 << attachment.index) & targetMask) == 0)
  855. continue;
  856. clearMask |= (ClearMaskBits)(1 << attachment.index);
  857. VkClearColorValue& colorValue = clearValues[i].color;
  858. colorValue.float32[0] = color.r;
  859. colorValue.float32[1] = color.g;
  860. colorValue.float32[2] = color.b;
  861. colorValue.float32[3] = color.a;
  862. }
  863. }
  864. if ((buffers & FBT_DEPTH) != 0 || (buffers & FBT_STENCIL) != 0)
  865. {
  866. if (mFramebuffer->hasDepthAttachment())
  867. {
  868. UINT32 depthAttachmentIdx = numColorAttachments;
  869. if ((buffers & FBT_DEPTH) != 0)
  870. {
  871. clearValues[depthAttachmentIdx].depthStencil.depth = depth;
  872. clearMask |= CLEAR_DEPTH;
  873. }
  874. if ((buffers & FBT_STENCIL) != 0)
  875. {
  876. clearValues[depthAttachmentIdx].depthStencil.stencil = stencil;
  877. clearMask |= CLEAR_STENCIL;
  878. }
  879. }
  880. }
  881. if (!clearMask)
  882. return;
  883. // Some previous clear operation is already queued, execute it first
  884. bool previousClearNeedsToFinish = (mClearMask & clearMask) != CLEAR_NONE;
  885. if(previousClearNeedsToFinish)
  886. executeClearPass();
  887. mClearMask |= clearMask;
  888. mClearValues = clearValues;
  889. mClearArea = area;
  890. }
  891. }
  892. void VulkanCmdBuffer::clearRenderTarget(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask)
  893. {
  894. Rect2I area(0, 0, mRenderTargetWidth, mRenderTargetHeight);
  895. clearViewport(area, buffers, color, depth, stencil, targetMask);
  896. }
  897. void VulkanCmdBuffer::clearViewport(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask)
  898. {
  899. Rect2I area;
  900. area.x = (UINT32)(mViewport.x * mRenderTargetWidth);
  901. area.y = (UINT32)(mViewport.y * mRenderTargetHeight);
  902. area.width = (UINT32)(mViewport.width * mRenderTargetWidth);
  903. area.height = (UINT32)(mViewport.height * mRenderTargetHeight);
  904. clearViewport(area, buffers, color, depth, stencil, targetMask);
  905. }
  906. void VulkanCmdBuffer::setPipelineState(const SPtr<GraphicsPipelineState>& state)
  907. {
  908. if (mGraphicsPipeline == state)
  909. return;
  910. mGraphicsPipeline = std::static_pointer_cast<VulkanGraphicsPipelineState>(state);
  911. mGfxPipelineRequiresBind = true;
  912. }
  913. void VulkanCmdBuffer::setPipelineState(const SPtr<ComputePipelineState>& state)
  914. {
  915. if (mComputePipeline == state)
  916. return;
  917. mComputePipeline = std::static_pointer_cast<VulkanComputePipelineState>(state);
  918. mCmpPipelineRequiresBind = true;
  919. }
  920. void VulkanCmdBuffer::setGpuParams(const SPtr<GpuParams>& gpuParams)
  921. {
  922. // Note: We keep an internal reference to GPU params even though we shouldn't keep a reference to a core thread
  923. // object. But it should be fine since we expect the resource to be externally synchronized so it should never
  924. // be allowed to go out of scope on a non-core thread anyway.
  925. mBoundParams = std::static_pointer_cast<VulkanGpuParams>(gpuParams);
  926. if (mBoundParams != nullptr)
  927. mBoundParamsDirty = true;
  928. else
  929. {
  930. mNumBoundDescriptorSets = 0;
  931. mBoundParamsDirty = false;
  932. }
  933. mDescriptorSetsBindState = DescriptorSetBindFlag::Graphics | DescriptorSetBindFlag::Compute;
  934. }
  935. void VulkanCmdBuffer::setViewport(const Rect2& area)
  936. {
  937. if (mViewport == area)
  938. return;
  939. mViewport = area;
  940. mViewportRequiresBind = true;
  941. }
  942. void VulkanCmdBuffer::setScissorRect(const Rect2I& value)
  943. {
  944. if (mScissor == value)
  945. return;
  946. mScissor = value;
  947. mScissorRequiresBind = true;
  948. }
  949. void VulkanCmdBuffer::setStencilRef(UINT32 value)
  950. {
  951. if (mStencilRef == value)
  952. return;
  953. mStencilRef = value;
  954. mStencilRefRequiresBind = true;
  955. }
  956. void VulkanCmdBuffer::setDrawOp(DrawOperationType drawOp)
  957. {
  958. if (mDrawOp == drawOp)
  959. return;
  960. mDrawOp = drawOp;
  961. mGfxPipelineRequiresBind = true;
  962. }
  963. void VulkanCmdBuffer::setVertexBuffers(UINT32 index, SPtr<VertexBuffer>* buffers, UINT32 numBuffers)
  964. {
  965. if (numBuffers == 0)
  966. return;
  967. for(UINT32 i = 0; i < numBuffers; i++)
  968. {
  969. VulkanVertexBuffer* vertexBuffer = static_cast<VulkanVertexBuffer*>(buffers[i].get());
  970. if (vertexBuffer != nullptr)
  971. {
  972. VulkanBuffer* resource = vertexBuffer->getResource(mDevice.getIndex());
  973. if (resource != nullptr)
  974. {
  975. mVertexBuffersTemp[i] = resource->getHandle();
  976. registerResource(resource, VulkanUseFlag::Read);
  977. }
  978. else
  979. mVertexBuffersTemp[i] = VK_NULL_HANDLE;
  980. }
  981. else
  982. mVertexBuffersTemp[i] = VK_NULL_HANDLE;
  983. }
  984. vkCmdBindVertexBuffers(mCmdBuffer, index, numBuffers, mVertexBuffersTemp, mVertexBufferOffsetsTemp);
  985. }
  986. void VulkanCmdBuffer::setIndexBuffer(const SPtr<IndexBuffer>& buffer)
  987. {
  988. VulkanIndexBuffer* indexBuffer = static_cast<VulkanIndexBuffer*>(buffer.get());
  989. VkBuffer vkBuffer = VK_NULL_HANDLE;
  990. VkIndexType indexType = VK_INDEX_TYPE_UINT32;
  991. if (indexBuffer != nullptr)
  992. {
  993. VulkanBuffer* resource = indexBuffer->getResource(mDevice.getIndex());
  994. if (resource != nullptr)
  995. {
  996. vkBuffer = resource->getHandle();
  997. indexType = VulkanUtility::getIndexType(buffer->getProperties().getType());
  998. registerResource(resource, VulkanUseFlag::Read);
  999. }
  1000. }
  1001. vkCmdBindIndexBuffer(mCmdBuffer, vkBuffer, 0, indexType);
  1002. }
  1003. void VulkanCmdBuffer::setVertexDeclaration(const SPtr<VertexDeclaration>& decl)
  1004. {
  1005. if (mVertexDecl == decl)
  1006. return;
  1007. mVertexDecl = decl;
  1008. mGfxPipelineRequiresBind = true;
  1009. }
  1010. bool VulkanCmdBuffer::isReadyForRender()
  1011. {
  1012. if (mGraphicsPipeline == nullptr)
  1013. return false;
  1014. SPtr<VertexDeclaration> inputDecl = mGraphicsPipeline->getInputDeclaration();
  1015. if (inputDecl == nullptr)
  1016. return false;
  1017. return mFramebuffer != nullptr && mVertexDecl != nullptr;
  1018. }
  1019. bool VulkanCmdBuffer::bindGraphicsPipeline()
  1020. {
  1021. SPtr<VertexDeclaration> inputDecl = mGraphicsPipeline->getInputDeclaration();
  1022. SPtr<VulkanVertexInput> vertexInput = VulkanVertexInputManager::instance().getVertexInfo(mVertexDecl, inputDecl);
  1023. VulkanPipeline* pipeline = mGraphicsPipeline->getPipeline(mDevice.getIndex(), mFramebuffer,
  1024. mRenderTargetReadOnlyFlags, mDrawOp, vertexInput);
  1025. if (pipeline == nullptr)
  1026. return false;
  1027. // Check that pipeline matches the read-only state of any framebuffer attachments
  1028. UINT32 numColorAttachments = mFramebuffer->getNumColorAttachments();
  1029. for (UINT32 i = 0; i < numColorAttachments; i++)
  1030. {
  1031. const VulkanFramebufferAttachment& fbAttachment = mFramebuffer->getColorAttachment(i);
  1032. ImageSubresourceInfo& subresourceInfo = findSubresourceInfo(fbAttachment.image, fbAttachment.surface.arraySlice,
  1033. fbAttachment.surface.mipLevel);
  1034. if (subresourceInfo.isShaderInput && !pipeline->isColorReadOnly(i))
  1035. {
  1036. LOGWRN("Framebuffer attachment also used as a shader input, but color writes aren't disabled. This will"
  1037. " result in undefined behavior.");
  1038. }
  1039. }
  1040. if (mFramebuffer->hasDepthAttachment())
  1041. {
  1042. const VulkanFramebufferAttachment& fbAttachment = mFramebuffer->getDepthStencilAttachment();
  1043. ImageSubresourceInfo& subresourceInfo = findSubresourceInfo(fbAttachment.image, fbAttachment.surface.arraySlice,
  1044. fbAttachment.surface.mipLevel);
  1045. if (subresourceInfo.isShaderInput && !pipeline->isDepthReadOnly())
  1046. {
  1047. LOGWRN("Framebuffer attachment also used as a shader input, but depth/stencil writes aren't disabled. "
  1048. "This will result in undefined behavior.");
  1049. }
  1050. }
  1051. mGraphicsPipeline->registerPipelineResources(this);
  1052. registerResource(pipeline, VulkanUseFlag::Read);
  1053. vkCmdBindPipeline(mCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->getHandle());
  1054. bindDynamicStates(true);
  1055. mGfxPipelineRequiresBind = false;
  1056. return true;
  1057. }
  1058. void VulkanCmdBuffer::bindDynamicStates(bool forceAll)
  1059. {
  1060. if (mViewportRequiresBind || forceAll)
  1061. {
  1062. VkViewport viewport;
  1063. viewport.x = mViewport.x * mRenderTargetWidth;
  1064. viewport.y = mViewport.y * mRenderTargetHeight;
  1065. viewport.width = mViewport.width * mRenderTargetWidth;
  1066. viewport.height = mViewport.height * mRenderTargetHeight;
  1067. viewport.minDepth = 0.0f;
  1068. viewport.maxDepth = 1.0f;
  1069. vkCmdSetViewport(mCmdBuffer, 0, 1, &viewport);
  1070. mViewportRequiresBind = false;
  1071. }
  1072. if(mStencilRefRequiresBind || forceAll)
  1073. {
  1074. vkCmdSetStencilReference(mCmdBuffer, VK_STENCIL_FRONT_AND_BACK, mStencilRef);
  1075. mStencilRefRequiresBind = false;
  1076. }
  1077. if(mScissorRequiresBind || forceAll)
  1078. {
  1079. VkRect2D scissorRect;
  1080. if(mGraphicsPipeline->isScissorEnabled())
  1081. {
  1082. scissorRect.offset.x = mScissor.x;
  1083. scissorRect.offset.y = mScissor.y;
  1084. scissorRect.extent.width = mScissor.width;
  1085. scissorRect.extent.height = mScissor.height;
  1086. }
  1087. else
  1088. {
  1089. scissorRect.offset.x = 0;
  1090. scissorRect.offset.y = 0;
  1091. scissorRect.extent.width = mRenderTargetWidth;
  1092. scissorRect.extent.height = mRenderTargetHeight;
  1093. }
  1094. vkCmdSetScissor(mCmdBuffer, 0, 1, &scissorRect);
  1095. mScissorRequiresBind = false;
  1096. }
  1097. }
  1098. void VulkanCmdBuffer::bindGpuParams()
  1099. {
  1100. if (mBoundParamsDirty)
  1101. {
  1102. if (mBoundParams != nullptr)
  1103. {
  1104. mNumBoundDescriptorSets = mBoundParams->getNumSets();
  1105. mBoundParams->prepareForBind(*this, mDescriptorSetsTemp);
  1106. }
  1107. else
  1108. mNumBoundDescriptorSets = 0;
  1109. mBoundParamsDirty = false;
  1110. }
  1111. else
  1112. {
  1113. mNumBoundDescriptorSets = 0;
  1114. }
  1115. }
  1116. void VulkanCmdBuffer::executeLayoutTransitions()
  1117. {
  1118. auto createLayoutTransitionBarrier = [&](VulkanImage* image, ImageInfo& imageInfo)
  1119. {
  1120. ImageSubresourceInfo* subresourceInfos = &mSubresourceInfoStorage[imageInfo.subresourceInfoIdx];
  1121. for (UINT32 i = 0; i < imageInfo.numSubresourceInfos; i++)
  1122. {
  1123. ImageSubresourceInfo& subresourceInfo = subresourceInfos[i];
  1124. if (!subresourceInfo.hasTransitioned || subresourceInfo.currentLayout == subresourceInfo.requiredLayout)
  1125. continue;
  1126. mLayoutTransitionBarriersTemp.push_back(VkImageMemoryBarrier());
  1127. VkImageMemoryBarrier& barrier = mLayoutTransitionBarriersTemp.back();
  1128. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  1129. barrier.pNext = nullptr;
  1130. barrier.srcAccessMask = image->getAccessFlags(subresourceInfo.currentLayout);
  1131. barrier.dstAccessMask = image->getAccessFlags(subresourceInfo.requiredLayout, subresourceInfo.isReadOnly);
  1132. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  1133. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  1134. barrier.oldLayout = subresourceInfo.currentLayout;
  1135. barrier.newLayout = subresourceInfo.requiredLayout;
  1136. barrier.image = image->getHandle();
  1137. barrier.subresourceRange = subresourceInfo.range;
  1138. subresourceInfo.currentLayout = subresourceInfo.requiredLayout;
  1139. subresourceInfo.isReadOnly = true;
  1140. subresourceInfo.hasTransitioned = true;
  1141. }
  1142. };
  1143. // Note: These layout transitions will contain transitions for offscreen framebuffer attachments (while they
  1144. // transition to shader read-only layout). This can be avoided, since they're immediately used by the render pass
  1145. // as color attachments, making the layout change redundant.
  1146. for (auto& entry : mQueuedLayoutTransitions)
  1147. {
  1148. UINT32 imageInfoIdx = entry.second;
  1149. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  1150. createLayoutTransitionBarrier(entry.first, imageInfo);
  1151. }
  1152. VkPipelineStageFlags srcStage = 0;
  1153. VkPipelineStageFlags dstStage = 0;
  1154. getPipelineStageFlags(mLayoutTransitionBarriersTemp, srcStage, dstStage);
  1155. vkCmdPipelineBarrier(mCmdBuffer,
  1156. srcStage, dstStage,
  1157. 0, 0, nullptr,
  1158. 0, nullptr,
  1159. (UINT32)mLayoutTransitionBarriersTemp.size(), mLayoutTransitionBarriersTemp.data());
  1160. mQueuedLayoutTransitions.clear();
  1161. mLayoutTransitionBarriersTemp.clear();
  1162. }
  1163. void VulkanCmdBuffer::updateFinalLayouts()
  1164. {
  1165. if (mFramebuffer == nullptr)
  1166. return;
  1167. UINT32 numColorAttachments = mFramebuffer->getNumColorAttachments();
  1168. for (UINT32 i = 0; i < numColorAttachments; i++)
  1169. {
  1170. const VulkanFramebufferAttachment& fbAttachment = mFramebuffer->getColorAttachment(i);
  1171. ImageSubresourceInfo& subresourceInfo = findSubresourceInfo(fbAttachment.image, fbAttachment.surface.arraySlice,
  1172. fbAttachment.surface.mipLevel);
  1173. subresourceInfo.currentLayout = subresourceInfo.finalLayout;
  1174. subresourceInfo.requiredLayout = subresourceInfo.finalLayout;
  1175. subresourceInfo.hasTransitioned = true;
  1176. }
  1177. if (mFramebuffer->hasDepthAttachment())
  1178. {
  1179. const VulkanFramebufferAttachment& fbAttachment = mFramebuffer->getDepthStencilAttachment();
  1180. ImageSubresourceInfo& subresourceInfo = findSubresourceInfo(fbAttachment.image, fbAttachment.surface.arraySlice,
  1181. fbAttachment.surface.mipLevel);
  1182. subresourceInfo.currentLayout = subresourceInfo.finalLayout;
  1183. subresourceInfo.requiredLayout = subresourceInfo.finalLayout;
  1184. subresourceInfo.hasTransitioned = true;
  1185. }
  1186. }
  1187. void VulkanCmdBuffer::executeClearPass()
  1188. {
  1189. assert(mState == State::Recording);
  1190. executeLayoutTransitions();
  1191. VkRenderPassBeginInfo renderPassBeginInfo;
  1192. renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  1193. renderPassBeginInfo.pNext = nullptr;
  1194. renderPassBeginInfo.framebuffer = mFramebuffer->getFramebuffer(RT_NONE, RT_NONE, mClearMask);
  1195. renderPassBeginInfo.renderPass = mFramebuffer->getRenderPass(RT_NONE, RT_NONE, mClearMask);
  1196. renderPassBeginInfo.renderArea.offset.x = mClearArea.x;
  1197. renderPassBeginInfo.renderArea.offset.y = mClearArea.y;
  1198. renderPassBeginInfo.renderArea.extent.width = mClearArea.width;
  1199. renderPassBeginInfo.renderArea.extent.height = mClearArea.height;
  1200. renderPassBeginInfo.clearValueCount = mFramebuffer->getNumClearEntries(mClearMask);
  1201. renderPassBeginInfo.pClearValues = mClearValues.data();
  1202. vkCmdBeginRenderPass(mCmdBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);
  1203. vkCmdEndRenderPass(mCmdBuffer);
  1204. updateFinalLayouts();
  1205. mClearMask = CLEAR_NONE;
  1206. }
  1207. void VulkanCmdBuffer::draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount)
  1208. {
  1209. if (!isReadyForRender())
  1210. return;
  1211. // Need to bind gpu params before starting render pass, in order to make sure any layout transitions execute
  1212. bindGpuParams();
  1213. if (!isInRenderPass())
  1214. beginRenderPass();
  1215. if (mGfxPipelineRequiresBind)
  1216. {
  1217. if (!bindGraphicsPipeline())
  1218. return;
  1219. }
  1220. else
  1221. bindDynamicStates(false);
  1222. if (mDescriptorSetsBindState.isSet(DescriptorSetBindFlag::Graphics))
  1223. {
  1224. if (mNumBoundDescriptorSets > 0)
  1225. {
  1226. UINT32 deviceIdx = mDevice.getIndex();
  1227. VkPipelineLayout pipelineLayout = mGraphicsPipeline->getPipelineLayout(deviceIdx);
  1228. vkCmdBindDescriptorSets(mCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0,
  1229. mNumBoundDescriptorSets, mDescriptorSetsTemp, 0, nullptr);
  1230. }
  1231. mDescriptorSetsBindState.unset(DescriptorSetBindFlag::Graphics);
  1232. }
  1233. if (instanceCount <= 0)
  1234. instanceCount = 1;
  1235. vkCmdDraw(mCmdBuffer, vertexCount, instanceCount, vertexOffset, 0);
  1236. }
  1237. void VulkanCmdBuffer::drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 instanceCount)
  1238. {
  1239. if (!isReadyForRender())
  1240. return;
  1241. // Need to bind gpu params before starting render pass, in order to make sure any layout transitions execute
  1242. bindGpuParams();
  1243. if (!isInRenderPass())
  1244. beginRenderPass();
  1245. if (mGfxPipelineRequiresBind)
  1246. {
  1247. if (!bindGraphicsPipeline())
  1248. return;
  1249. }
  1250. else
  1251. bindDynamicStates(false);
  1252. if (mDescriptorSetsBindState.isSet(DescriptorSetBindFlag::Graphics))
  1253. {
  1254. if (mNumBoundDescriptorSets > 0)
  1255. {
  1256. UINT32 deviceIdx = mDevice.getIndex();
  1257. VkPipelineLayout pipelineLayout = mGraphicsPipeline->getPipelineLayout(deviceIdx);
  1258. vkCmdBindDescriptorSets(mCmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0,
  1259. mNumBoundDescriptorSets, mDescriptorSetsTemp, 0, nullptr);
  1260. }
  1261. mDescriptorSetsBindState.unset(DescriptorSetBindFlag::Graphics);
  1262. }
  1263. if (instanceCount <= 0)
  1264. instanceCount = 1;
  1265. vkCmdDrawIndexed(mCmdBuffer, indexCount, instanceCount, startIndex, vertexOffset, 0);
  1266. }
  1267. void VulkanCmdBuffer::dispatch(UINT32 numGroupsX, UINT32 numGroupsY, UINT32 numGroupsZ)
  1268. {
  1269. if (mComputePipeline == nullptr)
  1270. return;
  1271. if (isInRenderPass())
  1272. endRenderPass();
  1273. // Note: Should I restore the render target after? Note that this is only being done is framebuffer subresources
  1274. // have their "isFBAttachment" flag reset, potentially I can just clear/restore those
  1275. setRenderTarget(nullptr, 0, RT_ALL);
  1276. // Need to bind gpu params before starting render pass, in order to make sure any layout transitions execute
  1277. bindGpuParams();
  1278. executeLayoutTransitions();
  1279. UINT32 deviceIdx = mDevice.getIndex();
  1280. if(mCmpPipelineRequiresBind)
  1281. {
  1282. VulkanPipeline* pipeline = mComputePipeline->getPipeline(deviceIdx);
  1283. if (pipeline == nullptr)
  1284. return;
  1285. registerResource(pipeline, VulkanUseFlag::Read);
  1286. mComputePipeline->registerPipelineResources(this);
  1287. vkCmdBindPipeline(mCmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipeline->getHandle());
  1288. mCmpPipelineRequiresBind = false;
  1289. }
  1290. if(mDescriptorSetsBindState.isSet(DescriptorSetBindFlag::Compute))
  1291. {
  1292. if (mNumBoundDescriptorSets > 0)
  1293. {
  1294. VkPipelineLayout pipelineLayout = mComputePipeline->getPipelineLayout(deviceIdx);
  1295. vkCmdBindDescriptorSets(mCmdBuffer, VK_PIPELINE_BIND_POINT_COMPUTE, pipelineLayout, 0,
  1296. mNumBoundDescriptorSets, mDescriptorSetsTemp, 0, nullptr);
  1297. }
  1298. mDescriptorSetsBindState.unset(DescriptorSetBindFlag::Compute);
  1299. }
  1300. vkCmdDispatch(mCmdBuffer, numGroupsX, numGroupsY, numGroupsZ);
  1301. // Update any layout transitions that were performed by subpass dependencies, reset flags that signal image usage
  1302. // and reset read-only state.
  1303. for(auto& entry : mPassTouchedSubresourceInfos)
  1304. {
  1305. ImageSubresourceInfo& subresourceInfo = mSubresourceInfoStorage[entry];
  1306. subresourceInfo.isShaderInput = false;
  1307. subresourceInfo.isReadOnly = true;
  1308. subresourceInfo.needsBarrier = false;
  1309. }
  1310. for (auto& entry : mBuffers)
  1311. entry.second.needsBarrier = false;
  1312. mPassTouchedSubresourceInfos.clear();
  1313. }
  1314. void VulkanCmdBuffer::setEvent(VulkanEvent* event)
  1315. {
  1316. if(isInRenderPass())
  1317. mQueuedEvents.push_back(event);
  1318. else
  1319. vkCmdSetEvent(mCmdBuffer, event->getHandle(), VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  1320. }
  1321. void VulkanCmdBuffer::resetQuery(VulkanQuery* query)
  1322. {
  1323. if (isInRenderPass())
  1324. mQueuedQueryResets.push_back(query);
  1325. else
  1326. query->reset(mCmdBuffer);
  1327. }
  1328. void VulkanCmdBuffer::memoryBarrier(VkBuffer buffer, VkAccessFlags srcAccessFlags, VkAccessFlags dstAccessFlags,
  1329. VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage)
  1330. {
  1331. VkBufferMemoryBarrier barrier;
  1332. barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
  1333. barrier.pNext = nullptr;
  1334. barrier.srcAccessMask = srcAccessFlags;
  1335. barrier.dstAccessMask = dstAccessFlags;
  1336. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  1337. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  1338. barrier.buffer = buffer;
  1339. barrier.offset = 0;
  1340. barrier.size = VK_WHOLE_SIZE;
  1341. vkCmdPipelineBarrier(getHandle(),
  1342. srcStage,
  1343. dstStage,
  1344. 0, 0, nullptr,
  1345. 1, &barrier,
  1346. 0, nullptr);
  1347. }
  1348. void VulkanCmdBuffer::memoryBarrier(VkImage image, VkAccessFlags srcAccessFlags, VkAccessFlags dstAccessFlags,
  1349. VkPipelineStageFlags srcStage, VkPipelineStageFlags dstStage, VkImageLayout layout,
  1350. const VkImageSubresourceRange& range)
  1351. {
  1352. VkImageMemoryBarrier barrier;
  1353. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  1354. barrier.pNext = nullptr;
  1355. barrier.srcAccessMask = srcAccessFlags;
  1356. barrier.dstAccessMask = dstAccessFlags;
  1357. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  1358. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  1359. barrier.image = image;
  1360. barrier.subresourceRange = range;
  1361. barrier.oldLayout = layout;
  1362. barrier.newLayout = layout;
  1363. vkCmdPipelineBarrier(getHandle(),
  1364. srcStage,
  1365. dstStage,
  1366. 0, 0, nullptr,
  1367. 0, nullptr,
  1368. 1, &barrier);
  1369. }
  1370. void VulkanCmdBuffer::setLayout(VkImage image, VkAccessFlags srcAccessFlags, VkAccessFlags dstAccessFlags,
  1371. VkImageLayout oldLayout, VkImageLayout newLayout, const VkImageSubresourceRange& range)
  1372. {
  1373. VkImageMemoryBarrier barrier;
  1374. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  1375. barrier.pNext = nullptr;
  1376. barrier.srcAccessMask = srcAccessFlags;
  1377. barrier.dstAccessMask = dstAccessFlags;
  1378. barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  1379. barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  1380. barrier.oldLayout = oldLayout;
  1381. barrier.newLayout = newLayout;
  1382. barrier.image = image;
  1383. barrier.subresourceRange = range;
  1384. VkPipelineStageFlags srcStage = getPipelineStageFlags(srcAccessFlags);
  1385. VkPipelineStageFlags dstStage = getPipelineStageFlags(dstAccessFlags);
  1386. vkCmdPipelineBarrier(getHandle(),
  1387. srcStage,
  1388. dstStage,
  1389. 0, 0, nullptr,
  1390. 0, nullptr,
  1391. 1, &barrier);
  1392. }
  1393. void VulkanCmdBuffer::registerResource(VulkanResource* res, VulkanUseFlags flags)
  1394. {
  1395. auto insertResult = mResources.insert(std::make_pair(res, ResourceUseHandle()));
  1396. if(insertResult.second) // New element
  1397. {
  1398. ResourceUseHandle& useHandle = insertResult.first->second;
  1399. useHandle.used = false;
  1400. useHandle.flags = flags;
  1401. res->notifyBound();
  1402. }
  1403. else // Existing element
  1404. {
  1405. ResourceUseHandle& useHandle = insertResult.first->second;
  1406. assert(!useHandle.used);
  1407. useHandle.flags |= flags;
  1408. }
  1409. }
  1410. void VulkanCmdBuffer::registerResource(VulkanImage* res, const VkImageSubresourceRange& range, VulkanUseFlags flags,
  1411. ResourceUsage usage)
  1412. {
  1413. VkImageLayout layout = res->getOptimalLayout();
  1414. registerResource(res, range, layout, layout, flags, usage);
  1415. }
  1416. void VulkanCmdBuffer::registerResource(VulkanImage* res, const VkImageSubresourceRange& range, VkImageLayout newLayout,
  1417. VkImageLayout finalLayout, VulkanUseFlags flags, ResourceUsage usage)
  1418. {
  1419. bool isFBAttachment = usage == ResourceUsage::Framebuffer;
  1420. bool isTransfer = usage == ResourceUsage::Transfer;
  1421. bool isShaderBind = usage == ResourceUsage::ShaderBind;
  1422. // If binding it for write in a shader (not as color attachment or transfer op), we will need to issue a memory
  1423. // barrier if the image gets used again during this render pass, so remember this information.
  1424. bool needsBarrier = isShaderBind && flags.isSet(VulkanUseFlag::Write);
  1425. UINT32 nextImageInfoIdx = (UINT32)mImageInfos.size();
  1426. auto registerSubresourceInfo = [&](const VkImageSubresourceRange& subresourceRange)
  1427. {
  1428. mSubresourceInfoStorage.push_back(ImageSubresourceInfo());
  1429. ImageSubresourceInfo& subresourceInfo = mSubresourceInfoStorage.back();
  1430. subresourceInfo.currentLayout = newLayout;
  1431. subresourceInfo.initialLayout = newLayout;
  1432. subresourceInfo.requiredLayout = newLayout;
  1433. subresourceInfo.finalLayout = finalLayout;
  1434. subresourceInfo.range = subresourceRange;
  1435. subresourceInfo.isFBAttachment = isFBAttachment;
  1436. subresourceInfo.isShaderInput = isShaderBind;
  1437. if (!isTransfer)
  1438. {
  1439. subresourceInfo.hasTransitioned = false;
  1440. subresourceInfo.isReadOnly = !flags.isSet(VulkanUseFlag::Write);
  1441. }
  1442. else
  1443. {
  1444. subresourceInfo.hasTransitioned = true; // Transfers handle layout transitions externally (at this point they are assumed to already be done)
  1445. subresourceInfo.isReadOnly = true; // Doesn't matter for transfers
  1446. }
  1447. subresourceInfo.isInitialReadOnly = subresourceInfo.isReadOnly;
  1448. subresourceInfo.needsBarrier = needsBarrier;
  1449. mPassTouchedSubresourceInfos.insert((UINT32)mSubresourceInfoStorage.size() - 1);
  1450. };
  1451. auto insertResult = mImages.insert(std::make_pair(res, nextImageInfoIdx));
  1452. if (insertResult.second) // New element
  1453. {
  1454. UINT32 imageInfoIdx = insertResult.first->second;
  1455. mImageInfos.push_back(ImageInfo());
  1456. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  1457. imageInfo.subresourceInfoIdx = (UINT32)mSubresourceInfoStorage.size();
  1458. imageInfo.numSubresourceInfos = 1;
  1459. imageInfo.useHandle.used = false;
  1460. imageInfo.useHandle.flags = flags;
  1461. registerSubresourceInfo(range);
  1462. res->notifyBound();
  1463. }
  1464. else // Existing element
  1465. {
  1466. UINT32 imageInfoIdx = insertResult.first->second;
  1467. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  1468. assert(!imageInfo.useHandle.used);
  1469. imageInfo.useHandle.flags |= flags;
  1470. // See if there is an overlap between existing ranges and the new range. And if so break them up accordingly.
  1471. //// First test for the simplest and most common case (same range or no overlap) to avoid more complex
  1472. //// computations.
  1473. ImageSubresourceInfo* subresources = &mSubresourceInfoStorage[imageInfo.subresourceInfoIdx];
  1474. bool foundRange = false;
  1475. for(UINT32 i = 0; i < imageInfo.numSubresourceInfos; i++)
  1476. {
  1477. if(VulkanUtility::rangeOverlaps(subresources[i].range, range))
  1478. {
  1479. if (subresources[i].range.layerCount == range.layerCount &&
  1480. subresources[i].range.levelCount == range.levelCount &&
  1481. subresources[i].range.baseArrayLayer == range.baseArrayLayer &&
  1482. subresources[i].range.baseMipLevel == range.baseMipLevel)
  1483. {
  1484. // Just update existing range
  1485. updateSubresourceInfo(res, imageInfoIdx, subresources[i], newLayout, finalLayout, flags, usage);
  1486. mPassTouchedSubresourceInfos.insert(imageInfo.subresourceInfoIdx + i);
  1487. foundRange = true;
  1488. break;
  1489. }
  1490. break;
  1491. }
  1492. }
  1493. //// We'll need to update subresource ranges or add new ones. The hope is that this code is trigger VERY rarely
  1494. //// (for just a few specific textures per frame).
  1495. if (!foundRange)
  1496. {
  1497. std::array<VkImageSubresourceRange, 5> tempCutRanges;
  1498. bs_frame_mark();
  1499. {
  1500. // We orphan previously allocated memory (we reset it after submit() anyway)
  1501. UINT32 newSubresourceIdx = (UINT32)mSubresourceInfoStorage.size();
  1502. FrameVector<UINT32> cutOverlappingRanges;
  1503. for (UINT32 i = 0; i < imageInfo.numSubresourceInfos; i++)
  1504. {
  1505. UINT32 subresourceIdx = imageInfo.subresourceInfoIdx + i;
  1506. ImageSubresourceInfo& subresource = mSubresourceInfoStorage[subresourceIdx];
  1507. if (!VulkanUtility::rangeOverlaps(subresource.range, range))
  1508. {
  1509. // Just copy as is
  1510. mSubresourceInfoStorage.push_back(subresource);
  1511. mPassTouchedSubresourceInfos.insert((UINT32)mSubresourceInfoStorage.size() - 1);
  1512. }
  1513. else // Need to cut
  1514. {
  1515. UINT32 numCutRanges;
  1516. VulkanUtility::cutRange(subresource.range, range, tempCutRanges, numCutRanges);
  1517. for(UINT32 j = 0; j < numCutRanges; j++)
  1518. {
  1519. // Create a copy of the original subresource with the new range
  1520. ImageSubresourceInfo newInfo = mSubresourceInfoStorage[subresourceIdx];
  1521. newInfo.range = tempCutRanges[j];
  1522. if(VulkanUtility::rangeOverlaps(tempCutRanges[j], range))
  1523. {
  1524. // Update overlapping sub-resource range with new data from this range
  1525. updateSubresourceInfo(res, imageInfoIdx, newInfo, newLayout, finalLayout, flags, usage);
  1526. // Keep track of the overlapping ranges for later
  1527. cutOverlappingRanges.push_back((UINT32)mSubresourceInfoStorage.size());
  1528. }
  1529. mSubresourceInfoStorage.push_back(newInfo);
  1530. mPassTouchedSubresourceInfos.insert((UINT32)mSubresourceInfoStorage.size() - 1);
  1531. }
  1532. }
  1533. }
  1534. // Our range doesn't overlap with any existing ranges, so just add it
  1535. if(cutOverlappingRanges.size() == 0)
  1536. {
  1537. registerSubresourceInfo(range);
  1538. }
  1539. else // Search if overlapping ranges fully cover the requested range, and insert non-covered regions
  1540. {
  1541. FrameQueue<VkImageSubresourceRange> sourceRanges;
  1542. sourceRanges.push(range);
  1543. for(auto& entry : cutOverlappingRanges)
  1544. {
  1545. VkImageSubresourceRange& overlappingRange = mSubresourceInfoStorage[entry].range;
  1546. UINT32 numSourceRanges = (UINT32)sourceRanges.size();
  1547. for(UINT32 i = 0; i < numSourceRanges; i++)
  1548. {
  1549. VkImageSubresourceRange sourceRange = sourceRanges.front();
  1550. sourceRanges.pop();
  1551. UINT32 numCutRanges;
  1552. VulkanUtility::cutRange(sourceRange, overlappingRange, tempCutRanges, numCutRanges);
  1553. for(UINT32 j = 0; j < numCutRanges; j++)
  1554. {
  1555. // We only care about ranges outside of the ones we already covered
  1556. if(!VulkanUtility::rangeOverlaps(tempCutRanges[j], overlappingRange))
  1557. sourceRanges.push(tempCutRanges[j]);
  1558. }
  1559. }
  1560. }
  1561. // Any remaining range hasn't been covered yet
  1562. while(!sourceRanges.empty())
  1563. {
  1564. registerSubresourceInfo(sourceRanges.front());
  1565. sourceRanges.pop();
  1566. }
  1567. }
  1568. imageInfo.subresourceInfoIdx = newSubresourceIdx;
  1569. imageInfo.numSubresourceInfos = (UINT32)mSubresourceInfoStorage.size() - newSubresourceIdx;
  1570. }
  1571. bs_frame_clear();
  1572. }
  1573. }
  1574. // Register any sub-resources
  1575. for(UINT32 i = 0; i < range.layerCount; i++)
  1576. {
  1577. for(UINT32 j = 0; j < range.levelCount; j++)
  1578. {
  1579. UINT32 layer = range.baseArrayLayer + i;
  1580. UINT32 mipLevel = range.baseMipLevel + j;
  1581. registerResource(res->getSubresource(layer, mipLevel), flags);
  1582. }
  1583. }
  1584. }
  1585. void VulkanCmdBuffer::registerResource(VulkanBuffer* res, VkAccessFlags accessFlags, VulkanUseFlags flags)
  1586. {
  1587. bool isShaderWrite = (accessFlags & VK_ACCESS_SHADER_WRITE_BIT) != 0;
  1588. auto insertResult = mBuffers.insert(std::make_pair(res, BufferInfo()));
  1589. if (insertResult.second) // New element
  1590. {
  1591. BufferInfo& bufferInfo = insertResult.first->second;
  1592. bufferInfo.accessFlags = accessFlags;
  1593. bufferInfo.useHandle.used = false;
  1594. bufferInfo.useHandle.flags = flags;
  1595. // Any writes done on storage buffers will need explicit memory barriers (if read during the same pass) so
  1596. // we remember this, in case this buffers gets used later in this pass.
  1597. bufferInfo.needsBarrier = isShaderWrite;
  1598. res->notifyBound();
  1599. }
  1600. else // Existing element
  1601. {
  1602. BufferInfo& bufferInfo = insertResult.first->second;
  1603. assert(!bufferInfo.useHandle.used);
  1604. bufferInfo.useHandle.flags |= flags;
  1605. bufferInfo.accessFlags |= accessFlags;
  1606. // If the buffer was written to previously in this pass, and is now being used by a shader we need to issue
  1607. // a barrier to make those writes visible.
  1608. bool isShaderRead = (accessFlags & VK_ACCESS_SHADER_READ_BIT) != 0;
  1609. if(bufferInfo.needsBarrier && (isShaderRead || isShaderWrite))
  1610. {
  1611. // Need to end render pass in order to execute the barrier. Hopefully this won't trigger much since most
  1612. // shader writes are done during compute
  1613. if (isInRenderPass())
  1614. endRenderPass();
  1615. VkPipelineStageFlags stages =
  1616. VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
  1617. VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
  1618. VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT |
  1619. VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT |
  1620. VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
  1621. VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
  1622. VkBuffer buffer = res->getHandle();
  1623. memoryBarrier(buffer, VK_ACCESS_SHADER_WRITE_BIT, accessFlags, stages, stages);
  1624. bufferInfo.needsBarrier = isShaderWrite;
  1625. }
  1626. }
  1627. }
  1628. void VulkanCmdBuffer::registerResource(VulkanFramebuffer* res, RenderSurfaceMask loadMask, UINT32 readMask)
  1629. {
  1630. auto insertResult = mResources.insert(std::make_pair(res, ResourceUseHandle()));
  1631. if (insertResult.second) // New element
  1632. {
  1633. ResourceUseHandle& useHandle = insertResult.first->second;
  1634. useHandle.used = false;
  1635. useHandle.flags = VulkanUseFlag::Write;
  1636. res->notifyBound();
  1637. }
  1638. else // Existing element
  1639. {
  1640. ResourceUseHandle& useHandle = insertResult.first->second;
  1641. assert(!useHandle.used);
  1642. useHandle.flags |= VulkanUseFlag::Write;
  1643. }
  1644. // Register any sub-resources
  1645. UINT32 numColorAttachments = res->getNumColorAttachments();
  1646. for (UINT32 i = 0; i < numColorAttachments; i++)
  1647. {
  1648. const VulkanFramebufferAttachment& attachment = res->getColorAttachment(i);
  1649. // If image is being loaded, we need to transfer it to correct layout, otherwise it doesn't matter
  1650. VkImageLayout layout;
  1651. if (loadMask.isSet((RenderSurfaceMaskBits)(1 << i)))
  1652. {
  1653. // Note that this might not be the actual layout used during the render pass, as the render pass can
  1654. // transition this to a different layout when it begins, but we handle that elsewhere
  1655. layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
  1656. }
  1657. else
  1658. layout = VK_IMAGE_LAYOUT_UNDEFINED;
  1659. VkImageSubresourceRange range = attachment.image->getRange(attachment.surface);
  1660. registerResource(attachment.image, range, layout, attachment.finalLayout, VulkanUseFlag::Write,
  1661. ResourceUsage::Framebuffer);
  1662. }
  1663. if(res->hasDepthAttachment())
  1664. {
  1665. const VulkanFramebufferAttachment& attachment = res->getDepthStencilAttachment();
  1666. VulkanUseFlag useFlag = VulkanUseFlag::Write;
  1667. // If image is being loaded, we need to transfer it to correct layout, otherwise it doesn't matter
  1668. VkImageLayout layout;
  1669. if (loadMask.isSet(RT_DEPTH) || loadMask.isSet(RT_STENCIL)) // Can't load one without the other
  1670. {
  1671. // Note that this might not be the actual layout used during the render pass, as the render pass can
  1672. // transition this to a different layout when it begins, but we handle that elsewhere
  1673. layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
  1674. }
  1675. else
  1676. layout = VK_IMAGE_LAYOUT_UNDEFINED;
  1677. VkImageSubresourceRange range = attachment.image->getRange(attachment.surface);
  1678. registerResource(attachment.image, range, layout, attachment.finalLayout, useFlag, ResourceUsage::Framebuffer);
  1679. }
  1680. }
  1681. bool VulkanCmdBuffer::updateSubresourceInfo(VulkanImage* image, UINT32 imageInfoIdx,
  1682. ImageSubresourceInfo& subresourceInfo, VkImageLayout newLayout, VkImageLayout finalLayout, VulkanUseFlags flags,
  1683. ResourceUsage usage)
  1684. {
  1685. bool isTransfer = usage == ResourceUsage::Transfer;
  1686. bool isFBAttachment = usage == ResourceUsage::Framebuffer;
  1687. bool isShaderBind = usage == ResourceUsage::ShaderBind;
  1688. // Transfers are always considered read only because this only matters for destination access mask, and transfers
  1689. // handle that externally
  1690. if(!isTransfer)
  1691. subresourceInfo.isReadOnly &= !flags.isSet(VulkanUseFlag::Write);
  1692. // For transfers, just assign new layout, external code does all the work
  1693. if (isTransfer)
  1694. subresourceInfo.requiredLayout = newLayout;
  1695. else
  1696. {
  1697. // New layout is valid, check for transitions (UNDEFINED signifies the caller doesn't want a layout transition)
  1698. if (newLayout != VK_IMAGE_LAYOUT_UNDEFINED)
  1699. {
  1700. // If layout transition was requested by framebuffer bind, respect it because render-pass will only accept a
  1701. // specific layout (in certain cases), and we have no choice.
  1702. // In the case when a FB attachment is also bound for shader reads, this will override the layout required for
  1703. // shader read (GENERAL or DEPTH_READ_ONLY), but that is fine because those transitions are handled
  1704. // automatically by render-pass layout transitions.
  1705. // Any other texture (non FB attachment) will only even be bound in a single layout and we can keep the one it
  1706. // was originally registered with.
  1707. if (isFBAttachment)
  1708. subresourceInfo.requiredLayout = newLayout;
  1709. else if (!subresourceInfo.isFBAttachment) // Layout transition is not being done on a FB image
  1710. {
  1711. // Check if the image had a layout previously assigned, and if so check if multiple different layouts
  1712. // were requested. In that case we wish to transfer the image to GENERAL layout.
  1713. bool firstUseInRenderPass = !subresourceInfo.isShaderInput && !subresourceInfo.isFBAttachment;
  1714. if (firstUseInRenderPass || subresourceInfo.requiredLayout == VK_IMAGE_LAYOUT_UNDEFINED)
  1715. subresourceInfo.requiredLayout = newLayout;
  1716. else if (subresourceInfo.requiredLayout != newLayout)
  1717. subresourceInfo.requiredLayout = VK_IMAGE_LAYOUT_GENERAL;
  1718. }
  1719. }
  1720. }
  1721. // If attached to FB, then the final layout is set by the FB (provided as layout param here), otherwise its
  1722. // the same as required layout
  1723. if (!isFBAttachment && !subresourceInfo.isFBAttachment)
  1724. subresourceInfo.finalLayout = subresourceInfo.requiredLayout;
  1725. else
  1726. {
  1727. if (isFBAttachment)
  1728. subresourceInfo.finalLayout = finalLayout;
  1729. }
  1730. // Queue layout transition, if not transfer. Transfer handle layout transitions externally.
  1731. if (!isTransfer)
  1732. {
  1733. // If we haven't done a layout transition yet, we can just overwrite the previously written values, and the
  1734. // transition will be handled as the first thing in submit(), otherwise we queue a non-initial transition
  1735. // below.
  1736. if (!subresourceInfo.hasTransitioned)
  1737. {
  1738. subresourceInfo.initialLayout = subresourceInfo.requiredLayout;
  1739. subresourceInfo.currentLayout = subresourceInfo.requiredLayout;
  1740. subresourceInfo.isInitialReadOnly = subresourceInfo.isReadOnly;
  1741. }
  1742. else
  1743. {
  1744. if (subresourceInfo.currentLayout != subresourceInfo.requiredLayout)
  1745. mQueuedLayoutTransitions[image] = imageInfoIdx;
  1746. }
  1747. }
  1748. else
  1749. {
  1750. // Resource has already transitioned its layout externally since this is a transfer. We cannot allow a
  1751. // transition in submit().
  1752. subresourceInfo.currentLayout = subresourceInfo.requiredLayout;
  1753. subresourceInfo.hasTransitioned = true;
  1754. }
  1755. // If a FB attachment was just bound as a shader input, we might need to restart the render pass with a FB
  1756. // attachment that supports read-only attachments using the GENERAL or DEPTH_READ_ONLY layout
  1757. bool resetRenderPass = false;
  1758. if (isFBAttachment)
  1759. {
  1760. if (!subresourceInfo.isFBAttachment)
  1761. {
  1762. subresourceInfo.isFBAttachment = true;
  1763. resetRenderPass = subresourceInfo.isShaderInput;
  1764. }
  1765. }
  1766. else
  1767. {
  1768. if (!subresourceInfo.isShaderInput)
  1769. {
  1770. subresourceInfo.isShaderInput = true;
  1771. if (subresourceInfo.isFBAttachment)
  1772. {
  1773. // Special case for depth: If user has set up proper read-only flags, then the render pass will have
  1774. // taken care of setting the valid state anyway, so no need to end the render pass
  1775. if (subresourceInfo.requiredLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
  1776. {
  1777. if ((mRenderTargetReadOnlyFlags & FBT_DEPTH) != 0 || (mRenderTargetReadOnlyFlags & FBT_STENCIL) != 0)
  1778. resetRenderPass = false;
  1779. else
  1780. resetRenderPass = true;
  1781. }
  1782. else
  1783. resetRenderPass = true;
  1784. }
  1785. else
  1786. resetRenderPass = false;
  1787. }
  1788. }
  1789. // If we need to switch frame-buffers, end current render pass
  1790. if (resetRenderPass && isInRenderPass())
  1791. endRenderPass();
  1792. else
  1793. {
  1794. // Since we won't be ending the render pass, check if this same sub-resource was written earlier in the pass,
  1795. // in which case we need to issue a memory barrier so those writes are visible.
  1796. // Memory barrier only matters if image is bound for shader use (no need for color attachments or transfers)
  1797. if(subresourceInfo.needsBarrier && isShaderBind)
  1798. {
  1799. bool isWrite = flags.isSet(VulkanUseFlag::Write);
  1800. VkPipelineStageFlags stages =
  1801. VK_PIPELINE_STAGE_VERTEX_SHADER_BIT |
  1802. VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
  1803. VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT |
  1804. VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT |
  1805. VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
  1806. VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
  1807. memoryBarrier(image->getHandle(), VK_ACCESS_SHADER_WRITE_BIT,
  1808. image->getAccessFlags(subresourceInfo.requiredLayout, !isWrite),
  1809. stages, stages, subresourceInfo.requiredLayout, subresourceInfo.range);
  1810. subresourceInfo.needsBarrier = isWrite;
  1811. }
  1812. }
  1813. return resetRenderPass;
  1814. }
  1815. VulkanCmdBuffer::ImageSubresourceInfo& VulkanCmdBuffer::findSubresourceInfo(VulkanImage* image, UINT32 face, UINT32 mip)
  1816. {
  1817. UINT32 imageInfoIdx = mImages[image];
  1818. ImageInfo& imageInfo = mImageInfos[imageInfoIdx];
  1819. ImageSubresourceInfo* subresourceInfos = &mSubresourceInfoStorage[imageInfo.subresourceInfoIdx];
  1820. for(UINT32 i = 0; i < imageInfo.numSubresourceInfos; i++)
  1821. {
  1822. ImageSubresourceInfo& entry = subresourceInfos[i];
  1823. if(face >= entry.range.baseArrayLayer && face < (entry.range.baseArrayLayer + entry.range.layerCount) &&
  1824. mip >= entry.range.baseMipLevel && mip < (entry.range.baseMipLevel + entry.range.levelCount))
  1825. {
  1826. return entry;
  1827. }
  1828. }
  1829. assert(false); // Caller should ensure the subresource actually exists, so this shouldn't happen
  1830. return subresourceInfos[0];
  1831. }
  1832. void VulkanCmdBuffer::getInProgressQueries(Vector<VulkanTimerQuery*>& timer, Vector<VulkanOcclusionQuery*>& occlusion) const
  1833. {
  1834. for(auto& query : mTimerQueries)
  1835. {
  1836. if (query->_isInProgress())
  1837. timer.push_back(query);
  1838. }
  1839. for (auto& query : mOcclusionQueries)
  1840. {
  1841. if (query->_isInProgress())
  1842. occlusion.push_back(query);
  1843. }
  1844. }
  1845. VulkanCommandBuffer::VulkanCommandBuffer(VulkanDevice& device, GpuQueueType type, UINT32 deviceIdx,
  1846. UINT32 queueIdx, bool secondary)
  1847. : CommandBuffer(type, deviceIdx, queueIdx, secondary), mBuffer(nullptr)
  1848. , mDevice(device), mQueue(nullptr), mIdMask(0)
  1849. {
  1850. UINT32 numQueues = device.getNumQueues(mType);
  1851. if (numQueues == 0) // Fall back to graphics queue
  1852. {
  1853. mType = GQT_GRAPHICS;
  1854. numQueues = device.getNumQueues(GQT_GRAPHICS);
  1855. }
  1856. mQueue = device.getQueue(mType, mQueueIdx % numQueues);
  1857. mIdMask = device.getQueueMask(mType, mQueueIdx);
  1858. acquireNewBuffer();
  1859. }
  1860. VulkanCommandBuffer::~VulkanCommandBuffer()
  1861. {
  1862. mBuffer->reset();
  1863. }
  1864. void VulkanCommandBuffer::acquireNewBuffer()
  1865. {
  1866. VulkanCmdBufferPool& pool = mDevice.getCmdBufferPool();
  1867. if (mBuffer != nullptr)
  1868. assert(mBuffer->isSubmitted());
  1869. UINT32 queueFamily = mDevice.getQueueFamily(mType);
  1870. mBuffer = pool.getBuffer(queueFamily, mIsSecondary);
  1871. }
  1872. void VulkanCommandBuffer::submit(UINT32 syncMask)
  1873. {
  1874. // Ignore myself
  1875. syncMask &= ~mIdMask;
  1876. if (mBuffer->isInRenderPass())
  1877. mBuffer->endRenderPass();
  1878. // Execute any queued layout transitions that weren't already handled by the render pass
  1879. mBuffer->executeLayoutTransitions();
  1880. // Interrupt any in-progress queries (no in-progress queries allowed during command buffer submit)
  1881. Vector<VulkanTimerQuery*> timerQueries;
  1882. Vector<VulkanOcclusionQuery*> occlusionQueries;
  1883. mBuffer->getInProgressQueries(timerQueries, occlusionQueries);
  1884. for (auto& query : timerQueries)
  1885. query->_interrupt(*mBuffer);
  1886. for (auto& query : occlusionQueries)
  1887. query->_interrupt(*mBuffer);
  1888. if (mBuffer->isRecording())
  1889. mBuffer->end();
  1890. if (mBuffer->isReadyForSubmit()) // Possibly nothing was recorded in the buffer
  1891. {
  1892. mBuffer->submit(mQueue, mQueueIdx, syncMask);
  1893. acquireNewBuffer();
  1894. gVulkanCBManager().refreshStates(mDeviceIdx);
  1895. }
  1896. // Resume interrupted queries on the new command buffer
  1897. for (auto& query : timerQueries)
  1898. query->_resume(*mBuffer);
  1899. for (auto& query : occlusionQueries)
  1900. query->_resume(*mBuffer);
  1901. }
  1902. }}