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