BsVulkanTexture.cpp 48 KB

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