BsVulkanTexture.cpp 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452
  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 "BsVulkanCommandBufferManager.h"
  8. #include "BsVulkanHardwareBuffer.h"
  9. #include "BsCoreThread.h"
  10. #include "BsRenderStats.h"
  11. #include "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. , mOwnsImage(ownsImage), mNumFaces(desc.numFaces), mNumMipLevels(desc.numMipLevels), mUsage(desc.usage)
  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.arraySlice == entry.surface.arraySlice &&
  119. surface.numArraySlices == entry.surface.numArraySlices)
  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.numArraySlices == 1)
  152. mImageViewCI.viewType = VK_IMAGE_VIEW_TYPE_2D;
  153. else if(surface.numArraySlices % 6 == 0)
  154. {
  155. if(surface.numArraySlices > 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.numArraySlices > 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.numArraySlices > 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.arraySlice;
  177. mImageViewCI.subresourceRange.layerCount = surface.numArraySlices == 0 ? VK_REMAINING_ARRAY_LAYERS : surface.numArraySlices;
  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.arraySlice;
  227. range.layerCount = surface.numArraySlices == 0 ? mNumFaces : surface.numArraySlices;
  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. accessFlags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT;
  319. break;
  320. case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
  321. accessFlags = VK_ACCESS_SHADER_READ_BIT;
  322. break;
  323. case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
  324. accessFlags = VK_ACCESS_MEMORY_READ_BIT;
  325. break;
  326. case VK_IMAGE_LAYOUT_UNDEFINED:
  327. case VK_IMAGE_LAYOUT_PREINITIALIZED:
  328. accessFlags = 0;
  329. break;
  330. default:
  331. accessFlags = 0;
  332. LOGWRN("Unsupported source layout for Vulkan image.");
  333. break;
  334. }
  335. return accessFlags;
  336. }
  337. void VulkanImage::getBarriers(const VkImageSubresourceRange& range, Vector<VkImageMemoryBarrier>& barriers)
  338. {
  339. UINT32 numSubresources = range.levelCount * range.layerCount;
  340. // Nothing to do
  341. if (numSubresources == 0)
  342. return;
  343. UINT32 mip = range.baseMipLevel;
  344. UINT32 face = range.baseArrayLayer;
  345. UINT32 lastMip = range.baseMipLevel + range.levelCount - 1;
  346. UINT32 lastFace = range.baseArrayLayer + range.layerCount - 1;
  347. VkImageMemoryBarrier defaultBarrier;
  348. defaultBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  349. defaultBarrier.pNext = nullptr;
  350. defaultBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  351. defaultBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  352. defaultBarrier.image = getHandle();
  353. defaultBarrier.subresourceRange.aspectMask = range.aspectMask;
  354. defaultBarrier.subresourceRange.layerCount = 1;
  355. defaultBarrier.subresourceRange.levelCount = 1;
  356. defaultBarrier.subresourceRange.baseArrayLayer = 0;
  357. defaultBarrier.subresourceRange.baseMipLevel = 0;
  358. auto addNewBarrier = [&](VulkanImageSubresource* subresource, UINT32 face, UINT32 mip)
  359. {
  360. barriers.push_back(defaultBarrier);
  361. VkImageMemoryBarrier* barrier = &barriers.back();
  362. barrier->subresourceRange.baseArrayLayer = face;
  363. barrier->subresourceRange.baseMipLevel = mip;
  364. barrier->srcAccessMask = getAccessFlags(subresource->getLayout());
  365. barrier->oldLayout = subresource->getLayout();
  366. return barrier;
  367. };
  368. bs_frame_mark();
  369. {
  370. FrameVector<bool> processed(numSubresources, false);
  371. // Add first subresource
  372. VulkanImageSubresource* subresource = getSubresource(face, mip);
  373. addNewBarrier(subresource, face, mip);
  374. numSubresources--;
  375. processed[0] = true;
  376. while (numSubresources > 0)
  377. {
  378. // Try to expand the barrier as much as possible
  379. VkImageMemoryBarrier* barrier = &barriers.back();
  380. while (true)
  381. {
  382. // Expand by one in the X direction
  383. bool expandedFace = true;
  384. if (face < lastFace)
  385. {
  386. for (UINT32 i = 0; i < barrier->subresourceRange.levelCount; i++)
  387. {
  388. UINT32 curMip = barrier->subresourceRange.baseMipLevel + i;
  389. VulkanImageSubresource* subresource = getSubresource(face + 1, curMip);
  390. if (barrier->oldLayout != subresource->getLayout())
  391. {
  392. expandedFace = false;
  393. break;
  394. }
  395. }
  396. if (expandedFace)
  397. {
  398. barrier->subresourceRange.layerCount++;
  399. numSubresources -= barrier->subresourceRange.levelCount;
  400. face++;
  401. for (UINT32 i = 0; i < barrier->subresourceRange.levelCount; i++)
  402. {
  403. UINT32 idx = i * range.layerCount + (face - range.baseArrayLayer);
  404. processed[idx] = true;
  405. }
  406. }
  407. }
  408. else
  409. expandedFace = false;
  410. // Expand by one in the Y direction
  411. bool expandedMip = true;
  412. if (mip < lastMip)
  413. {
  414. for (UINT32 i = 0; i < barrier->subresourceRange.layerCount; i++)
  415. {
  416. UINT32 curFace = barrier->subresourceRange.baseArrayLayer + i;
  417. VulkanImageSubresource* subresource = getSubresource(curFace, mip + 1);
  418. if (barrier->oldLayout != subresource->getLayout())
  419. {
  420. expandedMip = false;
  421. break;
  422. }
  423. }
  424. if (expandedMip)
  425. {
  426. barrier->subresourceRange.levelCount++;
  427. numSubresources -= barrier->subresourceRange.layerCount;
  428. mip++;
  429. for (UINT32 i = 0; i < barrier->subresourceRange.layerCount; i++)
  430. {
  431. UINT32 idx = (mip - range.baseMipLevel) * range.layerCount + i;
  432. processed[idx] = true;
  433. }
  434. }
  435. }
  436. else
  437. expandedMip = false;
  438. // If we can't grow no more, we're done with this square
  439. if (!expandedMip && !expandedFace)
  440. break;
  441. }
  442. // Look for a new starting point (sub-resource we haven't processed yet)
  443. for (UINT32 i = 0; i < range.levelCount; i++)
  444. {
  445. bool found = false;
  446. for (UINT32 j = 0; j < range.layerCount; j++)
  447. {
  448. UINT32 idx = i * range.layerCount + j;
  449. if (!processed[idx])
  450. {
  451. mip = range.baseMipLevel + i;
  452. face = range.baseArrayLayer + j;
  453. found = true;
  454. break;
  455. }
  456. }
  457. if (found)
  458. {
  459. VulkanImageSubresource* subresource = getSubresource(face, mip);
  460. addNewBarrier(subresource, face, mip);
  461. numSubresources--;
  462. break;
  463. }
  464. }
  465. }
  466. }
  467. bs_frame_clear();
  468. }
  469. VulkanImageSubresource::VulkanImageSubresource(VulkanResourceManager* owner, VkImageLayout layout)
  470. :VulkanResource(owner, false), mLayout(layout)
  471. { }
  472. VulkanTexture::VulkanTexture(const TEXTURE_DESC& desc, const SPtr<PixelData>& initialData,
  473. GpuDeviceFlags deviceMask)
  474. : Texture(desc, initialData, deviceMask), mImages(), mDeviceMask(deviceMask), mStagingBuffer(nullptr)
  475. , mMappedDeviceIdx(-1), mMappedGlobalQueueIdx(-1), mMappedMip(0), mMappedFace(0), mMappedRowPitch(false)
  476. , mMappedSlicePitch(false), mMappedLockOptions(GBL_WRITE_ONLY), mInternalFormats()
  477. , mDirectlyMappable(false), mSupportsGPUWrites(false), mIsMapped(false)
  478. {
  479. }
  480. VulkanTexture::~VulkanTexture()
  481. {
  482. for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  483. {
  484. if (mImages[i] == nullptr)
  485. return;
  486. mImages[i]->destroy();
  487. }
  488. assert(mStagingBuffer == nullptr);
  489. BS_INC_RENDER_STAT_CAT(ResDestroyed, RenderStatObject_Texture);
  490. }
  491. void VulkanTexture::initialize()
  492. {
  493. THROW_IF_NOT_CORE_THREAD;
  494. const TextureProperties& props = mProperties;
  495. mImageCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
  496. mImageCI.pNext = nullptr;
  497. mImageCI.flags = 0;
  498. TextureType texType = props.getTextureType();
  499. switch(texType)
  500. {
  501. case TEX_TYPE_1D:
  502. mImageCI.imageType = VK_IMAGE_TYPE_1D;
  503. break;
  504. case TEX_TYPE_2D:
  505. mImageCI.imageType = VK_IMAGE_TYPE_2D;
  506. break;
  507. case TEX_TYPE_3D:
  508. mImageCI.imageType = VK_IMAGE_TYPE_3D;
  509. break;
  510. case TEX_TYPE_CUBE_MAP:
  511. mImageCI.imageType = VK_IMAGE_TYPE_2D;
  512. mImageCI.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
  513. break;
  514. }
  515. // Note: I force rendertarget and depthstencil types to be readable in shader. Depending on performance impact
  516. // it might be beneficial to allow the user to enable this explicitly only when needed.
  517. mImageCI.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
  518. int usage = props.getUsage();
  519. if ((usage & TU_RENDERTARGET) != 0)
  520. {
  521. mImageCI.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
  522. mSupportsGPUWrites = true;
  523. }
  524. else if ((usage & TU_DEPTHSTENCIL) != 0)
  525. {
  526. mImageCI.usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
  527. mSupportsGPUWrites = true;
  528. }
  529. else
  530. mImageCI.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
  531. if ((usage & TU_LOADSTORE) != 0)
  532. {
  533. mImageCI.usage |= VK_IMAGE_USAGE_STORAGE_BIT;
  534. mSupportsGPUWrites = true;
  535. }
  536. VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
  537. VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED;
  538. if ((usage & TU_DYNAMIC) != 0) // Attempt to use linear tiling for dynamic textures, so we can directly map and modify them
  539. {
  540. // Only support 2D textures, with one sample and one mip level, only used for shader reads
  541. // (Optionally check vkGetPhysicalDeviceFormatProperties & vkGetPhysicalDeviceImageFormatProperties for
  542. // additional supported configs, but right now there doesn't seem to be any additional support)
  543. if(texType == TEX_TYPE_2D && props.getNumSamples() <= 1 && props.getNumMipmaps() == 0 &&
  544. props.getNumFaces() == 1 && (mImageCI.usage & VK_IMAGE_USAGE_SAMPLED_BIT) != 0)
  545. {
  546. // Also, only support normal textures, not render targets or storage textures
  547. if (!mSupportsGPUWrites)
  548. {
  549. mDirectlyMappable = true;
  550. tiling = VK_IMAGE_TILING_LINEAR;
  551. layout = VK_IMAGE_LAYOUT_PREINITIALIZED;
  552. }
  553. }
  554. }
  555. mImageCI.extent = { props.getWidth(), props.getHeight(), props.getDepth() };
  556. mImageCI.mipLevels = props.getNumMipmaps() + 1;
  557. mImageCI.arrayLayers = props.getNumFaces();
  558. mImageCI.samples = VulkanUtility::getSampleFlags(props.getNumSamples());
  559. mImageCI.tiling = tiling;
  560. mImageCI.initialLayout = layout;
  561. mImageCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  562. mImageCI.queueFamilyIndexCount = 0;
  563. mImageCI.pQueueFamilyIndices = nullptr;
  564. VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance());
  565. VulkanDevice* devices[BS_MAX_DEVICES];
  566. VulkanUtility::getDevices(rapi, mDeviceMask, devices);
  567. // Allocate buffers per-device
  568. for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  569. {
  570. if (devices[i] == nullptr)
  571. continue;
  572. bool optimalTiling = tiling == VK_IMAGE_TILING_OPTIMAL;
  573. mInternalFormats[i] = VulkanUtility::getClosestSupportedPixelFormat(
  574. *devices[i], props.getFormat(), props.getTextureType(), props.getUsage(), optimalTiling,
  575. props.isHardwareGammaEnabled());
  576. mImages[i] = createImage(*devices[i], mInternalFormats[i]);
  577. }
  578. BS_INC_RENDER_STAT_CAT(ResCreated, RenderStatObject_Texture);
  579. Texture::initialize();
  580. }
  581. VulkanImage* VulkanTexture::createImage(VulkanDevice& device, PixelFormat format)
  582. {
  583. bool directlyMappable = mImageCI.tiling == VK_IMAGE_TILING_LINEAR;
  584. VkMemoryPropertyFlags flags = directlyMappable ?
  585. (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) : // Note: Try using cached memory
  586. VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
  587. VkDevice vkDevice = device.getLogical();
  588. mImageCI.format = VulkanUtility::getPixelFormat(format, mProperties.isHardwareGammaEnabled());;
  589. VkImage image;
  590. VkResult result = vkCreateImage(vkDevice, &mImageCI, gVulkanAllocator, &image);
  591. assert(result == VK_SUCCESS);
  592. VkMemoryRequirements memReqs;
  593. vkGetImageMemoryRequirements(vkDevice, image, &memReqs);
  594. VkDeviceMemory memory = device.allocateMemory(memReqs, flags);
  595. result = vkBindImageMemory(vkDevice, image, memory, 0);
  596. assert(result == VK_SUCCESS);
  597. return device.getResourceManager().create<VulkanImage>(image, memory, mImageCI.initialLayout, getProperties());
  598. }
  599. VulkanBuffer* VulkanTexture::createStaging(VulkanDevice& device, const PixelData& pixelData, bool readable)
  600. {
  601. VkBufferCreateInfo bufferCI;
  602. bufferCI.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
  603. bufferCI.pNext = nullptr;
  604. bufferCI.flags = 0;
  605. bufferCI.size = pixelData.getSize();
  606. bufferCI.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
  607. bufferCI.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
  608. bufferCI.queueFamilyIndexCount = 0;
  609. bufferCI.pQueueFamilyIndices = nullptr;
  610. if (readable)
  611. bufferCI.usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT;
  612. VkDevice vkDevice = device.getLogical();
  613. VkBuffer buffer;
  614. VkResult result = vkCreateBuffer(vkDevice, &bufferCI, gVulkanAllocator, &buffer);
  615. assert(result == VK_SUCCESS);
  616. VkMemoryRequirements memReqs;
  617. vkGetBufferMemoryRequirements(vkDevice, buffer, &memReqs);
  618. VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
  619. VkDeviceMemory memory = device.allocateMemory(memReqs, flags);
  620. result = vkBindBufferMemory(vkDevice, buffer, memory, 0);
  621. assert(result == VK_SUCCESS);
  622. VkBufferView view = VK_NULL_HANDLE;
  623. return device.getResourceManager().create<VulkanBuffer>(buffer, view, memory,
  624. pixelData.getRowPitch(), pixelData.getSlicePitch());
  625. }
  626. void VulkanTexture::copyImage(VulkanTransferBuffer* cb, VulkanImage* srcImage, VulkanImage* dstImage,
  627. VkImageLayout srcFinalLayout, VkImageLayout dstFinalLayout)
  628. {
  629. UINT32 numFaces = mProperties.getNumFaces();
  630. UINT32 numMipmaps = mProperties.getNumMipmaps() + 1;
  631. UINT32 mipWidth = mProperties.getWidth();
  632. UINT32 mipHeight = mProperties.getHeight();
  633. UINT32 mipDepth = mProperties.getDepth();
  634. VkImageCopy* imageRegions = bs_stack_alloc<VkImageCopy>(numMipmaps);
  635. for(UINT32 i = 0; i < numMipmaps; i++)
  636. {
  637. VkImageCopy& imageRegion = imageRegions[i];
  638. imageRegion.srcOffset = { 0, 0, 0 };
  639. imageRegion.dstOffset = { 0, 0, 0 };
  640. imageRegion.extent = { mipWidth, mipHeight, mipDepth };
  641. imageRegion.srcSubresource.baseArrayLayer = 0;
  642. imageRegion.srcSubresource.layerCount = numFaces;
  643. imageRegion.srcSubresource.mipLevel = i;
  644. imageRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  645. imageRegion.dstSubresource.baseArrayLayer = 0;
  646. imageRegion.dstSubresource.layerCount = numFaces;
  647. imageRegion.dstSubresource.mipLevel = i;
  648. imageRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  649. if (mipWidth != 1) mipWidth /= 2;
  650. if (mipHeight != 1) mipHeight /= 2;
  651. if (mipDepth != 1) mipDepth /= 2;
  652. }
  653. VkImageSubresourceRange range;
  654. range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  655. range.baseArrayLayer = 0;
  656. range.layerCount = numFaces;
  657. range.baseMipLevel = 0;
  658. range.levelCount = numMipmaps;
  659. VkImageLayout transferSrcLayout, transferDstLayout;
  660. if (mDirectlyMappable)
  661. {
  662. transferSrcLayout = VK_IMAGE_LAYOUT_GENERAL;
  663. transferDstLayout = VK_IMAGE_LAYOUT_GENERAL;
  664. }
  665. else
  666. {
  667. transferSrcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
  668. transferDstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  669. }
  670. // Transfer textures to a valid layout
  671. cb->setLayout(srcImage, range, VK_ACCESS_TRANSFER_READ_BIT, transferSrcLayout);
  672. cb->setLayout(dstImage, range, VK_ACCESS_TRANSFER_WRITE_BIT, transferDstLayout);
  673. vkCmdCopyImage(cb->getCB()->getHandle(), srcImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  674. dstImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, numMipmaps, imageRegions);
  675. // Transfer back to final layouts
  676. VkAccessFlags srcAccessMask = srcImage->getAccessFlags(srcFinalLayout);
  677. cb->setLayout(srcImage->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, srcAccessMask,
  678. transferSrcLayout, srcFinalLayout, range);
  679. VkAccessFlags dstAccessMask = dstImage->getAccessFlags(dstFinalLayout);
  680. cb->setLayout(dstImage->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask,
  681. transferDstLayout, dstFinalLayout, range);
  682. cb->getCB()->registerResource(srcImage, range, VulkanUseFlag::Read);
  683. cb->getCB()->registerResource(dstImage, range, VulkanUseFlag::Write);
  684. bs_stack_free(imageRegions);
  685. }
  686. void VulkanTexture::copyImpl(UINT32 srcFace, UINT32 srcMipLevel, UINT32 destFace, UINT32 destMipLevel,
  687. const SPtr<Texture>& target, UINT32 queueIdx)
  688. {
  689. VulkanTexture* other = static_cast<VulkanTexture*>(target.get());
  690. const TextureProperties& srcProps = mProperties;
  691. const TextureProperties& dstProps = other->getProperties();
  692. bool srcHasMultisample = srcProps.getNumSamples() > 1;
  693. bool destHasMultisample = dstProps.getNumSamples() > 1;
  694. if ((srcProps.getUsage() & TU_DEPTHSTENCIL) != 0 || (dstProps.getUsage() & TU_DEPTHSTENCIL) != 0)
  695. {
  696. LOGERR("Texture copy/resolve isn't supported for depth-stencil textures.");
  697. return;
  698. }
  699. bool needsResolve = srcHasMultisample && !destHasMultisample;
  700. bool isMSCopy = srcHasMultisample || destHasMultisample;
  701. if (!needsResolve && isMSCopy)
  702. {
  703. if (srcProps.getNumSamples() != dstProps.getNumSamples())
  704. {
  705. LOGERR("When copying textures their multisample counts must match. Ignoring copy.");
  706. return;
  707. }
  708. }
  709. VulkanCommandBufferManager& cbManager = gVulkanCBManager();
  710. GpuQueueType queueType;
  711. UINT32 localQueueIdx = CommandSyncMask::getQueueIdxAndType(queueIdx, queueType);
  712. VkImageLayout transferSrcLayout, transferDstLayout;
  713. if (mDirectlyMappable)
  714. {
  715. transferSrcLayout = VK_IMAGE_LAYOUT_GENERAL;
  716. transferDstLayout = VK_IMAGE_LAYOUT_GENERAL;
  717. }
  718. else
  719. {
  720. transferSrcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
  721. transferDstLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  722. }
  723. UINT32 mipWidth, mipHeight, mipDepth;
  724. PixelUtil::getSizeForMipLevel(srcProps.getWidth(), srcProps.getHeight(), srcProps.getDepth(), srcMipLevel,
  725. mipWidth, mipHeight, mipDepth);
  726. VkImageResolve resolveRegion;
  727. resolveRegion.srcOffset = { 0, 0, 0 };
  728. resolveRegion.dstOffset = { 0, 0, 0 };
  729. resolveRegion.extent = { mipWidth, mipHeight, mipDepth };
  730. resolveRegion.srcSubresource.baseArrayLayer = srcFace;
  731. resolveRegion.srcSubresource.layerCount = 1;
  732. resolveRegion.srcSubresource.mipLevel = srcMipLevel;
  733. resolveRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  734. resolveRegion.dstSubresource.baseArrayLayer = destFace;
  735. resolveRegion.dstSubresource.layerCount = 1;
  736. resolveRegion.dstSubresource.mipLevel = destMipLevel;
  737. resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  738. VkImageCopy imageRegion;
  739. imageRegion.srcOffset = { 0, 0, 0 };
  740. imageRegion.dstOffset = { 0, 0, 0 };
  741. imageRegion.extent = { mipWidth, mipHeight, mipDepth };
  742. imageRegion.srcSubresource.baseArrayLayer = srcFace;
  743. imageRegion.srcSubresource.layerCount = 1;
  744. imageRegion.srcSubresource.mipLevel = srcMipLevel;
  745. imageRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  746. imageRegion.dstSubresource.baseArrayLayer = destFace;
  747. imageRegion.dstSubresource.layerCount = 1;
  748. imageRegion.dstSubresource.mipLevel = destMipLevel;
  749. imageRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  750. VkImageSubresourceRange srcRange;
  751. srcRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  752. srcRange.baseArrayLayer = srcFace;
  753. srcRange.layerCount = 1;
  754. srcRange.baseMipLevel = srcMipLevel;
  755. srcRange.levelCount = 1;
  756. VkImageSubresourceRange dstRange;
  757. dstRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  758. dstRange.baseArrayLayer = destFace;
  759. dstRange.layerCount = 1;
  760. dstRange.baseMipLevel = destMipLevel;
  761. dstRange.levelCount = 1;
  762. VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance());
  763. for(UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  764. {
  765. VulkanDevice& device = *rapi._getDevice(i);
  766. VulkanImage* srcImage = mImages[i];
  767. VulkanImage* dstImage = other->getResource(i);
  768. if (srcImage == nullptr || dstImage == nullptr)
  769. continue;
  770. VulkanImageSubresource* srcSubresource = srcImage->getSubresource(srcFace, srcMipLevel);
  771. VulkanImageSubresource* dstSubresource = dstImage->getSubresource(destFace, destMipLevel);
  772. VkImageLayout srcLayout = srcSubresource->getLayout();
  773. VkImageLayout dstLayout = dstSubresource->getLayout();
  774. VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(i, queueType, localQueueIdx);
  775. VkCommandBuffer vkCmdBuf = transferCB->getCB()->getHandle();
  776. // If destination subresource is queued for some operation on a CB (ignoring the ones we're waiting for), then
  777. // we need to make a copy of the image to avoid modifying its use in the previous operation
  778. UINT32 useCount = dstImage->getUseCount();
  779. UINT32 boundCount = dstImage->getBoundCount();
  780. bool isBoundWithoutUse = boundCount > useCount;
  781. if (isBoundWithoutUse)
  782. {
  783. VulkanImage* newImage = createImage(device, mInternalFormats[i]);
  784. // Avoid copying original contents if the image only has one sub-resource, which we'll overwrite anyway
  785. if (dstProps.getNumMipmaps() > 0 || dstProps.getNumFaces() > 1)
  786. {
  787. VkImageLayout oldDstLayout = dstImage->getOptimalLayout();
  788. dstLayout = newImage->getOptimalLayout();
  789. copyImage(transferCB, dstImage, newImage, oldDstLayout, dstLayout);
  790. }
  791. dstImage->destroy();
  792. dstImage = newImage;
  793. mImages[i] = dstImage;
  794. }
  795. VkAccessFlags srcAccessMask = srcImage->getAccessFlags(srcLayout);
  796. VkAccessFlags dstAccessMask = dstImage->getAccessFlags(dstLayout);
  797. // Transfer textures to a valid layout
  798. transferCB->setLayout(srcImage->getHandle(), srcAccessMask, VK_ACCESS_TRANSFER_READ_BIT, srcLayout,
  799. transferSrcLayout, srcRange);
  800. transferCB->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(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  805. dstImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &resolveRegion);
  806. }
  807. else // Just a normal copy
  808. {
  809. vkCmdCopyImage(vkCmdBuf, srcImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
  810. dstImage->getHandle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageRegion);
  811. }
  812. // Transfer back to optimal layouts
  813. srcLayout = srcImage->getOptimalLayout();
  814. srcAccessMask = srcImage->getAccessFlags(srcLayout);
  815. transferCB->setLayout(srcImage->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, srcAccessMask,
  816. transferSrcLayout, srcLayout, srcRange);
  817. dstLayout = dstImage->getOptimalLayout();
  818. dstAccessMask = dstImage->getAccessFlags(dstLayout);
  819. transferCB->setLayout(dstImage->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, dstAccessMask,
  820. transferDstLayout, dstLayout, dstRange);
  821. // Notify the command buffer that these resources are being used on it
  822. transferCB->getCB()->registerResource(srcImage, srcRange, VulkanUseFlag::Read);
  823. transferCB->getCB()->registerResource(dstImage, dstRange, VulkanUseFlag::Write);
  824. // Need to wait if subresource we're reading from is being written, or if the subresource we're writing to is
  825. // being accessed in any way
  826. UINT32 srcUseFlags = srcSubresource->getUseInfo(VulkanUseFlag::Write);
  827. UINT32 dstUseFlags = dstSubresource->getUseInfo(VulkanUseFlag::Read | VulkanUseFlag::Write);
  828. transferCB->appendMask(srcUseFlags | dstUseFlags);
  829. }
  830. }
  831. PixelData VulkanTexture::lockImpl(GpuLockOptions options, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx,
  832. UINT32 queueIdx)
  833. {
  834. const TextureProperties& props = getProperties();
  835. if (props.getNumSamples() > 1)
  836. {
  837. LOGERR("Multisampled textures cannot be accessed from the CPU directly.");
  838. return PixelData();
  839. }
  840. #if BS_PROFILING_ENABLED
  841. if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
  842. {
  843. BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_Texture);
  844. }
  845. if (options == GBL_READ_WRITE || options == GBL_WRITE_ONLY || options == GBL_WRITE_ONLY_DISCARD || options == GBL_WRITE_ONLY_NO_OVERWRITE)
  846. {
  847. BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
  848. }
  849. #endif
  850. UINT32 mipWidth = std::max(1u, props.getWidth() >> mipLevel);
  851. UINT32 mipHeight = std::max(1u, props.getHeight() >> mipLevel);
  852. UINT32 mipDepth = std::max(1u, props.getDepth() >> mipLevel);
  853. PixelData lockedArea(mipWidth, mipHeight, mipDepth, mInternalFormats[deviceIdx]);
  854. VulkanImage* image = mImages[deviceIdx];
  855. if (image == nullptr)
  856. return PixelData();
  857. mIsMapped = true;
  858. mMappedDeviceIdx = deviceIdx;
  859. mMappedGlobalQueueIdx = queueIdx;
  860. mMappedFace = face;
  861. mMappedMip = mipLevel;
  862. mMappedLockOptions = options;
  863. VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance());
  864. VulkanDevice& device = *rapi._getDevice(deviceIdx);
  865. VulkanCommandBufferManager& cbManager = gVulkanCBManager();
  866. GpuQueueType queueType;
  867. UINT32 localQueueIdx = CommandSyncMask::getQueueIdxAndType(queueIdx, queueType);
  868. VulkanImageSubresource* subresource = image->getSubresource(face, mipLevel);
  869. // If memory is host visible try mapping it directly
  870. if (mDirectlyMappable)
  871. {
  872. // Initially the texture will be in preinitialized layout, and it will transition to general layout on first
  873. // use in shader. No further transitions are allowed for directly mappable textures.
  874. assert(subresource->getLayout() == VK_IMAGE_LAYOUT_PREINITIALIZED ||
  875. subresource->getLayout() == VK_IMAGE_LAYOUT_GENERAL);
  876. // GPU should never be allowed to write to a directly mappable texture, since only linear tiling is supported
  877. // for direct mapping, and we don't support using it with either storage textures or render targets.
  878. assert(!mSupportsGPUWrites);
  879. // Check is the GPU currently reading from the image
  880. UINT32 useMask = subresource->getUseInfo(VulkanUseFlag::Read);
  881. bool isUsedOnGPU = useMask != 0;
  882. // We're safe to map directly since GPU isn't using the subresource
  883. if (!isUsedOnGPU)
  884. {
  885. // If some CB has an operation queued that will be using the current contents of the image, create a new
  886. // image so we don't modify the previous use of the image
  887. if (subresource->isBound())
  888. {
  889. VulkanImage* newImage = createImage(device, mInternalFormats[deviceIdx]);
  890. // Copy contents of the current image to the new one, unless caller explicitly specifies he doesn't
  891. // care about the current contents
  892. if (options != GBL_WRITE_ONLY_DISCARD)
  893. {
  894. VkMemoryRequirements memReqs;
  895. vkGetImageMemoryRequirements(device.getLogical(), image->getHandle(), &memReqs);
  896. UINT8* src = image->map(0, (UINT32)memReqs.size);
  897. UINT8* dst = newImage->map(0, (UINT32)memReqs.size);
  898. memcpy(dst, src, memReqs.size);
  899. image->unmap();
  900. newImage->unmap();
  901. }
  902. image->destroy();
  903. image = newImage;
  904. mImages[deviceIdx] = image;
  905. }
  906. image->map(face, mipLevel, lockedArea);
  907. return lockedArea;
  908. }
  909. // Caller guarantees he won't touch the same data as the GPU, so just map even though the GPU is using the
  910. // subresource
  911. if (options == GBL_WRITE_ONLY_NO_OVERWRITE)
  912. {
  913. image->map(face, mipLevel, lockedArea);
  914. return lockedArea;
  915. }
  916. // Caller doesn't care about buffer contents, so just discard the existing buffer and create a new one
  917. if (options == GBL_WRITE_ONLY_DISCARD)
  918. {
  919. // We need to discard the entire image, even though we're only writing to a single sub-resource
  920. image->destroy();
  921. image = createImage(device, mInternalFormats[deviceIdx]);
  922. mImages[deviceIdx] = image;
  923. image->map(face, mipLevel, lockedArea);
  924. return lockedArea;
  925. }
  926. // We need to read the buffer contents
  927. if (options == GBL_READ_ONLY || options == GBL_READ_WRITE)
  928. {
  929. VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(deviceIdx, queueType, localQueueIdx);
  930. // Ensure flush() will wait for all queues currently using to the texture (if any) to finish
  931. // If only reading, wait for all writes to complete, otherwise wait on both writes and reads
  932. if (options == GBL_READ_ONLY)
  933. useMask = subresource->getUseInfo(VulkanUseFlag::Write);
  934. else
  935. useMask = subresource->getUseInfo(VulkanUseFlag::Read | VulkanUseFlag::Write);
  936. transferCB->appendMask(useMask);
  937. // Submit the command buffer and wait until it finishes
  938. transferCB->flush(true);
  939. // If writing and some CB has an operation queued that will be using the current contents of the image,
  940. // create a new image so we don't modify the previous use of the image
  941. if (options == GBL_READ_WRITE && subresource->isBound())
  942. {
  943. VulkanImage* newImage = createImage(device, mInternalFormats[deviceIdx]);
  944. VkMemoryRequirements memReqs;
  945. vkGetImageMemoryRequirements(device.getLogical(), image->getHandle(), &memReqs);
  946. UINT8* src = image->map(0, (UINT32)memReqs.size);
  947. UINT8* dst = newImage->map(0, (UINT32)memReqs.size);
  948. memcpy(dst, src, memReqs.size);
  949. image->unmap();
  950. newImage->unmap();
  951. image->destroy();
  952. image = newImage;
  953. mImages[deviceIdx] = image;
  954. }
  955. image->map(face, mipLevel, lockedArea);
  956. return lockedArea;
  957. }
  958. // Otherwise, we're doing write only, in which case it's best to use the staging buffer to avoid waiting
  959. // and blocking, so fall through
  960. }
  961. // Can't use direct mapping, so use a staging buffer
  962. // We might need to copy the current contents of the image to the staging buffer. Even if the user doesn't plan on
  963. // reading, it is still required as we will eventually copy all of the contents back to the original image,
  964. // and we can't write potentially uninitialized data. The only exception is when the caller specifies the image
  965. // contents should be discarded in which he guarantees he will overwrite the entire locked area with his own
  966. // contents.
  967. bool needRead = options != GBL_WRITE_ONLY_DISCARD_RANGE && options != GBL_WRITE_ONLY_DISCARD;
  968. // Allocate a staging buffer
  969. mStagingBuffer = createStaging(device, lockedArea, needRead);
  970. if (needRead) // If reading, we need to copy the current contents of the image to the staging buffer
  971. {
  972. VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(deviceIdx, queueType, localQueueIdx);
  973. // Similar to above, if image supports GPU writes or is currently being written to, we need to wait on any
  974. // potential writes to complete
  975. UINT32 writeUseMask = subresource->getUseInfo(VulkanUseFlag::Write);
  976. if (mSupportsGPUWrites || writeUseMask != 0)
  977. {
  978. // Ensure flush() will wait for all queues currently writing to the image (if any) to finish
  979. transferCB->appendMask(writeUseMask);
  980. }
  981. VkImageSubresourceRange range;
  982. range.aspectMask = image->getAspectFlags();
  983. range.baseArrayLayer = face;
  984. range.layerCount = 1;
  985. range.baseMipLevel = mipLevel;
  986. range.levelCount = 1;
  987. VkImageSubresourceLayers rangeLayers;
  988. if ((props.getUsage() & TU_DEPTHSTENCIL) != 0)
  989. rangeLayers.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
  990. else
  991. rangeLayers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  992. rangeLayers.baseArrayLayer = range.baseArrayLayer;
  993. rangeLayers.layerCount = range.layerCount;
  994. rangeLayers.mipLevel = range.baseMipLevel;
  995. VkExtent3D extent;
  996. PixelUtil::getSizeForMipLevel(props.getWidth(), props.getHeight(), props.getDepth(), mMappedMip,
  997. extent.width, extent.height, extent.depth);
  998. // Transfer texture to a valid layout
  999. VkAccessFlags currentAccessMask = image->getAccessFlags(subresource->getLayout());
  1000. transferCB->setLayout(image->getHandle(), currentAccessMask, VK_ACCESS_TRANSFER_READ_BIT, subresource->getLayout(),
  1001. VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, range);
  1002. // Queue copy command
  1003. image->copy(transferCB, mStagingBuffer, extent, rangeLayers, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
  1004. // Transfer back to original layout
  1005. VkImageLayout dstLayout = image->getOptimalLayout();
  1006. currentAccessMask = image->getAccessFlags(dstLayout);
  1007. transferCB->setLayout(image->getHandle(), VK_ACCESS_TRANSFER_READ_BIT, currentAccessMask,
  1008. VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dstLayout, range);
  1009. transferCB->getCB()->registerResource(image, range, VulkanUseFlag::Read);
  1010. // Ensure data written to the staging buffer is visible
  1011. VkAccessFlags stagingAccessFlags;
  1012. if (options == GBL_READ_ONLY)
  1013. stagingAccessFlags = VK_ACCESS_HOST_READ_BIT;
  1014. else // Must be read/write
  1015. stagingAccessFlags = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT;
  1016. transferCB->memoryBarrier(mStagingBuffer->getHandle(),
  1017. VK_ACCESS_TRANSFER_WRITE_BIT,
  1018. stagingAccessFlags,
  1019. VK_PIPELINE_STAGE_TRANSFER_BIT,
  1020. VK_PIPELINE_STAGE_HOST_BIT);
  1021. // Submit the command buffer and wait until it finishes
  1022. transferCB->flush(true);
  1023. }
  1024. UINT8* data = mStagingBuffer->map(0, lockedArea.getSize());
  1025. lockedArea.setExternalBuffer(data);
  1026. return lockedArea;
  1027. }
  1028. void VulkanTexture::unlockImpl()
  1029. {
  1030. // Possibly map() failed with some error
  1031. if (!mIsMapped)
  1032. return;
  1033. // Note: If we did any writes they need to be made visible to the GPU. However there is no need to execute
  1034. // a pipeline barrier because (as per spec) host writes are implicitly visible to the device.
  1035. if (mStagingBuffer == nullptr)
  1036. mImages[mMappedDeviceIdx]->unmap();
  1037. else
  1038. {
  1039. mStagingBuffer->unmap();
  1040. bool isWrite = mMappedLockOptions != GBL_READ_ONLY;
  1041. // We the caller wrote anything to the staging buffer, we need to upload it back to the main buffer
  1042. if (isWrite)
  1043. {
  1044. VulkanRenderAPI& rapi = static_cast<VulkanRenderAPI&>(RenderAPI::instance());
  1045. VulkanDevice& device = *rapi._getDevice(mMappedDeviceIdx);
  1046. VulkanCommandBufferManager& cbManager = gVulkanCBManager();
  1047. GpuQueueType queueType;
  1048. UINT32 localQueueIdx = CommandSyncMask::getQueueIdxAndType(mMappedGlobalQueueIdx, queueType);
  1049. VulkanImage* image = mImages[mMappedDeviceIdx];
  1050. VulkanTransferBuffer* transferCB = cbManager.getTransferBuffer(mMappedDeviceIdx, queueType, localQueueIdx);
  1051. VulkanImageSubresource* subresource = image->getSubresource(mMappedFace, mMappedMip);
  1052. VkImageLayout curLayout = subresource->getLayout();
  1053. // If the subresource is used in any way on the GPU, we need to wait for that use to finish before
  1054. // we issue our copy
  1055. UINT32 useMask = subresource->getUseInfo(VulkanUseFlag::Read | VulkanUseFlag::Write);
  1056. bool isNormalWrite = false;
  1057. if (useMask != 0) // Subresource is currently used on the GPU
  1058. {
  1059. // Try to avoid the wait by checking for special write conditions
  1060. // Caller guarantees he won't touch the same data as the GPU, so just copy
  1061. if (mMappedLockOptions == GBL_WRITE_ONLY_NO_OVERWRITE)
  1062. {
  1063. // Fall through to copy()
  1064. }
  1065. // Caller doesn't care about buffer contents, so just discard the existing buffer and create a new one
  1066. else if (mMappedLockOptions == GBL_WRITE_ONLY_DISCARD)
  1067. {
  1068. // We need to discard the entire image, even though we're only writing to a single sub-resource
  1069. image->destroy();
  1070. image = createImage(device, mInternalFormats[mMappedDeviceIdx]);
  1071. mImages[mMappedDeviceIdx] = image;
  1072. subresource = image->getSubresource(mMappedFace, mMappedMip);
  1073. }
  1074. else // Otherwise we have no choice but to issue a dependency between the queues
  1075. {
  1076. transferCB->appendMask(useMask);
  1077. isNormalWrite = true;
  1078. }
  1079. }
  1080. else
  1081. isNormalWrite = true;
  1082. const TextureProperties& props = getProperties();
  1083. // Check if the subresource will still be bound somewhere after the CBs using it finish
  1084. if (isNormalWrite)
  1085. {
  1086. UINT32 useCount = subresource->getUseCount();
  1087. UINT32 boundCount = subresource->getBoundCount();
  1088. bool isBoundWithoutUse = boundCount > useCount;
  1089. // If image is queued for some operation on a CB, then we need to make a copy of the subresource to
  1090. // avoid modifying its use in the previous operation
  1091. if (isBoundWithoutUse)
  1092. {
  1093. VulkanImage* newImage = createImage(device, mInternalFormats[mMappedDeviceIdx]);
  1094. // Avoid copying original contents if the image only has one sub-resource, which we'll overwrite anyway
  1095. if (props.getNumMipmaps() > 0 || props.getNumFaces() > 1)
  1096. {
  1097. VkImageLayout oldImgLayout = image->getOptimalLayout();
  1098. curLayout = newImage->getOptimalLayout();
  1099. copyImage(transferCB, image, newImage, oldImgLayout, curLayout);
  1100. }
  1101. image->destroy();
  1102. image = newImage;
  1103. mImages[mMappedDeviceIdx] = image;
  1104. }
  1105. }
  1106. VkImageSubresourceRange range;
  1107. range.aspectMask = image->getAspectFlags();
  1108. range.baseArrayLayer = mMappedFace;
  1109. range.layerCount = 1;
  1110. range.baseMipLevel = mMappedMip;
  1111. range.levelCount = 1;
  1112. VkImageSubresourceLayers rangeLayers;
  1113. rangeLayers.aspectMask = range.aspectMask;
  1114. rangeLayers.baseArrayLayer = range.baseArrayLayer;
  1115. rangeLayers.layerCount = range.layerCount;
  1116. rangeLayers.mipLevel = range.baseMipLevel;
  1117. VkExtent3D extent;
  1118. PixelUtil::getSizeForMipLevel(props.getWidth(), props.getHeight(), props.getDepth(), mMappedMip,
  1119. extent.width, extent.height, extent.depth);
  1120. VkImageLayout transferLayout;
  1121. if (mDirectlyMappable)
  1122. transferLayout = VK_IMAGE_LAYOUT_GENERAL;
  1123. else
  1124. transferLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  1125. // Transfer texture to a valid layout
  1126. VkAccessFlags currentAccessMask = image->getAccessFlags(curLayout);
  1127. transferCB->setLayout(image->getHandle(), currentAccessMask, VK_ACCESS_TRANSFER_WRITE_BIT,
  1128. curLayout, transferLayout, range);
  1129. // Queue copy command
  1130. mStagingBuffer->copy(transferCB, image, extent, rangeLayers, transferLayout);
  1131. // Transfer back to original (or optimal if initial layout was undefined/preinitialized)
  1132. VkImageLayout dstLayout = image->getOptimalLayout();
  1133. currentAccessMask = image->getAccessFlags(dstLayout);
  1134. transferCB->setLayout(image->getHandle(), VK_ACCESS_TRANSFER_WRITE_BIT, currentAccessMask,
  1135. transferLayout, dstLayout, range);
  1136. // Notify the command buffer that these resources are being used on it
  1137. transferCB->getCB()->registerResource(mStagingBuffer, VK_ACCESS_TRANSFER_READ_BIT, VulkanUseFlag::Read);
  1138. transferCB->getCB()->registerResource(image, range, VulkanUseFlag::Write);
  1139. // We don't actually flush the transfer buffer here since it's an expensive operation, but it's instead
  1140. // done automatically before next "normal" command buffer submission.
  1141. }
  1142. mStagingBuffer->destroy();
  1143. mStagingBuffer = nullptr;
  1144. }
  1145. mIsMapped = false;
  1146. }
  1147. void VulkanTexture::readDataImpl(PixelData& dest, UINT32 mipLevel, UINT32 face, UINT32 deviceIdx, UINT32 queueIdx)
  1148. {
  1149. if (mProperties.getNumSamples() > 1)
  1150. {
  1151. LOGERR("Multisampled textures cannot be accessed from the CPU directly.");
  1152. return;
  1153. }
  1154. PixelData myData = lock(GBL_READ_ONLY, mipLevel, face, deviceIdx, queueIdx);
  1155. PixelUtil::bulkPixelConversion(myData, dest);
  1156. unlock();
  1157. BS_INC_RENDER_STAT_CAT(ResRead, RenderStatObject_Texture);
  1158. }
  1159. void VulkanTexture::writeDataImpl(const PixelData& src, UINT32 mipLevel, UINT32 face, bool discardWholeBuffer,
  1160. UINT32 queueIdx)
  1161. {
  1162. if (mProperties.getNumSamples() > 1)
  1163. {
  1164. LOGERR("Multisampled textures cannot be accessed from the CPU directly.");
  1165. return;
  1166. }
  1167. mipLevel = Math::clamp(mipLevel, (UINT32)mipLevel, mProperties.getNumMipmaps());
  1168. face = Math::clamp(face, (UINT32)0, mProperties.getNumFaces() - 1);
  1169. if (face > 0 && mProperties.getTextureType() == TEX_TYPE_3D)
  1170. {
  1171. LOGERR("3D texture arrays are not supported.");
  1172. return;
  1173. }
  1174. // Write to every device
  1175. for (UINT32 i = 0; i < BS_MAX_DEVICES; i++)
  1176. {
  1177. if (mImages[i] == nullptr)
  1178. continue;
  1179. PixelData myData = lock(discardWholeBuffer ? GBL_WRITE_ONLY_DISCARD : GBL_WRITE_ONLY_DISCARD_RANGE,
  1180. mipLevel, face, i, queueIdx);
  1181. PixelUtil::bulkPixelConversion(src, myData);
  1182. unlock();
  1183. }
  1184. BS_INC_RENDER_STAT_CAT(ResWrite, RenderStatObject_Texture);
  1185. }
  1186. }}