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 8 #ifndef GrVkImage_DEFINED 9 #define GrVkImage_DEFINED 10 11 #include "include/core/SkRefCnt.h" 12 #include "include/core/SkTypes.h" 13 #include "include/gpu/GpuTypes.h" 14 #include "include/gpu/ganesh/GrBackendSurface.h" 15 #include "include/gpu/ganesh/GrTypes.h" 16 #include "include/gpu/MutableTextureState.h" 17 #include "include/gpu/ganesh/vk/GrVkBackendSurface.h" 18 #include "include/gpu/ganesh/vk/GrVkTypes.h" 19 #include "include/gpu/vk/VulkanMutableTextureState.h" 20 #include "include/gpu/vk/VulkanTypes.h" 21 #include "include/private/base/SkDebug.h" 22 #include "include/private/base/SkTo.h" 23 #include "include/private/gpu/ganesh/GrTypesPriv.h" 24 #include "include/private/gpu/vk/SkiaVulkan.h" 25 #include "src/gpu/GpuRefCnt.h" 26 #include "src/gpu/ganesh/GrAttachment.h" 27 #include "src/gpu/ganesh/GrManagedResource.h" 28 #include "src/gpu/ganesh/vk/GrVkDescriptorSet.h" // IWYU pragma: keep 29 #include "src/gpu/vk/VulkanMutableTextureStatePriv.h" 30 31 #include <cinttypes> 32 #include <cstdint> 33 #include <string_view> 34 35 class GrVkGpu; 36 class GrVkImageView; 37 struct SkISize; 38 39 class GrVkImage : public GrAttachment { 40 private: 41 class Resource; 42 43 public: 44 static sk_sp<GrVkImage> MakeStencil(GrVkGpu* gpu, 45 SkISize dimensions, 46 int sampleCnt, 47 VkFormat format); 48 49 static sk_sp<GrVkImage> MakeMSAA(GrVkGpu* gpu, 50 SkISize dimensions, 51 int numSamples, 52 VkFormat format, 53 GrProtected isProtected, 54 GrMemoryless memoryless); 55 56 static sk_sp<GrVkImage> MakeTexture(GrVkGpu* gpu, 57 SkISize dimensions, 58 VkFormat format, 59 uint32_t mipLevels, 60 GrRenderable renderable, 61 int numSamples, 62 skgpu::Budgeted budgeted, 63 GrProtected isProtected); 64 65 static sk_sp<GrVkImage> MakeWrapped(GrVkGpu* gpu, 66 SkISize dimensions, 67 const GrVkImageInfo&, 68 sk_sp<skgpu::MutableTextureState>, 69 UsageFlags attachmentUsages, 70 GrWrapOwnership, 71 GrWrapCacheable, 72 std::string_view label, 73 bool forSecondaryCB = false); 74 75 ~GrVkImage() override; 76 image()77 VkImage image() const { 78 // Should only be called when we have a real fResource object, i.e. never when being used as 79 // a RT in an external secondary command buffer. 80 SkASSERT(fResource); 81 return fInfo.fImage; 82 } alloc()83 const skgpu::VulkanAlloc& alloc() const { 84 // Should only be called when we have a real fResource object, i.e. never when being used as 85 // a RT in an external secondary command buffer. 86 SkASSERT(fResource); 87 return fInfo.fAlloc; 88 } vkImageInfo()89 const GrVkImageInfo& vkImageInfo() const { return fInfo; } imageFormat()90 VkFormat imageFormat() const { return fInfo.fFormat; } backendFormat()91 GrBackendFormat backendFormat() const override { 92 bool usesDRMModifier = 93 this->vkImageInfo().fImageTiling == VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT; 94 if (fResource && this->ycbcrConversionInfo().isValid()) { 95 SkASSERT(this->imageFormat() == this->ycbcrConversionInfo().fFormat); 96 return GrBackendFormats::MakeVk(this->ycbcrConversionInfo(), usesDRMModifier); 97 } 98 SkASSERT(this->imageFormat() != VK_FORMAT_UNDEFINED); 99 return GrBackendFormats::MakeVk(this->imageFormat(), usesDRMModifier); 100 } mipLevels()101 uint32_t mipLevels() const { return fInfo.fLevelCount; } ycbcrConversionInfo()102 const skgpu::VulkanYcbcrConversionInfo& ycbcrConversionInfo() const { 103 // Should only be called when we have a real fResource object, i.e. never when being used as 104 // a RT in an external secondary command buffer. 105 SkASSERT(fResource); 106 return fInfo.fYcbcrConversionInfo; 107 } vkUsageFlags()108 VkImageUsageFlags vkUsageFlags() { return fInfo.fImageUsageFlags; } supportsInputAttachmentUsage()109 bool supportsInputAttachmentUsage() const { 110 return fInfo.fImageUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; 111 } 112 framebufferView()113 const GrVkImageView* framebufferView() const { return fFramebufferView.get(); } textureView()114 const GrVkImageView* textureView() const { return fTextureView.get(); } 115 116 // So that we don't need to rewrite descriptor sets each time, we keep cached input descriptor 117 // sets on the attachment and simply reuse those descriptor sets for this attachment only. These 118 // calls will fail if the attachment does not support being used as an input attachment. These 119 // calls do not ref the GrVkDescriptorSet so they called will need to manually ref them if they 120 // need to be kept alive. 121 gr_rp<const GrVkDescriptorSet> inputDescSetForBlending(GrVkGpu* gpu); 122 // Input descripotr set used when needing to read a resolve attachment to load data into a 123 // discardable msaa attachment. 124 gr_rp<const GrVkDescriptorSet> inputDescSetForMSAALoad(GrVkGpu* gpu); 125 resource()126 const Resource* resource() const { 127 SkASSERT(fResource); 128 return fResource; 129 } isLinearTiled()130 bool isLinearTiled() const { 131 // Should only be called when we have a real fResource object, i.e. never when being used as 132 // a RT in an external secondary command buffer. 133 SkASSERT(fResource); 134 return SkToBool(VK_IMAGE_TILING_LINEAR == fInfo.fImageTiling); 135 } isBorrowed()136 bool isBorrowed() const { return fIsBorrowed; } 137 getMutableState()138 sk_sp<skgpu::MutableTextureState> getMutableState() const { return fMutableState; } 139 currentLayout()140 VkImageLayout currentLayout() const { 141 return skgpu::MutableTextureStates::GetVkImageLayout(fMutableState.get()); 142 } 143 144 void setImageLayoutAndQueueIndex(const GrVkGpu* gpu, 145 VkImageLayout newLayout, 146 VkAccessFlags dstAccessMask, 147 VkPipelineStageFlags dstStageMask, 148 bool byRegion, 149 uint32_t newQueueFamilyIndex); 150 setImageLayout(const GrVkGpu * gpu,VkImageLayout newLayout,VkAccessFlags dstAccessMask,VkPipelineStageFlags dstStageMask,bool byRegion)151 void setImageLayout(const GrVkGpu* gpu, 152 VkImageLayout newLayout, 153 VkAccessFlags dstAccessMask, 154 VkPipelineStageFlags dstStageMask, 155 bool byRegion) { 156 this->setImageLayoutAndQueueIndex(gpu, newLayout, dstAccessMask, dstStageMask, byRegion, 157 VK_QUEUE_FAMILY_IGNORED); 158 } 159 currentQueueFamilyIndex()160 uint32_t currentQueueFamilyIndex() const { 161 return skgpu::MutableTextureStates::GetVkQueueFamilyIndex(fMutableState.get()); 162 } 163 setQueueFamilyIndex(uint32_t queueFamilyIndex)164 void setQueueFamilyIndex(uint32_t queueFamilyIndex) { 165 skgpu::MutableTextureStates::SetVkQueueFamilyIndex(fMutableState.get(), queueFamilyIndex); 166 } 167 168 // Returns the image to its original queue family and changes the layout to present if the queue 169 // family is not external or foreign. 170 void prepareForPresent(GrVkGpu* gpu); 171 172 // Returns the image to its original queue family 173 void prepareForExternal(GrVkGpu* gpu); 174 175 // This simply updates our tracking of the image layout and does not actually do any gpu work. 176 // This is only used for mip map generation where we are manually changing the layouts as we 177 // blit each layer, and then at the end need to update our tracking. updateImageLayout(VkImageLayout newLayout)178 void updateImageLayout(VkImageLayout newLayout) { 179 // Should only be called when we have a real fResource object, i.e. never when being used as 180 // a RT in an external secondary command buffer. 181 SkASSERT(fResource); 182 skgpu::MutableTextureStates::SetVkImageLayout(fMutableState.get(), newLayout); 183 } 184 185 struct ImageDesc { 186 VkImageType fImageType; 187 VkFormat fFormat; 188 uint32_t fWidth; 189 uint32_t fHeight; 190 uint32_t fLevels; 191 uint32_t fSamples; 192 VkImageTiling fImageTiling; 193 VkImageUsageFlags fUsageFlags; 194 VkFlags fMemProps; 195 GrProtected fIsProtected; 196 ImageDescImageDesc197 ImageDesc() 198 : fImageType(VK_IMAGE_TYPE_2D) 199 , fFormat(VK_FORMAT_UNDEFINED) 200 , fWidth(0) 201 , fHeight(0) 202 , fLevels(1) 203 , fSamples(1) 204 , fImageTiling(VK_IMAGE_TILING_OPTIMAL) 205 , fUsageFlags(0) 206 , fMemProps(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) 207 , fIsProtected(GrProtected::kNo) {} 208 }; 209 210 static bool InitImageInfo(GrVkGpu* gpu, const ImageDesc& imageDesc, GrVkImageInfo*); 211 // Destroys the internal VkImage and VkDeviceMemory in the GrVkImageInfo 212 static void DestroyImageInfo(const GrVkGpu* gpu, GrVkImageInfo*); 213 214 // These match the definitions in SkImage, for whence they came 215 typedef void* ReleaseCtx; 216 typedef void (*ReleaseProc)(ReleaseCtx); 217 218 void setResourceRelease(sk_sp<RefCntedReleaseProc> releaseHelper); 219 220 // Helpers to use for setting the layout of the VkImage 221 static VkPipelineStageFlags LayoutToPipelineSrcStageFlags(const VkImageLayout layout); 222 static VkAccessFlags LayoutToSrcAccessMask(const VkImageLayout layout); 223 224 #if defined(GPU_TEST_UTILS) 225 void setCurrentQueueFamilyToGraphicsQueue(GrVkGpu* gpu); 226 #endif 227 228 private: 229 static sk_sp<GrVkImage> Make(GrVkGpu* gpu, 230 SkISize dimensions, 231 UsageFlags attachmentUsages, 232 int sampleCnt, 233 VkFormat format, 234 uint32_t mipLevels, 235 VkImageUsageFlags vkUsageFlags, 236 GrProtected isProtected, 237 GrMemoryless, 238 skgpu::Budgeted); 239 240 GrVkImage(GrVkGpu* gpu, 241 SkISize dimensions, 242 UsageFlags supportedUsages, 243 const GrVkImageInfo&, 244 sk_sp<skgpu::MutableTextureState> mutableState, 245 sk_sp<const GrVkImageView> framebufferView, 246 sk_sp<const GrVkImageView> textureView, 247 skgpu::Budgeted, 248 std::string_view label); 249 250 GrVkImage(GrVkGpu* gpu, 251 SkISize dimensions, 252 UsageFlags supportedUsages, 253 const GrVkImageInfo&, 254 sk_sp<skgpu::MutableTextureState> mutableState, 255 sk_sp<const GrVkImageView> framebufferView, 256 sk_sp<const GrVkImageView> textureView, 257 GrBackendObjectOwnership, 258 GrWrapCacheable, 259 bool forSecondaryCB, 260 std::string_view label); 261 262 void init(GrVkGpu*, bool forSecondaryCB); 263 264 void onRelease() override; 265 void onAbandon() override; 266 267 void releaseImage(); hasResource()268 bool hasResource() const { return fResource; } 269 270 GrVkGpu* getVkGpu() const; 271 272 GrVkImageInfo fInfo; 273 uint32_t fInitialQueueFamily; 274 sk_sp<skgpu::MutableTextureState> fMutableState; 275 276 sk_sp<const GrVkImageView> fFramebufferView; 277 sk_sp<const GrVkImageView> fTextureView; 278 279 bool fIsBorrowed; 280 281 // Descriptor set used when this is used as an input attachment for reading the dst in blending. 282 gr_rp<const GrVkDescriptorSet> fCachedBlendingInputDescSet; 283 // Descriptor set used when this is used as an input attachment for loading an msaa attachment. 284 gr_rp<const GrVkDescriptorSet> fCachedMSAALoadInputDescSet; 285 286 class Resource : public GrTextureResource { 287 public: Resource(const GrVkGpu * gpu)288 explicit Resource(const GrVkGpu* gpu) 289 : fGpu(gpu) 290 , fImage(VK_NULL_HANDLE) { 291 fAlloc.fMemory = VK_NULL_HANDLE; 292 fAlloc.fOffset = 0; 293 } 294 Resource(const GrVkGpu * gpu,VkImage image,const skgpu::VulkanAlloc & alloc,VkImageTiling tiling)295 Resource(const GrVkGpu* gpu, 296 VkImage image, 297 const skgpu::VulkanAlloc& alloc, 298 VkImageTiling tiling) 299 : fGpu(gpu) 300 , fImage(image) 301 , fAlloc(alloc) {} 302 ~Resource()303 ~Resource() override {} 304 305 #ifdef SK_TRACE_MANAGED_RESOURCES dumpInfo()306 void dumpInfo() const override { 307 SkDebugf("GrVkImage: %" PRIdPTR " (%d refs)\n", (intptr_t)fImage, this->getRefCnt()); 308 } 309 #endif 310 311 #ifdef SK_DEBUG asVkImageResource()312 const GrManagedResource* asVkImageResource() const override { return this; } 313 #endif 314 315 private: 316 void freeGPUData() const override; 317 318 const GrVkGpu* fGpu; 319 VkImage fImage; 320 skgpu::VulkanAlloc fAlloc; 321 322 using INHERITED = GrTextureResource; 323 }; 324 325 // for wrapped textures 326 class BorrowedResource : public Resource { 327 public: BorrowedResource(const GrVkGpu * gpu,VkImage image,const skgpu::VulkanAlloc & alloc,VkImageTiling tiling)328 BorrowedResource(const GrVkGpu* gpu, VkImage image, const skgpu::VulkanAlloc& alloc, 329 VkImageTiling tiling) 330 : Resource(gpu, image, alloc, tiling) { 331 } 332 private: 333 void freeGPUData() const override; 334 }; 335 336 Resource* fResource; 337 338 friend class GrVkRenderTarget; 339 }; 340 341 #endif 342