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