BsVulkanTexture.cpp 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsVulkanTexture.h"
  4. #include "BsVulkanRenderAPI.h"
  5. #include "BsVulkanDevice.h"
  6. #include "BsVulkanUtility.h"
  7. #include "Managers/BsVulkanCommandBufferManager.h"
  8. #include "BsVulkanHardwareBuffer.h"
  9. #include "CoreThread/BsCoreThread.h"
  10. #include "Profiling/BsRenderStats.h"
  11. #include "Math/BsMath.h"
  12. namespace bs { namespace ct
  13. {
  14. VULKAN_IMAGE_DESC createDesc(VkImage image, VkDeviceMemory memory, VkImageLayout layout, const TextureProperties& props)
  15. {
  16. VULKAN_IMAGE_DESC desc;
  17. desc.image = image;
  18. desc.memory = memory;
  19. desc.type = props.getTextureType();
  20. desc.format = VulkanUtility::getPixelFormat(props.getFormat(), props.isHardwareGammaEnabled());
  21. desc.numFaces = props.getNumFaces();
  22. desc.numMipLevels = props.getNumMipmaps() + 1;
  23. desc.layout = layout;
  24. desc.usage = (UINT32)props.getUsage();
  25. return desc;
  26. }
  27. VulkanImage::VulkanImage(VulkanResourceManager* owner, VkImage image, VkDeviceMemory memory, VkImageLayout layout,
  28. const TextureProperties& props, bool ownsImage)
  29. : VulkanImage(owner, createDesc(image, memory, layout, props), ownsImage)
  30. { }
  31. VulkanImage::VulkanImage(VulkanResourceManager* owner, const VULKAN_IMAGE_DESC& desc, bool ownsImage)
  32. : VulkanResource(owner, false), mImage(desc.image), mMemory(desc.memory), mFramebufferMainView(VK_NULL_HANDLE)
  33. , mUsage(desc.usage), mOwnsImage(ownsImage), mNumFaces(desc.numFaces), mNumMipLevels(desc.numMipLevels)
  34. {
  35. mImageViewCI.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
  36. mImageViewCI.pNext = nullptr;
  37. mImageViewCI.flags = 0;
  38. mImageViewCI.image = desc.image;
  39. mImageViewCI.format = desc.format;
  40. mImageViewCI.components = {
  41. VK_COMPONENT_SWIZZLE_R,
  42. VK_COMPONENT_SWIZZLE_G,
  43. VK_COMPONENT_SWIZZLE_B,
  44. VK_COMPONENT_SWIZZLE_A
  45. };
  46. switch (desc.type)
  47. {
  48. case TEX_TYPE_1D:
  49. mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_1D;
  50. break;
  51. default:
  52. case TEX_TYPE_2D:
  53. mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
  54. break;
  55. case TEX_TYPE_3D:
  56. mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_3D;
  57. break;
  58. case TEX_TYPE_CUBE_MAP:
  59. mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
  60. break;
  61. }
  62. TextureSurface completeSurface(0, desc.numMipLevels, 0, desc.numFaces);
  63. if ((mUsage & TU_DEPTHSTENCIL) != 0)
  64. {
  65. mFramebufferMainView = createView(completeSurface, getAspectFlags());
  66. mMainView = createView(completeSurface, VK_IMAGE_ASPECT_DEPTH_BIT);
  67. }
  68. else
  69. mMainView = createView(completeSurface, VK_IMAGE_ASPECT_COLOR_BIT);
  70. ImageViewInfo mainViewInfo;
  71. mainViewInfo.surface = completeSurface;
  72. mainViewInfo.framebuffer = false;
  73. mainViewInfo.view = mMainView;
  74. mImageInfos.push_back(mainViewInfo);
  75. if (mFramebufferMainView != VK_NULL_HANDLE)
  76. {
  77. ImageViewInfo fbMainViewInfo;
  78. fbMainViewInfo.surface = completeSurface;
  79. fbMainViewInfo.framebuffer = true;
  80. fbMainViewInfo.view = mFramebufferMainView;
  81. mImageInfos.push_back(fbMainViewInfo);
  82. }
  83. UINT32 numSubresources = mNumFaces * mNumMipLevels;
  84. mSubresources = (VulkanImageSubresource**)bs_alloc(sizeof(VulkanImageSubresource*) * numSubresources);
  85. for (UINT32 i = 0; i < numSubresources; i++)
  86. mSubresources[i] = owner->create<VulkanImageSubresource>(desc.layout);
  87. }
  88. VulkanImage::~VulkanImage()
  89. {
  90. VulkanDevice& device = mOwner->getDevice();
  91. VkDevice vkDevice = device.getLogical();
  92. UINT32 numSubresources = mNumFaces * mNumMipLevels;
  93. for (UINT32 i = 0; i < numSubresources; i++)
  94. {
  95. assert(!mSubresources[i]->isBound()); // Image beeing freed but its subresources are still bound somewhere
  96. mSubresources[i]->destroy();
  97. }
  98. for(auto& entry : mImageInfos)
  99. vkDestroyImageView(vkDevice, entry.view, gVulkanAllocator);
  100. if (mOwnsImage)
  101. {
  102. vkDestroyImage(vkDevice, mImage, gVulkanAllocator);
  103. device.freeMemory(mMemory);
  104. }
  105. }
  106. VkImageView VulkanImage::getView(bool framebuffer) const
  107. {
  108. if(framebuffer && (mUsage & TU_DEPTHSTENCIL) != 0)
  109. return mFramebufferMainView;
  110. return mMainView;
  111. }
  112. VkImageView VulkanImage::getView(const TextureSurface& surface, bool framebuffer) const
  113. {
  114. for(auto& entry : mImageInfos)
  115. {
  116. if (surface.mipLevel == entry.surface.mipLevel &&
  117. surface.numMipLevels == entry.surface.numMipLevels &&
  118. surface.face == entry.surface.face &&
  119. surface.numFaces == entry.surface.numFaces)
  120. {
  121. if((mUsage & TU_DEPTHSTENCIL) == 0)
  122. return entry.view;
  123. else
  124. {
  125. if (framebuffer == entry.framebuffer)
  126. return entry.view;
  127. }
  128. }
  129. }
  130. ImageViewInfo info;
  131. info.surface = surface;
  132. info.framebuffer = framebuffer;
  133. if ((mUsage & TU_DEPTHSTENCIL) != 0)
  134. {
  135. if(framebuffer)
  136. info.view = createView(surface, getAspectFlags());
  137. else
  138. info.view = createView(surface, VK_IMAGE_ASPECT_DEPTH_BIT);
  139. }
  140. else
  141. info.view = createView(surface, VK_IMAGE_ASPECT_COLOR_BIT);
  142. mImageInfos.push_back(info);
  143. return info.view;
  144. }
  145. VkImageView VulkanImage::createView(const TextureSurface& surface, VkImageAspectFlags aspectMask) const
  146. {
  147. VkImageViewType oldViewType = mImageViewCI.viewType;
  148. switch (oldViewType)
  149. {
  150. case VK_IMAGE_VIEW_TYPE_CUBE:
  151. if(surface.numFaces == 1)
  152. mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
  153. else if(surface.numFaces % 6 == 0)
  154. {
  155. if(mNumFaces > 6)
  156. mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
  157. }
  158. else
  159. mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
  160. break;
  161. case VK_IMAGE_VIEW_TYPE_1D:
  162. if(surface.numFaces > 1)
  163. mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_1D_ARRAY;
  164. break;
  165. case VK_IMAGE_VIEW_TYPE_2D:
  166. case VK_IMAGE_VIEW_TYPE_3D:
  167. if (surface.numFaces > 1)
  168. mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
  169. break;
  170. default:
  171. break;
  172. }
  173. mImageViewCI.subresourceRange.aspectMask = aspectMask;
  174. mImageViewCI.subresourceRange.baseMipLevel = surface.mipLevel;
  175. mImageViewCI.subresourceRange.levelCount = surface.numMipLevels == 0 ? VK_REMAINING_MIP_LEVELS : surface.numMipLevels;
  176. mImageViewCI.subresourceRange.baseArrayLayer = surface.face;
  177. mImageViewCI.subresourceRange.layerCount = surface.numFaces == 0 ? VK_REMAINING_ARRAY_LAYERS : surface.numFaces;
  178. VkImageView view;
  179. VkResult result = vkCreateImageView(mOwner->getDevice().getLogical(), &mImageViewCI, gVulkanAllocator, &view);
  180. assert(result == VK_SUCCESS);
  181. mImageViewCI.viewType = oldViewType;
  182. return view;
  183. }
  184. VkImageLayout VulkanImage::getOptimalLayout() const
  185. {
  186. // If it's load-store, no other flags matter, it must be in general layout
  187. if ((mUsage & TU_LOADSTORE) != 0)
  188. return VK_IMAGE_LAYOUT_GENERAL;
  189. if ((mUsage & TU_RENDERTARGET) != 0)
  190. return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
  191. else if ((mUsage & TU_DEPTHSTENCIL) != 0)
  192. return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
  193. else
  194. {
  195. if ((mUsage & TU_DYNAMIC) != 0)
  196. return VK_IMAGE_LAYOUT_GENERAL;
  197. return VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
  198. }
  199. }
  200. VkImageAspectFlags VulkanImage::getAspectFlags() const
  201. {
  202. if ((mUsage & TU_DEPTHSTENCIL) != 0)
  203. {
  204. bool hasStencil = mImageViewCI.format == VK_FORMAT_D16_UNORM_S8_UINT ||
  205. mImageViewCI.format == VK_FORMAT_D24_UNORM_S8_UINT ||
  206. mImageViewCI.format == VK_FORMAT_D32_SFLOAT_S8_UINT;
  207. if (hasStencil)
  208. return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
  209. return VK_IMAGE_ASPECT_DEPTH_BIT;
  210. }
  211. return VK_IMAGE_ASPECT_COLOR_BIT;
  212. }
  213. VkImageSubresourceRange VulkanImage::getRange() const
  214. {
  215. VkImageSubresourceRange range;
  216. range.baseArrayLayer = 0;
  217. range.layerCount = mNumFaces;
  218. range.baseMipLevel = 0;
  219. range.levelCount = mNumMipLevels;
  220. range.aspectMask = getAspectFlags();
  221. return range;
  222. }
  223. VkImageSubresourceRange VulkanImage::getRange(const TextureSurface& surface) const
  224. {
  225. VkImageSubresourceRange range;
  226. range.baseArrayLayer = surface.face;
  227. range.layerCount = surface.numFaces == 0 ? mNumFaces : surface.numFaces;
  228. range.baseMipLevel = surface.mipLevel;
  229. range.levelCount = surface.numMipLevels == 0 ? mNumMipLevels : surface.numMipLevels;
  230. range.aspectMask = getAspectFlags();
  231. return range;
  232. }
  233. VulkanImageSubresource* VulkanImage::getSubresource(UINT32 face, UINT32 mipLevel)
  234. {
  235. return mSubresources[mipLevel * mNumFaces + face];
  236. }
  237. void VulkanImage::map(UINT32 face, UINT32 mipLevel, PixelData& output) const
  238. {
  239. VulkanDevice& device = mOwner->getDevice();
  240. VkImageSubresource range;
  241. range.mipLevel = mipLevel;
  242. range.arrayLayer = face;
  243. if (mImageViewCI.subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT)
  244. range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  245. else // Depth stencil, but we only map depth
  246. range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
  247. VkSubresourceLayout layout;
  248. vkGetImageSubresourceLayout(device.getLogical(), mImage, &range, &layout);
  249. assert(layout.size == output.getSize());
  250. output.setRowPitch((UINT32)layout.rowPitch);
  251. output.setSlicePitch((UINT32)layout.depthPitch);
  252. UINT8* data;
  253. VkResult result = vkMapMemory(device.getLogical(), mMemory, layout.offset, layout.size, 0, (void**)&data);
  254. assert(result == VK_SUCCESS);
  255. output.setExternalBuffer(data);
  256. }
  257. UINT8* VulkanImage::map(UINT32 offset, UINT32 size) const
  258. {
  259. VulkanDevice& device = mOwner->getDevice();
  260. UINT8* data;
  261. VkResult result = vkMapMemory(device.getLogical(), mMemory, offset, size, 0, (void**)&data);
  262. assert(result == VK_SUCCESS);
  263. return data;
  264. }
  265. void VulkanImage::unmap()
  266. {
  267. VulkanDevice& device = mOwner->getDevice();
  268. vkUnmapMemory(device.getLogical(), mMemory);
  269. }
  270. void VulkanImage::copy(VulkanTransferBuffer* cb, VulkanBuffer* destination, const VkExtent3D& extent,
  271. const VkImageSubresourceLayers& range, VkImageLayout layout)
  272. {
  273. VkBufferImageCopy region;
  274. region.bufferRowLength = destination->getRowPitch();
  275. region.bufferImageHeight = destination->getSliceHeight();
  276. region.bufferOffset = 0;
  277. region.imageOffset.x = 0;
  278. region.imageOffset.y = 0;
  279. region.imageOffset.z = 0;
  280. region.imageExtent = extent;
  281. region.imageSubresource = range;
  282. vkCmdCopyImageToBuffer(cb->getCB()->getHandle(), mImage, layout, destination->getHandle(), 1, &region);
  283. }
  284. VkAccessFlags VulkanImage::getAccessFlags(VkImageLayout layout, bool readOnly)
  285. {
  286. VkAccessFlags accessFlags;
  287. switch (layout)
  288. {
  289. case VK_IMAGE_LAYOUT_GENERAL:
  290. {
  291. accessFlags = VK_ACCESS_SHADER_READ_BIT;
  292. if ((mUsage & TU_LOADSTORE) != 0)
  293. {
  294. if (!readOnly)
  295. accessFlags |= VK_ACCESS_SHADER_WRITE_BIT;
  296. }
  297. if ((mUsage & TU_RENDERTARGET) != 0)
  298. {
  299. accessFlags |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
  300. if(!readOnly)
  301. accessFlags |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  302. }
  303. else if ((mUsage & TU_DEPTHSTENCIL) != 0)
  304. {
  305. accessFlags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
  306. if (!readOnly)
  307. accessFlags |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
  308. }
  309. }
  310. break;
  311. case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
  312. accessFlags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
  313. break;
  314. case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
  315. accessFlags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
  316. break;
  317. case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
  318. case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR:
  319. case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR:
  320. accessFlags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
  321. break;
  322. case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
  323. accessFlags = VK_ACCESS_SHADER_READ_BIT;
  324. break;
  325. case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
  326. accessFlags = VK_ACCESS_TRANSFER_READ_BIT;
  327. break;
  328. case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
  329. accessFlags = VK_ACCESS_TRANSFER_WRITE_BIT;
  330. break;
  331. case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
  332. accessFlags = VK_ACCESS_MEMORY_READ_BIT;
  333. break;
  334. case VK_IMAGE_LAYOUT_UNDEFINED:
  335. case VK_IMAGE_LAYOUT_PREINITIALIZED:
  336. accessFlags = 0;
  337. break;
  338. default:
  339. accessFlags = 0;
  340. LOGWRN("Unsupported source layout for Vulkan image.");
  341. break;
  342. }
  343. return accessFlags;
  344. }
  345. void VulkanImage::getBarriers(const VkImageSubresourceRange& range, Vector<VkImageMemoryBarrier>& barriers)
  346. {
  347. UINT32 numSubresources = range.levelCount * range.layerCount;
  348. // Nothing to do
  349. if (numSubresources == 0)
  350. return;
  351. UINT32 mip = range.baseMipLevel;
  352. UINT32 face = range.baseArrayLayer;
  353. UINT32 lastMip = range.baseMipLevel + range.levelCount - 1;
  354. UINT32 lastFace = range.baseArrayLayer + range.layerCount - 1;
  355. VkImageMemoryBarrier defaultBarrier;
  356. defaultBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  357. defaultBarrier.pNext = nullptr;
  358. defaultBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  359. defaultBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  360. defaultBarrier.image = getHandle();
  361. defaultBarrier.subresourceRange.aspectMask = range.aspectMask;
  362. defaultBarrier.subresourceRange.layerCount = 1;
  363. defaultBarrier.subresourceRange.levelCount = 1;
  364. defaultBarrier.subresourceRange.baseArrayLayer = 0;
  365. defaultBarrier.subresourceRange.baseMipLevel = 0;
  366. auto addNewBarrier = [&](VulkanImageSubresource* subresource, UINT32 face, UINT32 mip)
  367. {
  368. barriers.push_back(defaultBarrier);
  369. VkImageMemoryBarrier* barrier = &barriers.back();
  370. barrier->subresourceRange.baseArrayLayer = face;
  371. barrier->subresourceRange.baseMipLevel = mip;
  372. barrier->srcAccessMask = getAccessFlags(subresource->getLayout());
  373. barrier->oldLayout = subresource->getLayout();
  374. return barrier;
  375. };
  376. bs_frame_mark();
  377. {
  378. FrameVector<bool> processed(numSubresources, false);
  379. // Add first subresource
  380. VulkanImageSubresource* subresource = getSubresource(face, mip);
  381. addNewBarrier(subresource, face, mip);
  382. numSubresources--;
  383. processed[0] = true;
  384. while (numSubresources > 0)
  385. {
  386. // Try to expand the barrier as much as possible
  387. VkImageMemoryBarrier* barrier = &barriers.back();
  388. while (true)
  389. {
  390. // Expand by one in the X direction
  391. bool expandedFace = true;
  392. if (face < lastFace)
  393. {
  394. for (UINT32 i = 0; i < barrier->subresourceRange.levelCount; i++)
  395. {
  396. UINT32 curMip = barrier->subresourceRange.baseMipLevel + i;
  397. VulkanImageSubresource* subresource = getSubresource(face + 1, curMip);
  398. if (barrier->oldLayout != subresource->getLayout())
  399. {
  400. expandedFace = false;
  401. break;
  402. }
  403. }
  404. if (expandedFace)
  405. {
  406. barrier->subresourceRange.layerCount++;
  407. numSubresources -= barrier->subresourceRange.levelCount;
  408. face++;
  409. for (UINT32 i = 0; i < barrier->subresourceRange.levelCount; i++)
  410. {
  411. UINT32 curMip = (barrier->subresourceRange.baseMipLevel + i) - range.baseMipLevel;
  412. UINT32 idx = curMip * range.layerCount + (face - range.baseArrayLayer);
  413. processed[idx] = true;
  414. }
  415. }
  416. }
  417. else
  418. expandedFace = false;
  419. // Expand by one in the Y direction
  420. bool expandedMip = true;
  421. if (mip < lastMip)
  422. {
  423. for (UINT32 i = 0; i < barrier->subresourceRange.layerCount; i++)
  424. {
  425. UINT32 curFace = barrier->subresourceRange.baseArrayLayer + i;
  426. VulkanImageSubresource* subresource = getSubresource(curFace, mip + 1);
  427. if (barrier->oldLayout != subresource->getLayout())
  428. {
  429. expandedMip = false;
  430. break;
  431. }
  432. }
  433. if (expandedMip)
  434. {
  435. barrier->subresourceRange.levelCount++;
  436. numSubresources -= barrier->subresourceRange.layerCount;
  437. mip++;
  438. for (UINT32 i = 0; i < barrier->subresourceRange.layerCount; i++)
  439. {
  440. UINT32 curFace = (barrier->subresourceRange.baseArrayLayer + i) - range.baseArrayLayer;
  441. UINT32 idx = (mip - range.baseMipLevel) * range.layerCount + curFace;
  442. processed[idx] = true;
  443. }
  444. }
  445. }
  446. else
  447. expandedMip = false;
  448. // If we can't grow no more, we're done with this square
  449. if (!expandedMip && !expandedFace)
  450. break;
  451. }
  452. // Look for a new starting point (sub-resource we haven't processed yet)
  453. for (UINT32 i = 0; i < range.levelCount; i++)
  454. {
  455. bool found = false;
  456. for (UINT32 j = 0; j < range.layerCount; j++)
  457. {
  458. UINT32 idx = i * range.layerCount + j;
  459. if (!processed[idx])
  460. {
  461. mip = range.baseMipLevel + i;
  462. face = range.baseArrayLayer + j;
  463. found = true;
  464. processed[idx] = true;
  465. break;
  466. }
  467. }
  468. if (found)
  469. {
  470. VulkanImageSubresource* subresource = getSubresource(face, mip);
  471. addNewBarrier(subresource, face, mip);
  472. numSubresources--;
  473. break;
  474. }
  475. }
  476. }
  477. }
  478. bs_frame_clear();
  479. }
  480. VulkanImageSubresource::VulkanImageSubresource(VulkanResourceManager* owner, VkImageLayout layout)
  481. :VulkanResource(owner, false), mLayout(layout)
  482. { }
  483. VulkanTexture::VulkanTexture(const TEXTURE_DESC& desc, const SPtr<PixelData>& initialData,
  484. GpuDeviceFlags deviceMask)
  485. : Texture(desc, initialData, deviceMask), mImages(), mInternalFormats(), mDeviceMask(deviceMask)
  486. , mStagingBuffer(nullptr), mMappedDeviceIdx((UINT32)-1), mMappedGlobalQueueIdx((UINT32)-1)
  487. , mMappedMip(0), mMappedFace(0), mMappedRowPitch(0), mMappedSlicePitch(0)
  488. , mMappedLockOptions(GBL_WRITE_ONLY), mDirectlyMappable(false), mSupportsGPUWrites(false), mIsMapped(false)
  489. {
  490. }
  491. VulkanTexture::~VulkanTexture()
  492. {
  493. for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  494. {
  495. if (mImages[i] == nullptr)
  496. return;
  497. mImages[i]->destroy();
  498. }
  499. assert(mStagingBuffer == nullptr);
  500. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
  501. }
  502. void VulkanTexture::initialize()
  503. {
  504. THROW_IF_NOT_CORE_THREAD;
  505. const TextureProperties& props = mProperties;
  506. mImageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  507. mImageCI.pNext = nullptr;
  508. mImageCI.flags = 0;
  509. TextureType texType = props.getTextureType();
  510. switch(texType)
  511. {
  512. case TEX_TYPE_1D:
  513. mImageCI.imageType = VK_IMAGE_TYPE_1D;
  514. break;
  515. case TEX_TYPE_2D:
  516. mImageCI.imageType = VK_IMAGE_TYPE_2D;
  517. break;
  518. case TEX_TYPE_3D:
  519. mImageCI.imageType = VK_IMAGE_TYPE_3D;
  520. break;
  521. case TEX_TYPE_CUBE_MAP:
  522. mImageCI.imageType = VK_IMAGE_TYPE_2D;
  523. mImageCI.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
  524. break;
  525. }
  526. // Note: I force rendertarget and depthstencil types to be readable in shader. Depending on performance impact
  527. // it might be beneficial to allow the user to enable this explicitly only when needed.
  528. mImageCI.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
  529. int usage = props.getUsage();
  530. if ((usage & TU_RENDERTARGET) != 0)
  531. {
  532. mImageCI.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  533. mSupportsGPUWrites = true;
  534. }
  535. else if ((usage & TU_DEPTHSTENCIL) != 0)
  536. {
  537. mImageCI.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
  538. mSupportsGPUWrites = true;
  539. }
  540. if ((usage & TU_LOADSTORE) != 0)
  541. {
  542. mImageCI.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
  543. mSupportsGPUWrites = true;
  544. }
  545. VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
  546. VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
  547. if ((usage & TU_DYNAMIC) != 0) // Attempt to use linear tiling for dynamic textures, so we can directly map and modify them
  548. {
  549. // Only support 2D textures, with one sample and one mip level, only used for shader reads
  550. // (Optionally check vkGetPhysicalDeviceFormatProperties & vkGetPhysicalDeviceImageFormatProperties for
  551. // additional supported configs, but right now there doesn't seem to be any additional support)
  552. if(texType == TEX_TYPE_2D && props.getNumSamples() <= 1 && props.getNumMipmaps() == 0 &&
  553. props.getNumFaces() == 1 && (mImageCI.usage & VK_IMAGE_USAGE_SAMPLED_BIT) != 0)
  554. {
  555. // Also, only support normal textures, not render targets or storage textures
  556. if (!mSupportsGPUWrites)
  557. {
  558. mDirectlyMappable = true;
  559. tiling = VK_IMAGE_TILING_LINEAR;
  560. layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
  561. }
  562. }
  563. }
  564. mImageCI.extent = { props.getWidth(), props.getHeight(), props.getDepth() };
  565. mImageCI.mipLevels = props.getNumMipmaps() + 1;
  566. mImageCI.arrayLayers = props.getNumFaces();
  567. mImageCI.samples = VulkanUtility::getSampleFlags(props.getNumSamples());
  568. mImageCI.tiling = tiling;
  569. mImageCI.initialLayout = layout;
  570. mImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  571. mImageCI.queueFamilyIndexCount = 0;
  572. mImageCI.pQueueFamilyIndices = nullptr;
  573. VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance());
  574. VulkanDevice* devices[BS_MAX_DEVICES];
  575. VulkanUtility::getDevices(rapi, mDeviceMask, devices);
  576. // Allocate buffers per-device
  577. for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  578. {
  579. if (devices[i] == nullptr)
  580. continue;
  581. bool optimalTiling = tiling == VK_IMAGE_TILING_OPTIMAL;
  582. mInternalFormats[i] = VulkanUtility::getClosestSupportedPixelFormat(
  583. *devices[i], props.getFormat(), props.getTextureType(), props.getUsage(), optimalTiling,
  584. props.isHardwareGammaEnabled());
  585. mImages[i] = createImage(*devices[i], mInternalFormats[i]);
  586. }
  587. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Texture);
  588. Texture::initialize();
  589. }
  590. VulkanImage* VulkanTexture::createImage(VulkanDevice& device, PixelFormat format)
  591. {
  592. bool directlyMappable = mImageCI.tiling == VK_IMAGE_TILING_LINEAR;
  593. VkMemoryPropertyFlags flags = directlyMappable ?
  594. (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) : // Note: Try using cached memory
  595. VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
  596. VkDevice vkDevice = device.getLogical();
  597. mImageCI.format = VulkanUtility::getPixelFormat(format, mProperties.isHardwareGammaEnabled());;
  598. VkImage image;
  599. VkResult result = vkCreateImage(vkDevice, &mImageCI, gVulkanAllocator, &image);
  600. assert(result == VK_SUCCESS);
  601. VkMemoryRequirements memReqs;
  602. vkGetImageMemoryRequirements(vkDevice, image, &memReqs);
  603. VkDeviceMemory memory = device.allocateMemory(memReqs, flags);
  604. result = vkBindImageMemory(vkDevice, image, memory, 0);
  605. assert(result == VK_SUCCESS);
  606. return device.getResourceManager().create<VulkanImage>(image, memory, mImageCI.initialLayout, getProperties());
  607. }
  608. VulkanBuffer* VulkanTexture::createStaging(VulkanDevice& device, const PixelData& pixelData, bool readable)
  609. {
  610. VkBufferCreateInfo bufferCI;
  611. bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  612. bufferCI.pNext = nullptr;
  613. bufferCI.flags = 0;
  614. bufferCI.size = pixelData.getSize();
  615. bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  616. bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
  617. bufferCI.queueFamilyIndexCount = 0;
  618. bufferCI.pQueueFamilyIndices = nullptr;
  619. if (readable)
  620. bufferCI.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
  621. VkDevice vkDevice = device.getLogical();
  622. VkBuffer buffer;
  623. VkResult result = vkCreateBuffer(vkDevice, &bufferCI, gVulkanAllocator, &buffer);
  624. assert(result == VK_SUCCESS);
  625. VkMemoryRequirements memReqs;
  626. vkGetBufferMemoryRequirements(vkDevice, buffer, &memReqs);
  627. VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
  628. VkDeviceMemory memory = device.allocateMemory(memReqs, flags);
  629. result = vkBindBufferMemory(vkDevice, buffer, memory, 0);
  630. assert(result == VK_SUCCESS);
  631. VkBufferView view = VK_NULL_HANDLE;
  632. return device.getResourceManager().create<VulkanBuffer>(buffer, view, memory,
  633. pixelData.getRowPitch(), pixelData.getSlicePitch());
  634. }
  635. void VulkanTexture::copyImage(VulkanTransferBuffer* cb, VulkanImage* srcImage, VulkanImage* dstImage,
  636. VkImageLayout srcFinalLayout, VkImageLayout dstFinalLayout)
  637. {
  638. UINT32 numFaces = mProperties.getNumFaces();
  639. UINT32 numMipmaps = mProperties.getNumMipmaps() + 1;
  640. UINT32 mipWidth = mProperties.getWidth();
  641. UINT32 mipHeight = mProperties.getHeight();
  642. UINT32 mipDepth = mProperties.getDepth();
  643. VkImageCopy* imageRegions = bs_stack_alloc<VkImageCopy>(numMipmaps);
  644. for(UINT32 i = 0; i < numMipmaps; i++)
  645. {
  646. VkImageCopy& imageRegion = imageRegions[i];
  647. imageRegion.srcOffset = { 0, 0, 0 };
  648. imageRegion.dstOffset = { 0, 0, 0 };
  649. imageRegion.extent = { mipWidth, mipHeight, mipDepth };
  650. imageRegion.srcSubresource.baseArrayLayer = 0;
  651. imageRegion.srcSubresource.layerCount = numFaces;
  652. imageRegion.srcSubresource.mipLevel = i;
  653. imageRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  654. imageRegion.dstSubresource.baseArrayLayer = 0;
  655. imageRegion.dstSubresource.layerCount = numFaces;
  656. imageRegion.dstSubresource.mipLevel = i;
  657. imageRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  658. if (mipWidth != 1) mipWidth /= 2;
  659. if (mipHeight != 1) mipHeight /= 2;
  660. if (mipDepth != 1) mipDepth /= 2;
  661. }
  662. VkImageSubresourceRange range;
  663. range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  664. range.baseArrayLayer = 0;
  665. range.layerCount = numFaces;
  666. range.baseMipLevel = 0;
  667. range.levelCount = numMipmaps;
  668. VkImageLayout transferSrcLayout, transferDstLayout;
  669. if (mDirectlyMappable)
  670. {
  671. transferSrcLayout = VK_IMAGE_LAYOUT_GENERAL;
  672. transferDstLayout = VK_IMAGE_LAYOUT_GENERAL;
  673. }
  674. else
  675. {
  676. transferSrcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
  677. transferDstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  678. }
  679. // Transfer textures to a valid layout
  680. cb->setLayout(srcImage, range, VK_ACCESS_TRANSFER_READ_BIT, transferSrcLayout);
  681. cb->setLayout(dstImage, range, VK_ACCESS_TRANSFER_WRITE_BIT, transferDstLayout);
  682. vkCmdCopyImage(cb->getCB()->getHandle(), srcImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  683. dstImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, numMipmaps, imageRegions);
  684. // Transfer back to final layouts
  685. VkAccessFlags srcAccessMask = srcImage->getAccessFlags(srcFinalLayout);
  686. cb->setLayout(srcImage->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, srcAccessMask,
  687. transferSrcLayout, srcFinalLayout, range);
  688. VkAccessFlags dstAccessMask = dstImage->getAccessFlags(dstFinalLayout);
  689. cb->setLayout(dstImage->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask,
  690. transferDstLayout, dstFinalLayout, range);
  691. cb->getCB()->registerResource(srcImage, range, VulkanUseFlag::Read, ResourceUsage::Transfer);
  692. cb->getCB()->registerResource(dstImage, range, VulkanUseFlag::Write, ResourceUsage::Transfer);
  693. bs_stack_free(imageRegions);
  694. }
  695. void VulkanTexture::copyImpl(const SPtr<Texture>& target, const TEXTURE_COPY_DESC& desc,
  696. const SPtr<CommandBuffer>& commandBuffer)
  697. {
  698. VulkanTexture* other = static_cast<VulkanTexture*>(target.get());
  699. const TextureProperties& srcProps = mProperties;
  700. const TextureProperties& dstProps = other->getProperties();
  701. bool srcHasMultisample = srcProps.getNumSamples() > 1;
  702. bool destHasMultisample = dstProps.getNumSamples() > 1;
  703. if ((srcProps.getUsage() & TU_DEPTHSTENCIL) != 0 || (dstProps.getUsage() & TU_DEPTHSTENCIL) != 0)
  704. {
  705. LOGERR("Texture copy/resolve isn't supported for depth-stencil textures.");
  706. return;
  707. }
  708. bool needsResolve = srcHasMultisample && !destHasMultisample;
  709. bool isMSCopy = srcHasMultisample || destHasMultisample;
  710. if (!needsResolve && isMSCopy)
  711. {
  712. if (srcProps.getNumSamples() != dstProps.getNumSamples())
  713. {
  714. LOGERR("When copying textures their multisample counts must match. Ignoring copy.");
  715. return;
  716. }
  717. }
  718. VkImageLayout transferSrcLayout = mDirectlyMappable ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
  719. VkImageLayout transferDstLayout = other->mDirectlyMappable ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  720. UINT32 mipWidth, mipHeight, mipDepth;
  721. bool copyEntireSurface = desc.srcVolume.getWidth() == 0 ||
  722. desc.srcVolume.getHeight() == 0 ||
  723. desc.srcVolume.getDepth() == 0;
  724. if(copyEntireSurface)
  725. {
  726. PixelUtil::getSizeForMipLevel(
  727. srcProps.getWidth(),
  728. srcProps.getHeight(),
  729. srcProps.getDepth(),
  730. desc.srcMip,
  731. mipWidth,
  732. mipHeight,
  733. mipDepth);
  734. }
  735. else
  736. {
  737. mipWidth = desc.srcVolume.getWidth();
  738. mipHeight = desc.srcVolume.getHeight();
  739. mipDepth = desc.srcVolume.getDepth();
  740. }
  741. VkImageResolve resolveRegion;
  742. resolveRegion.srcOffset = { (INT32)desc.srcVolume.left, (INT32)desc.srcVolume.top, (INT32)desc.srcVolume.front };
  743. resolveRegion.dstOffset = { desc.dstPosition.x, desc.dstPosition.y, desc.dstPosition.z };
  744. resolveRegion.extent = { mipWidth, mipHeight, mipDepth };
  745. resolveRegion.srcSubresource.baseArrayLayer = desc.srcFace;
  746. resolveRegion.srcSubresource.layerCount = 1;
  747. resolveRegion.srcSubresource.mipLevel = desc.srcMip;
  748. resolveRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  749. resolveRegion.dstSubresource.baseArrayLayer = desc.dstFace;
  750. resolveRegion.dstSubresource.layerCount = 1;
  751. resolveRegion.dstSubresource.mipLevel = desc.dstMip;
  752. resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  753. VkImageCopy imageRegion;
  754. imageRegion.srcOffset = { (INT32)desc.srcVolume.left, (INT32)desc.srcVolume.top, (INT32)desc.srcVolume.front };
  755. imageRegion.dstOffset = { desc.dstPosition.x, desc.dstPosition.y, desc.dstPosition.z };
  756. imageRegion.extent = { mipWidth, mipHeight, mipDepth };
  757. imageRegion.srcSubresource.baseArrayLayer = desc.srcFace;
  758. imageRegion.srcSubresource.layerCount = 1;
  759. imageRegion.srcSubresource.mipLevel = desc.srcMip;
  760. imageRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  761. imageRegion.dstSubresource.baseArrayLayer = desc.dstFace;
  762. imageRegion.dstSubresource.layerCount = 1;
  763. imageRegion.dstSubresource.mipLevel = desc.dstMip;
  764. imageRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  765. VkImageSubresourceRange srcRange;
  766. srcRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  767. srcRange.baseArrayLayer = desc.srcFace;
  768. srcRange.layerCount = 1;
  769. srcRange.baseMipLevel = desc.srcMip;
  770. srcRange.levelCount = 1;
  771. VkImageSubresourceRange dstRange;
  772. dstRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  773. dstRange.baseArrayLayer = desc.dstFace;
  774. dstRange.layerCount = 1;
  775. dstRange.baseMipLevel = desc.dstMip;
  776. dstRange.levelCount = 1;
  777. VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance());
  778. VulkanCmdBuffer* vkCB;
  779. if (commandBuffer != nullptr)
  780. vkCB = static_cast<VulkanCommandBuffer*>(commandBuffer.get())->getInternal();
  781. else
  782. vkCB = rapi._getMainCommandBuffer()->getInternal();
  783. UINT32 deviceIdx = vkCB->getDeviceIdx();
  784. VulkanImage* srcImage = mImages[deviceIdx];
  785. VulkanImage* dstImage = other->getResource(deviceIdx);
  786. if (srcImage == nullptr || dstImage == nullptr)
  787. return;
  788. VkImageLayout srcLayout = vkCB->getCurrentLayout(srcImage, srcRange, false);
  789. VkImageLayout dstLayout = vkCB->getCurrentLayout(dstImage, dstRange, false);
  790. VkCommandBuffer vkCmdBuf = vkCB->getHandle();
  791. VkAccessFlags srcAccessMask = srcImage->getAccessFlags(srcLayout);
  792. VkAccessFlags dstAccessMask = dstImage->getAccessFlags(dstLayout);
  793. if (vkCB->isInRenderPass())
  794. vkCB->endRenderPass();
  795. // Transfer textures to a valid layout
  796. vkCB->setLayout(srcImage->getHandle(), srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcLayout,
  797. transferSrcLayout, srcRange);
  798. vkCB->setLayout(dstImage->getHandle(), dstAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT,
  799. dstLayout, transferDstLayout, dstRange);
  800. if (srcHasMultisample && !destHasMultisample) // Resolving from MS to non-MS texture
  801. {
  802. vkCmdResolveImage(vkCmdBuf, srcImage->getHandle(), transferSrcLayout, dstImage->getHandle(), transferDstLayout,
  803. 1, &resolveRegion);
  804. }
  805. else // Just a normal copy
  806. {
  807. vkCmdCopyImage(vkCmdBuf, srcImage->getHandle(), transferSrcLayout, dstImage->getHandle(), transferDstLayout,
  808. 1, &imageRegion);
  809. }
  810. // Transfer back to optimal layouts
  811. srcLayout = srcImage->getOptimalLayout();
  812. // Notify the command buffer that these resources are being used on it
  813. vkCB->registerResource(srcImage, srcRange, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VulkanUseFlag::Read, ResourceUsage::Transfer);
  814. vkCB->registerResource(dstImage, dstRange, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VulkanUseFlag::Write, ResourceUsage::Transfer);
  815. }
  816. PixelData VulkanTexture::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx,
  817. UINT32 queueIdx)
  818. {
  819. const TextureProperties& props = getProperties();
  820. if (props.getNumSamples() > 1)
  821. {
  822. LOGERR("Multisampled textures cannot be accessed from the CPU directly.");
  823. return PixelData();
  824. }
  825. #if BS_PROFILING_ENABLED
  826. if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
  827. {
  828. BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_Texture);
  829. }
  830. if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
  831. {
  832. BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
  833. }
  834. #endif
  835. UINT32 mipWidth = std::max(1u, props.getWidth() >> mipLevel);
  836. UINT32 mipHeight = std::max(1u, props.getHeight() >> mipLevel);
  837. UINT32 mipDepth = std::max(1u, props.getDepth() >> mipLevel);
  838. PixelData lockedArea(mipWidth, mipHeight, mipDepth, mInternalFormats[deviceIdx]);
  839. VulkanImage* image = mImages[deviceIdx];
  840. if (image == nullptr)
  841. return PixelData();
  842. mIsMapped = true;
  843. mMappedDeviceIdx = deviceIdx;
  844. mMappedGlobalQueueIdx = queueIdx;
  845. mMappedFace = face;
  846. mMappedMip = mipLevel;
  847. mMappedLockOptions = options;
  848. VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance());
  849. VulkanDevice& device = *rapi._getDevice(deviceIdx);
  850. VulkanCommandBufferManager& cbManager = gVulkanCBManager();
  851. GpuQueueType queueType;
  852. UINT32 localQueueIdx = CommandSyncMask::getQueueIdxAndType(queueIdx, queueType);
  853. VulkanImageSubresource* subresource = image->getSubresource(face, mipLevel);
  854. // If memory is host visible try mapping it directly
  855. if (mDirectlyMappable)
  856. {
  857. // Initially the texture will be in preinitialized layout, and it will transition to general layout on first
  858. // use in shader. No further transitions are allowed for directly mappable textures.
  859. assert(subresource->getLayout() == VK_IMAGE_LAYOUT_PREINITIALIZED ||
  860. subresource->getLayout() == VK_IMAGE_LAYOUT_GENERAL);
  861. // GPU should never be allowed to write to a directly mappable texture, since only linear tiling is supported
  862. // for direct mapping, and we don't support using it with either storage textures or render targets.
  863. assert(!mSupportsGPUWrites);
  864. // Check is the GPU currently reading from the image
  865. UINT32 useMask = subresource->getUseInfo(VulkanUseFlag::Read);
  866. bool isUsedOnGPU = useMask != 0;
  867. // We're safe to map directly since GPU isn't using the subresource
  868. if (!isUsedOnGPU)
  869. {
  870. // If some CB has an operation queued that will be using the current contents of the image, create a new
  871. // image so we don't modify the previous use of the image
  872. if (subresource->isBound())
  873. {
  874. VulkanImage* newImage = createImage(device, mInternalFormats[deviceIdx]);
  875. // Copy contents of the current image to the new one, unless caller explicitly specifies he doesn't
  876. // care about the current contents
  877. if (options != GBL_WRITE_ONLY_DISCARD)
  878. {
  879. VkMemoryRequirements memReqs;
  880. vkGetImageMemoryRequirements(device.getLogical(), image->getHandle(), &memReqs);
  881. UINT8* src = image->map(0, (UINT32)memReqs.size);
  882. UINT8* dst = newImage->map(0, (UINT32)memReqs.size);
  883. memcpy(dst, src, memReqs.size);
  884. image->unmap();
  885. newImage->unmap();
  886. }
  887. image->destroy();
  888. image = newImage;
  889. mImages[deviceIdx] = image;
  890. }
  891. image->map(face, mipLevel, lockedArea);
  892. return lockedArea;
  893. }
  894. // Caller guarantees he won't touch the same data as the GPU, so just map even though the GPU is using the
  895. // subresource
  896. if (options == GBL_WRITE_ONLY_NO_OVERWRITE)
  897. {
  898. image->map(face, mipLevel, lockedArea);
  899. return lockedArea;
  900. }
  901. // Caller doesn't care about buffer contents, so just discard the existing buffer and create a new one
  902. if (options == GBL_WRITE_ONLY_DISCARD)
  903. {
  904. // We need to discard the entire image, even though we're only writing to a single sub-resource
  905. image->destroy();
  906. image = createImage(device, mInternalFormats[deviceIdx]);
  907. mImages[deviceIdx] = image;
  908. image->map(face, mipLevel, lockedArea);
  909. return lockedArea;
  910. }
  911. // We need to read the buffer contents
  912. if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
  913. {
  914. VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(deviceIdx, queueType, localQueueIdx);
  915. // Ensure flush() will wait for all queues currently using to the texture (if any) to finish
  916. // If only reading, wait for all writes to complete, otherwise wait on both writes and reads
  917. if (options == GBL_READ_ONLY)
  918. useMask = subresource->getUseInfo(VulkanUseFlag::Write);
  919. else
  920. useMask = subresource->getUseInfo(VulkanUseFlag::Read | VulkanUseFlag::Write);
  921. transferCB->appendMask(useMask);
  922. // Submit the command buffer and wait until it finishes
  923. transferCB->flush(true);
  924. // If writing and some CB has an operation queued that will be using the current contents of the image,
  925. // create a new image so we don't modify the previous use of the image
  926. if (options == GBL_READ_WRITE && subresource->isBound())
  927. {
  928. VulkanImage* newImage = createImage(device, mInternalFormats[deviceIdx]);
  929. VkMemoryRequirements memReqs;
  930. vkGetImageMemoryRequirements(device.getLogical(), image->getHandle(), &memReqs);
  931. UINT8* src = image->map(0, (UINT32)memReqs.size);
  932. UINT8* dst = newImage->map(0, (UINT32)memReqs.size);
  933. memcpy(dst, src, memReqs.size);
  934. image->unmap();
  935. newImage->unmap();
  936. image->destroy();
  937. image = newImage;
  938. mImages[deviceIdx] = image;
  939. }
  940. image->map(face, mipLevel, lockedArea);
  941. return lockedArea;
  942. }
  943. // Otherwise, we're doing write only, in which case it's best to use the staging buffer to avoid waiting
  944. // and blocking, so fall through
  945. }
  946. // Can't use direct mapping, so use a staging buffer
  947. // We might need to copy the current contents of the image to the staging buffer. Even if the user doesn't plan on
  948. // reading, it is still required as we will eventually copy all of the contents back to the original image,
  949. // and we can't write potentially uninitialized data. The only exception is when the caller specifies the image
  950. // contents should be discarded in which he guarantees he will overwrite the entire locked area with his own
  951. // contents.
  952. bool needRead = options != GBL_WRITE_ONLY_DISCARD_RANGE && options != GBL_WRITE_ONLY_DISCARD;
  953. // Allocate a staging buffer
  954. mStagingBuffer = createStaging(device, lockedArea, needRead);
  955. if (needRead) // If reading, we need to copy the current contents of the image to the staging buffer
  956. {
  957. VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(deviceIdx, queueType, localQueueIdx);
  958. // Similar to above, if image supports GPU writes or is currently being written to, we need to wait on any
  959. // potential writes to complete
  960. UINT32 writeUseMask = subresource->getUseInfo(VulkanUseFlag::Write);
  961. if (mSupportsGPUWrites || writeUseMask != 0)
  962. {
  963. // Ensure flush() will wait for all queues currently writing to the image (if any) to finish
  964. transferCB->appendMask(writeUseMask);
  965. }
  966. VkImageSubresourceRange range;
  967. range.aspectMask = image->getAspectFlags();
  968. range.baseArrayLayer = face;
  969. range.layerCount = 1;
  970. range.baseMipLevel = mipLevel;
  971. range.levelCount = 1;
  972. VkImageSubresourceLayers rangeLayers;
  973. if ((props.getUsage() & TU_DEPTHSTENCIL) != 0)
  974. rangeLayers.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
  975. else
  976. rangeLayers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  977. rangeLayers.baseArrayLayer = range.baseArrayLayer;
  978. rangeLayers.layerCount = range.layerCount;
  979. rangeLayers.mipLevel = range.baseMipLevel;
  980. VkExtent3D extent;
  981. PixelUtil::getSizeForMipLevel(props.getWidth(), props.getHeight(), props.getDepth(), mMappedMip,
  982. extent.width, extent.height, extent.depth);
  983. // Transfer texture to a valid layout
  984. VkAccessFlags currentAccessMask = image->getAccessFlags(subresource->getLayout());
  985. transferCB->setLayout(image->getHandle(), currentAccessMask, VK_ACCESS_TRANSFER_READ_BIT, subresource->getLayout(),
  986. VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, range);
  987. // Queue copy command
  988. image->copy(transferCB, mStagingBuffer, extent, rangeLayers, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
  989. // Transfer back to original layout
  990. VkImageLayout dstLayout = image->getOptimalLayout();
  991. currentAccessMask = image->getAccessFlags(dstLayout);
  992. transferCB->setLayout(image->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, currentAccessMask,
  993. VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstLayout, range);
  994. transferCB->getCB()->registerResource(image, range, VulkanUseFlag::Read, ResourceUsage::Transfer);
  995. // Ensure data written to the staging buffer is visible
  996. VkAccessFlags stagingAccessFlags;
  997. if (options == GBL_READ_ONLY)
  998. stagingAccessFlags = VK_ACCESS_HOST_READ_BIT;
  999. else // Must be read/write
  1000. stagingAccessFlags = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT;
  1001. transferCB->memoryBarrier(mStagingBuffer->getHandle(),
  1002. VK_ACCESS_TRANSFER_WRITE_BIT,
  1003. stagingAccessFlags,
  1004. VK_PIPELINE_STAGE_TRANSFER_BIT,
  1005. VK_PIPELINE_STAGE_HOST_BIT);
  1006. // Submit the command buffer and wait until it finishes
  1007. transferCB->flush(true);
  1008. }
  1009. UINT8* data = mStagingBuffer->map(0, lockedArea.getSize());
  1010. lockedArea.setExternalBuffer(data);
  1011. return lockedArea;
  1012. }
  1013. void VulkanTexture::unlockImpl()
  1014. {
  1015. // Possibly map() failed with some error
  1016. if (!mIsMapped)
  1017. return;
  1018. // Note: If we did any writes they need to be made visible to the GPU. However there is no need to execute
  1019. // a pipeline barrier because (as per spec) host writes are implicitly visible to the device.
  1020. if (mStagingBuffer == nullptr)
  1021. mImages[mMappedDeviceIdx]->unmap();
  1022. else
  1023. {
  1024. mStagingBuffer->unmap();
  1025. bool isWrite = mMappedLockOptions != GBL_READ_ONLY;
  1026. // We the caller wrote anything to the staging buffer, we need to upload it back to the main buffer
  1027. if (isWrite)
  1028. {
  1029. VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance());
  1030. VulkanDevice& device = *rapi._getDevice(mMappedDeviceIdx);
  1031. VulkanCommandBufferManager& cbManager = gVulkanCBManager();
  1032. GpuQueueType queueType;
  1033. UINT32 localQueueIdx = CommandSyncMask::getQueueIdxAndType(mMappedGlobalQueueIdx, queueType);
  1034. VulkanImage* image = mImages[mMappedDeviceIdx];
  1035. VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(mMappedDeviceIdx, queueType, localQueueIdx);
  1036. VulkanImageSubresource* subresource = image->getSubresource(mMappedFace, mMappedMip);
  1037. VkImageLayout curLayout = subresource->getLayout();
  1038. // If the subresource is used in any way on the GPU, we need to wait for that use to finish before
  1039. // we issue our copy
  1040. UINT32 useMask = subresource->getUseInfo(VulkanUseFlag::Read | VulkanUseFlag::Write);
  1041. bool isNormalWrite = false;
  1042. if (useMask != 0) // Subresource is currently used on the GPU
  1043. {
  1044. // Try to avoid the wait by checking for special write conditions
  1045. // Caller guarantees he won't touch the same data as the GPU, so just copy
  1046. if (mMappedLockOptions == GBL_WRITE_ONLY_NO_OVERWRITE)
  1047. {
  1048. // Fall through to copy()
  1049. }
  1050. // Caller doesn't care about buffer contents, so just discard the existing buffer and create a new one
  1051. else if (mMappedLockOptions == GBL_WRITE_ONLY_DISCARD)
  1052. {
  1053. // We need to discard the entire image, even though we're only writing to a single sub-resource
  1054. image->destroy();
  1055. image = createImage(device, mInternalFormats[mMappedDeviceIdx]);
  1056. mImages[mMappedDeviceIdx] = image;
  1057. subresource = image->getSubresource(mMappedFace, mMappedMip);
  1058. }
  1059. else // Otherwise we have no choice but to issue a dependency between the queues
  1060. {
  1061. transferCB->appendMask(useMask);
  1062. isNormalWrite = true;
  1063. }
  1064. }
  1065. else
  1066. isNormalWrite = true;
  1067. const TextureProperties& props = getProperties();
  1068. // Check if the subresource will still be bound somewhere after the CBs using it finish
  1069. if (isNormalWrite)
  1070. {
  1071. UINT32 useCount = subresource->getUseCount();
  1072. UINT32 boundCount = subresource->getBoundCount();
  1073. bool isBoundWithoutUse = boundCount > useCount;
  1074. // If image is queued for some operation on a CB, then we need to make a copy of the subresource to
  1075. // avoid modifying its use in the previous operation
  1076. if (isBoundWithoutUse)
  1077. {
  1078. VulkanImage* newImage = createImage(device, mInternalFormats[mMappedDeviceIdx]);
  1079. // Avoid copying original contents if the image only has one sub-resource, which we'll overwrite anyway
  1080. if (props.getNumMipmaps() > 0 || props.getNumFaces() > 1)
  1081. {
  1082. VkImageLayout oldImgLayout = image->getOptimalLayout();
  1083. curLayout = newImage->getOptimalLayout();
  1084. copyImage(transferCB, image, newImage, oldImgLayout, curLayout);
  1085. }
  1086. image->destroy();
  1087. image = newImage;
  1088. mImages[mMappedDeviceIdx] = image;
  1089. }
  1090. }
  1091. VkImageSubresourceRange range;
  1092. range.aspectMask = image->getAspectFlags();
  1093. range.baseArrayLayer = mMappedFace;
  1094. range.layerCount = 1;
  1095. range.baseMipLevel = mMappedMip;
  1096. range.levelCount = 1;
  1097. VkImageSubresourceLayers rangeLayers;
  1098. rangeLayers.aspectMask = range.aspectMask;
  1099. rangeLayers.baseArrayLayer = range.baseArrayLayer;
  1100. rangeLayers.layerCount = range.layerCount;
  1101. rangeLayers.mipLevel = range.baseMipLevel;
  1102. VkExtent3D extent;
  1103. PixelUtil::getSizeForMipLevel(props.getWidth(), props.getHeight(), props.getDepth(), mMappedMip,
  1104. extent.width, extent.height, extent.depth);
  1105. VkImageLayout transferLayout;
  1106. if (mDirectlyMappable)
  1107. transferLayout = VK_IMAGE_LAYOUT_GENERAL;
  1108. else
  1109. transferLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  1110. // Transfer texture to a valid layout
  1111. VkAccessFlags currentAccessMask = image->getAccessFlags(curLayout);
  1112. transferCB->setLayout(image->getHandle(), currentAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT,
  1113. curLayout, transferLayout, range);
  1114. // Queue copy command
  1115. mStagingBuffer->copy(transferCB->getCB(), image, extent, rangeLayers, transferLayout);
  1116. // Transfer back to original (or optimal if initial layout was undefined/preinitialized)
  1117. VkImageLayout dstLayout = image->getOptimalLayout();
  1118. currentAccessMask = image->getAccessFlags(dstLayout);
  1119. transferCB->setLayout(image->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, currentAccessMask,
  1120. transferLayout, dstLayout, range);
  1121. // Notify the command buffer that these resources are being used on it
  1122. transferCB->getCB()->registerResource(mStagingBuffer, VK_ACCESS_TRANSFER_READ_BIT, VulkanUseFlag::Read);
  1123. transferCB->getCB()->registerResource(image, range, VulkanUseFlag::Write, ResourceUsage::Transfer);
  1124. // We don't actually flush the transfer buffer here since it's an expensive operation, but it's instead
  1125. // done automatically before next "normal" command buffer submission.
  1126. }
  1127. mStagingBuffer->destroy();
  1128. mStagingBuffer = nullptr;
  1129. }
  1130. mIsMapped = false;
  1131. }
  1132. void VulkanTexture::readDataImpl(PixelData& dest, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx, UINT32 queueIdx)
  1133. {
  1134. if (mProperties.getNumSamples() > 1)
  1135. {
  1136. LOGERR("Multisampled textures cannot be accessed from the CPU directly.");
  1137. return;
  1138. }
  1139. PixelData myData = lock(GBL_READ_ONLY, mipLevel, face, deviceIdx, queueIdx);
  1140. PixelUtil::bulkPixelConversion(myData, dest);
  1141. unlock();
  1142. BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_Texture);
  1143. }
  1144. void VulkanTexture::writeDataImpl(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer,
  1145. UINT32 queueIdx)
  1146. {
  1147. if (mProperties.getNumSamples() > 1)
  1148. {
  1149. LOGERR("Multisampled textures cannot be accessed from the CPU directly.");
  1150. return;
  1151. }
  1152. mipLevel = Math::clamp(mipLevel, (UINT32)mipLevel, mProperties.getNumMipmaps());
  1153. face = Math::clamp(face, (UINT32)0, mProperties.getNumFaces() - 1);
  1154. if (face > 0 && mProperties.getTextureType() == TEX_TYPE_3D)
  1155. {
  1156. LOGERR("3D texture arrays are not supported.");
  1157. return;
  1158. }
  1159. // Write to every device
  1160. for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  1161. {
  1162. if (mImages[i] == nullptr)
  1163. continue;
  1164. PixelData myData = lock(discardWholeBuffer ? GBL_WRITE_ONLY_DISCARD : GBL_WRITE_ONLY_DISCARD_RANGE,
  1165. mipLevel, face, i, queueIdx);
  1166. PixelUtil::bulkPixelConversion(src, myData);
  1167. unlock();
  1168. }
  1169. BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
  1170. }
  1171. }}