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