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/GrTexture.h" 14 #include "include/gpu/vk/GrVkTypes.h" 15 #include "include/private/GrTypesPriv.h" 16 #include "src/gpu/vk/GrVkImageLayout.h" 17 #include "src/gpu/vk/GrVkResource.h" 18 19 class GrVkGpu; 20 class GrVkTexture; 21 22 class GrVkImage : SkNoncopyable { 23 private: 24 class Resource; 25 26 public: 27 GrVkImage(const GrVkImageInfo& info, sk_sp<GrVkImageLayout> layout, 28 GrBackendObjectOwnership ownership, bool forSecondaryCB = false) fInfo(info)29 : fInfo(info) 30 , fInitialQueueFamily(info.fCurrentQueueFamily) 31 , fLayout(std::move(layout)) 32 , fIsBorrowed(GrBackendObjectOwnership::kBorrowed == ownership) { 33 SkASSERT(fLayout->getImageLayout() == fInfo.fImageLayout); 34 if (forSecondaryCB) { 35 fResource = nullptr; 36 } else if (fIsBorrowed) { 37 fResource = new BorrowedResource(info.fImage, info.fAlloc, info.fImageTiling); 38 } else { 39 SkASSERT(VK_NULL_HANDLE != info.fAlloc.fMemory); 40 fResource = new Resource(info.fImage, info.fAlloc, info.fImageTiling); 41 } 42 } 43 virtual ~GrVkImage(); 44 image()45 VkImage image() const { 46 // Should only be called when we have a real fResource object, i.e. never when being used as 47 // a RT in an external secondary command buffer. 48 SkASSERT(fResource); 49 return fInfo.fImage; 50 } alloc()51 const GrVkAlloc& alloc() const { 52 // Should only be called when we have a real fResource object, i.e. never when being used as 53 // a RT in an external secondary command buffer. 54 SkASSERT(fResource); 55 return fInfo.fAlloc; 56 } imageFormat()57 VkFormat imageFormat() const { return fInfo.fFormat; } getBackendFormat()58 GrBackendFormat getBackendFormat() const { 59 if (fResource && this->ycbcrConversionInfo().isValid()) { 60 SkASSERT(this->imageFormat() == this->ycbcrConversionInfo().fFormat); 61 return GrBackendFormat::MakeVk(this->ycbcrConversionInfo()); 62 } 63 SkASSERT(this->imageFormat() != VK_FORMAT_UNDEFINED); 64 return GrBackendFormat::MakeVk(this->imageFormat()); 65 } mipLevels()66 uint32_t mipLevels() const { return fInfo.fLevelCount; } ycbcrConversionInfo()67 const GrVkYcbcrConversionInfo& ycbcrConversionInfo() const { 68 // Should only be called when we have a real fResource object, i.e. never when being used as 69 // a RT in an external secondary command buffer. 70 SkASSERT(fResource); 71 return fInfo.fYcbcrConversionInfo; 72 } resource()73 const Resource* resource() const { 74 SkASSERT(fResource); 75 return fResource; 76 } isLinearTiled()77 bool isLinearTiled() 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 SkToBool(VK_IMAGE_TILING_LINEAR == fInfo.fImageTiling); 82 } isBorrowed()83 bool isBorrowed() const { return fIsBorrowed; } 84 grVkImageLayout()85 sk_sp<GrVkImageLayout> grVkImageLayout() const { return fLayout; } 86 currentLayout()87 VkImageLayout currentLayout() const { 88 return fLayout->getImageLayout(); 89 } 90 91 void setImageLayout(const GrVkGpu* gpu, 92 VkImageLayout newLayout, 93 VkAccessFlags dstAccessMask, 94 VkPipelineStageFlags dstStageMask, 95 bool byRegion, 96 bool releaseFamilyQueue = false); 97 98 // Returns the image to its original queue family and changes the layout to present if the queue 99 // family is not external or foreign. 100 void prepareForPresent(GrVkGpu* gpu); 101 102 // Returns the image to its original queue family 103 void prepareForExternal(GrVkGpu* gpu); 104 105 // This simply updates our tracking of the image layout and does not actually do any gpu work. 106 // This is only used for mip map generation where we are manually changing the layouts as we 107 // blit each layer, and then at the end need to update our tracking. updateImageLayout(VkImageLayout newLayout)108 void updateImageLayout(VkImageLayout newLayout) { 109 // Should only be called when we have a real fResource object, i.e. never when being used as 110 // a RT in an external secondary command buffer. 111 SkASSERT(fResource); 112 fLayout->setImageLayout(newLayout); 113 } 114 115 struct ImageDesc { 116 VkImageType fImageType; 117 VkFormat fFormat; 118 uint32_t fWidth; 119 uint32_t fHeight; 120 uint32_t fLevels; 121 uint32_t fSamples; 122 VkImageTiling fImageTiling; 123 VkImageUsageFlags fUsageFlags; 124 VkFlags fMemProps; 125 GrProtected fIsProtected; 126 ImageDescImageDesc127 ImageDesc() 128 : fImageType(VK_IMAGE_TYPE_2D) 129 , fFormat(VK_FORMAT_UNDEFINED) 130 , fWidth(0) 131 , fHeight(0) 132 , fLevels(1) 133 , fSamples(1) 134 , fImageTiling(VK_IMAGE_TILING_OPTIMAL) 135 , fUsageFlags(0) 136 , fMemProps(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) 137 , fIsProtected(GrProtected::kNo) {} 138 }; 139 140 static bool InitImageInfo(const GrVkGpu* gpu, const ImageDesc& imageDesc, GrVkImageInfo*); 141 // Destroys the internal VkImage and VkDeviceMemory in the GrVkImageInfo 142 static void DestroyImageInfo(const GrVkGpu* gpu, GrVkImageInfo*); 143 144 // These match the definitions in SkImage, for whence they came 145 typedef void* ReleaseCtx; 146 typedef void (*ReleaseProc)(ReleaseCtx); 147 148 void setResourceRelease(sk_sp<GrRefCntedCallback> releaseHelper); 149 150 // Helpers to use for setting the layout of the VkImage 151 static VkPipelineStageFlags LayoutToPipelineSrcStageFlags(const VkImageLayout layout); 152 static VkAccessFlags LayoutToSrcAccessMask(const VkImageLayout layout); 153 154 #if GR_TEST_UTILS 155 void setCurrentQueueFamilyToGraphicsQueue(GrVkGpu* gpu); 156 #endif 157 158 protected: 159 void releaseImage(GrVkGpu* gpu); 160 void abandonImage(); hasResource()161 bool hasResource() const { return fResource; } 162 163 GrVkImageInfo fInfo; 164 uint32_t fInitialQueueFamily; 165 sk_sp<GrVkImageLayout> fLayout; 166 bool fIsBorrowed; 167 168 private: 169 class Resource : public GrVkResource { 170 public: Resource()171 Resource() 172 : fImage(VK_NULL_HANDLE) { 173 fAlloc.fMemory = VK_NULL_HANDLE; 174 fAlloc.fOffset = 0; 175 } 176 Resource(VkImage image,const GrVkAlloc & alloc,VkImageTiling tiling)177 Resource(VkImage image, const GrVkAlloc& alloc, VkImageTiling tiling) 178 : fImage(image) 179 , fAlloc(alloc) 180 , fImageTiling(tiling) {} 181 ~Resource()182 ~Resource() override { 183 SkASSERT(!fReleaseHelper); 184 } 185 186 #ifdef SK_TRACE_VK_RESOURCES dumpInfo()187 void dumpInfo() const override { 188 SkDebugf("GrVkImage: %d (%d refs)\n", fImage, this->getRefCnt()); 189 } 190 #endif setRelease(sk_sp<GrRefCntedCallback> releaseHelper)191 void setRelease(sk_sp<GrRefCntedCallback> releaseHelper) { 192 fReleaseHelper = std::move(releaseHelper); 193 } 194 195 /** 196 * These are used to coordinate calling the "finished" idle procs between the GrVkTexture 197 * and the Resource. If the GrVkTexture becomes purgeable and if there are no command 198 * buffers referring to the Resource then it calls the procs. Otherwise, the Resource calls 199 * them when the last command buffer reference goes away and the GrVkTexture is purgeable. 200 */ 201 void addIdleProc(GrVkTexture*, sk_sp<GrRefCntedCallback>) const; 202 int idleProcCnt() const; 203 sk_sp<GrRefCntedCallback> idleProc(int) const; 204 void resetIdleProcs() const; 205 void removeOwningTexture() const; 206 207 /** 208 * We track how many outstanding references this Resource has in command buffers and 209 * when the count reaches zero we call the idle proc. 210 */ 211 void notifyAddedToCommandBuffer() const override; 212 void notifyRemovedFromCommandBuffer() const override; isOwnedByCommandBuffer()213 bool isOwnedByCommandBuffer() const { return fNumCommandBufferOwners > 0; } 214 215 protected: 216 mutable sk_sp<GrRefCntedCallback> fReleaseHelper; 217 invokeReleaseProc()218 void invokeReleaseProc() const { 219 if (fReleaseHelper) { 220 // Depending on the ref count of fReleaseHelper this may or may not actually trigger 221 // the ReleaseProc to be called. 222 fReleaseHelper.reset(); 223 } 224 } 225 226 private: 227 void freeGPUData(GrVkGpu* gpu) const override; abandonGPUData()228 void abandonGPUData() const override { 229 this->invokeReleaseProc(); 230 SkASSERT(!fReleaseHelper); 231 } 232 233 VkImage fImage; 234 GrVkAlloc fAlloc; 235 VkImageTiling fImageTiling; 236 mutable int fNumCommandBufferOwners = 0; 237 mutable SkTArray<sk_sp<GrRefCntedCallback>> fIdleProcs; 238 mutable GrVkTexture* fOwningTexture = nullptr; 239 240 typedef GrVkResource INHERITED; 241 }; 242 243 // for wrapped textures 244 class BorrowedResource : public Resource { 245 public: BorrowedResource(VkImage image,const GrVkAlloc & alloc,VkImageTiling tiling)246 BorrowedResource(VkImage image, const GrVkAlloc& alloc, VkImageTiling tiling) 247 : Resource(image, alloc, tiling) { 248 } 249 private: 250 void freeGPUData(GrVkGpu* gpu) const override; 251 void abandonGPUData() const override; 252 }; 253 254 Resource* fResource; 255 256 friend class GrVkRenderTarget; 257 }; 258 259 #endif 260