BsVulkanTexture.cpp 49 KB

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