GrVkImage.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. * Copyright 2015 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "src/gpu/GrGpuResourcePriv.h"
  8. #include "src/gpu/vk/GrVkGpu.h"
  9. #include "src/gpu/vk/GrVkImage.h"
  10. #include "src/gpu/vk/GrVkMemory.h"
  11. #include "src/gpu/vk/GrVkTexture.h"
  12. #include "src/gpu/vk/GrVkUtil.h"
  13. #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
  14. VkPipelineStageFlags GrVkImage::LayoutToPipelineSrcStageFlags(const VkImageLayout layout) {
  15. if (VK_IMAGE_LAYOUT_GENERAL == layout) {
  16. return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  17. } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
  18. VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
  19. return VK_PIPELINE_STAGE_TRANSFER_BIT;
  20. } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
  21. return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  22. } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
  23. VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout) {
  24. return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
  25. } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
  26. return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
  27. } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
  28. return VK_PIPELINE_STAGE_HOST_BIT;
  29. } else if (VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout) {
  30. return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  31. }
  32. SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
  33. return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
  34. }
  35. VkAccessFlags GrVkImage::LayoutToSrcAccessMask(const VkImageLayout layout) {
  36. // Currently we assume we will never being doing any explict shader writes (this doesn't include
  37. // color attachment or depth/stencil writes). So we will ignore the
  38. // VK_MEMORY_OUTPUT_SHADER_WRITE_BIT.
  39. // We can only directly access the host memory if we are in preinitialized or general layout,
  40. // and the image is linear.
  41. // TODO: Add check for linear here so we are not always adding host to general, and we should
  42. // only be in preinitialized if we are linear
  43. VkAccessFlags flags = 0;
  44. if (VK_IMAGE_LAYOUT_GENERAL == layout) {
  45. flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
  46. VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
  47. VK_ACCESS_TRANSFER_WRITE_BIT |
  48. VK_ACCESS_TRANSFER_READ_BIT |
  49. VK_ACCESS_SHADER_READ_BIT |
  50. VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT;
  51. } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
  52. flags = VK_ACCESS_HOST_WRITE_BIT;
  53. } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
  54. flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
  55. } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
  56. flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
  57. } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
  58. flags = VK_ACCESS_TRANSFER_WRITE_BIT;
  59. } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
  60. VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout ||
  61. VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout) {
  62. // There are no writes that need to be made available
  63. flags = 0;
  64. }
  65. return flags;
  66. }
  67. VkImageAspectFlags vk_format_to_aspect_flags(VkFormat format) {
  68. switch (format) {
  69. case VK_FORMAT_S8_UINT:
  70. return VK_IMAGE_ASPECT_STENCIL_BIT;
  71. case VK_FORMAT_D24_UNORM_S8_UINT: // fallthrough
  72. case VK_FORMAT_D32_SFLOAT_S8_UINT:
  73. return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
  74. default:
  75. SkASSERT(GrVkFormatIsSupported(format));
  76. return VK_IMAGE_ASPECT_COLOR_BIT;
  77. }
  78. }
  79. void GrVkImage::setImageLayout(const GrVkGpu* gpu, VkImageLayout newLayout,
  80. VkAccessFlags dstAccessMask,
  81. VkPipelineStageFlags dstStageMask,
  82. bool byRegion, bool releaseFamilyQueue) {
  83. SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED != newLayout &&
  84. VK_IMAGE_LAYOUT_PREINITIALIZED != newLayout);
  85. VkImageLayout currentLayout = this->currentLayout();
  86. if (releaseFamilyQueue && fInfo.fCurrentQueueFamily == fInitialQueueFamily &&
  87. newLayout == currentLayout) {
  88. // We never transfered the image to this queue and we are releasing it so don't do anything.
  89. return;
  90. }
  91. // If the old and new layout are the same and the layout is a read only layout, there is no need
  92. // to put in a barrier unless we also need to switch queues.
  93. if (newLayout == currentLayout && !releaseFamilyQueue &&
  94. (fInfo.fCurrentQueueFamily == VK_QUEUE_FAMILY_IGNORED ||
  95. fInfo.fCurrentQueueFamily == gpu->queueIndex()) &&
  96. (VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == currentLayout ||
  97. VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == currentLayout ||
  98. VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == currentLayout)) {
  99. return;
  100. }
  101. VkAccessFlags srcAccessMask = GrVkImage::LayoutToSrcAccessMask(currentLayout);
  102. VkPipelineStageFlags srcStageMask = GrVkImage::LayoutToPipelineSrcStageFlags(currentLayout);
  103. VkImageAspectFlags aspectFlags = vk_format_to_aspect_flags(fInfo.fFormat);
  104. uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  105. uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
  106. if (fInfo.fCurrentQueueFamily != VK_QUEUE_FAMILY_IGNORED &&
  107. gpu->queueIndex() != fInfo.fCurrentQueueFamily) {
  108. // The image still is owned by its original queue family and we need to transfer it into
  109. // ours.
  110. SkASSERT(!releaseFamilyQueue);
  111. SkASSERT(fInfo.fCurrentQueueFamily == fInitialQueueFamily);
  112. srcQueueFamilyIndex = fInfo.fCurrentQueueFamily;
  113. dstQueueFamilyIndex = gpu->queueIndex();
  114. fInfo.fCurrentQueueFamily = gpu->queueIndex();
  115. } else if (releaseFamilyQueue) {
  116. // We are releasing the image so we must transfer the image back to its original queue
  117. // family.
  118. srcQueueFamilyIndex = fInfo.fCurrentQueueFamily;
  119. dstQueueFamilyIndex = fInitialQueueFamily;
  120. fInfo.fCurrentQueueFamily = fInitialQueueFamily;
  121. }
  122. VkImageMemoryBarrier imageMemoryBarrier = {
  123. VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
  124. nullptr, // pNext
  125. srcAccessMask, // srcAccessMask
  126. dstAccessMask, // dstAccessMask
  127. currentLayout, // oldLayout
  128. newLayout, // newLayout
  129. srcQueueFamilyIndex, // srcQueueFamilyIndex
  130. dstQueueFamilyIndex, // dstQueueFamilyIndex
  131. fInfo.fImage, // image
  132. { aspectFlags, 0, fInfo.fLevelCount, 0, 1 } // subresourceRange
  133. };
  134. gpu->addImageMemoryBarrier(this->resource(), srcStageMask, dstStageMask, byRegion,
  135. &imageMemoryBarrier);
  136. this->updateImageLayout(newLayout);
  137. }
  138. bool GrVkImage::InitImageInfo(const GrVkGpu* gpu, const ImageDesc& imageDesc, GrVkImageInfo* info) {
  139. if (0 == imageDesc.fWidth || 0 == imageDesc.fHeight) {
  140. return false;
  141. }
  142. if ((imageDesc.fIsProtected == GrProtected::kYes) && !gpu->vkCaps().supportsProtectedMemory()) {
  143. return false;
  144. }
  145. VkImage image = VK_NULL_HANDLE;
  146. GrVkAlloc alloc;
  147. bool isLinear = VK_IMAGE_TILING_LINEAR == imageDesc.fImageTiling;
  148. VkImageLayout initialLayout = isLinear ? VK_IMAGE_LAYOUT_PREINITIALIZED
  149. : VK_IMAGE_LAYOUT_UNDEFINED;
  150. // Create Image
  151. VkSampleCountFlagBits vkSamples;
  152. if (!GrSampleCountToVkSampleCount(imageDesc.fSamples, &vkSamples)) {
  153. return false;
  154. }
  155. SkASSERT(VK_IMAGE_TILING_OPTIMAL == imageDesc.fImageTiling ||
  156. VK_SAMPLE_COUNT_1_BIT == vkSamples);
  157. VkImageCreateFlags createflags = 0;
  158. if (imageDesc.fIsProtected == GrProtected::kYes || gpu->protectedContext()) {
  159. createflags |= VK_IMAGE_CREATE_PROTECTED_BIT;
  160. }
  161. const VkImageCreateInfo imageCreateInfo = {
  162. VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, // sType
  163. nullptr, // pNext
  164. createflags, // VkImageCreateFlags
  165. imageDesc.fImageType, // VkImageType
  166. imageDesc.fFormat, // VkFormat
  167. { imageDesc.fWidth, imageDesc.fHeight, 1 }, // VkExtent3D
  168. imageDesc.fLevels, // mipLevels
  169. 1, // arrayLayers
  170. vkSamples, // samples
  171. imageDesc.fImageTiling, // VkImageTiling
  172. imageDesc.fUsageFlags, // VkImageUsageFlags
  173. VK_SHARING_MODE_EXCLUSIVE, // VkSharingMode
  174. 0, // queueFamilyCount
  175. 0, // pQueueFamilyIndices
  176. initialLayout // initialLayout
  177. };
  178. GR_VK_CALL_ERRCHECK(gpu->vkInterface(), CreateImage(gpu->device(), &imageCreateInfo, nullptr,
  179. &image));
  180. if (!GrVkMemory::AllocAndBindImageMemory(gpu, image, isLinear, &alloc)) {
  181. VK_CALL(gpu, DestroyImage(gpu->device(), image, nullptr));
  182. return false;
  183. }
  184. info->fImage = image;
  185. info->fAlloc = alloc;
  186. info->fImageTiling = imageDesc.fImageTiling;
  187. info->fImageLayout = initialLayout;
  188. info->fFormat = imageDesc.fFormat;
  189. info->fLevelCount = imageDesc.fLevels;
  190. info->fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED;
  191. info->fProtected =
  192. (createflags & VK_IMAGE_CREATE_PROTECTED_BIT) ? GrProtected::kYes : GrProtected::kNo;
  193. return true;
  194. }
  195. void GrVkImage::DestroyImageInfo(const GrVkGpu* gpu, GrVkImageInfo* info) {
  196. VK_CALL(gpu, DestroyImage(gpu->device(), info->fImage, nullptr));
  197. bool isLinear = VK_IMAGE_TILING_LINEAR == info->fImageTiling;
  198. GrVkMemory::FreeImageMemory(gpu, isLinear, info->fAlloc);
  199. }
  200. GrVkImage::~GrVkImage() {
  201. // should have been released or abandoned first
  202. SkASSERT(!fResource);
  203. }
  204. void GrVkImage::prepareForPresent(GrVkGpu* gpu) {
  205. VkImageLayout layout = this->currentLayout();
  206. if (fInitialQueueFamily != VK_QUEUE_FAMILY_EXTERNAL &&
  207. fInitialQueueFamily != VK_QUEUE_FAMILY_FOREIGN_EXT) {
  208. if (gpu->vkCaps().supportsSwapchain()) {
  209. layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
  210. }
  211. }
  212. this->setImageLayout(gpu, layout, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, false, true);
  213. }
  214. void GrVkImage::prepareForExternal(GrVkGpu* gpu) {
  215. this->setImageLayout(gpu, this->currentLayout(), 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, false,
  216. true);
  217. }
  218. void GrVkImage::releaseImage(GrVkGpu* gpu) {
  219. if (fInfo.fCurrentQueueFamily != fInitialQueueFamily) {
  220. // The Vulkan spec is vague on what to put for the dstStageMask here. The spec for image
  221. // memory barrier says the dstStageMask must not be zero. However, in the spec when it talks
  222. // about family queue transfers it says the dstStageMask is ignored and should be set to
  223. // zero. Assuming it really is ignored we set it to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT here
  224. // since it makes the Vulkan validation layers happy.
  225. this->setImageLayout(gpu, this->currentLayout(), 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
  226. false, true);
  227. }
  228. if (fResource) {
  229. fResource->removeOwningTexture();
  230. fResource->unref(gpu);
  231. fResource = nullptr;
  232. }
  233. }
  234. void GrVkImage::abandonImage() {
  235. if (fResource) {
  236. fResource->removeOwningTexture();
  237. fResource->unrefAndAbandon();
  238. fResource = nullptr;
  239. }
  240. }
  241. void GrVkImage::setResourceRelease(sk_sp<GrRefCntedCallback> releaseHelper) {
  242. SkASSERT(fResource);
  243. // Forward the release proc on to GrVkImage::Resource
  244. fResource->setRelease(std::move(releaseHelper));
  245. }
  246. void GrVkImage::Resource::freeGPUData(GrVkGpu* gpu) const {
  247. this->invokeReleaseProc();
  248. VK_CALL(gpu, DestroyImage(gpu->device(), fImage, nullptr));
  249. bool isLinear = (VK_IMAGE_TILING_LINEAR == fImageTiling);
  250. GrVkMemory::FreeImageMemory(gpu, isLinear, fAlloc);
  251. }
  252. void GrVkImage::Resource::addIdleProc(GrVkTexture* owningTexture,
  253. sk_sp<GrRefCntedCallback> idleProc) const {
  254. SkASSERT(!fOwningTexture || fOwningTexture == owningTexture);
  255. fOwningTexture = owningTexture;
  256. fIdleProcs.push_back(std::move(idleProc));
  257. }
  258. int GrVkImage::Resource::idleProcCnt() const { return fIdleProcs.count(); }
  259. sk_sp<GrRefCntedCallback> GrVkImage::Resource::idleProc(int i) const { return fIdleProcs[i]; }
  260. void GrVkImage::Resource::resetIdleProcs() const { fIdleProcs.reset(); }
  261. void GrVkImage::Resource::removeOwningTexture() const { fOwningTexture = nullptr; }
  262. void GrVkImage::Resource::notifyAddedToCommandBuffer() const { ++fNumCommandBufferOwners; }
  263. void GrVkImage::Resource::notifyRemovedFromCommandBuffer() const {
  264. SkASSERT(fNumCommandBufferOwners);
  265. if (--fNumCommandBufferOwners || !fIdleProcs.count()) {
  266. return;
  267. }
  268. if (fOwningTexture) {
  269. if (fOwningTexture->resourcePriv().hasRefOrPendingIO()) {
  270. // Wait for the texture to become idle in the cache to call the procs.
  271. return;
  272. }
  273. fOwningTexture->callIdleProcsOnBehalfOfResource();
  274. } else {
  275. fIdleProcs.reset();
  276. }
  277. }
  278. void GrVkImage::BorrowedResource::freeGPUData(GrVkGpu* gpu) const {
  279. this->invokeReleaseProc();
  280. }
  281. void GrVkImage::BorrowedResource::abandonGPUData() const {
  282. this->invokeReleaseProc();
  283. }
  284. #if GR_TEST_UTILS
  285. void GrVkImage::setCurrentQueueFamilyToGraphicsQueue(GrVkGpu* gpu) {
  286. fInfo.fCurrentQueueFamily = gpu->queueIndex();
  287. }
  288. #endif