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