1 /* 2 * Copyright 2018 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 PromiseImageHelper_DEFINED 9 #define PromiseImageHelper_DEFINED 10 11 #include "include/core/SkBitmap.h" 12 #include "include/core/SkDeferredDisplayListRecorder.h" 13 #include "include/core/SkPromiseImageTexture.h" 14 #include "include/core/SkYUVAIndex.h" 15 #include "include/core/SkYUVAPixmaps.h" 16 #include "include/core/SkYUVASizeInfo.h" 17 #include "include/gpu/GrBackendSurface.h" 18 #include "include/private/SkTArray.h" 19 #include "src/core/SkCachedData.h" 20 #include "src/core/SkTLazy.h" 21 22 class GrDirectContext; 23 class SkImage; 24 class SkMipmap; 25 class SkPicture; 26 class SkTaskGroup; 27 struct SkYUVAIndex; 28 29 // This class acts as a proxy for a GrBackendTexture that backs an image. 30 // Whenever a promise image is created for the image, the promise image receives a ref to 31 // potentially several of these objects. Once all the promise images receive their done 32 // callbacks this object is deleted - removing the GrBackendTexture from VRAM. 33 // Note that while the DDLs are being created in the threads, the PromiseImageHelper holds 34 // a ref on all the PromiseImageCallbackContexts. However, once all the threads are done 35 // it drops all of its refs (via "reset"). 36 class PromiseImageCallbackContext : public SkRefCnt { 37 public: PromiseImageCallbackContext(GrDirectContext * direct,GrBackendFormat backendFormat)38 PromiseImageCallbackContext(GrDirectContext* direct, GrBackendFormat backendFormat) 39 : fContext(direct) 40 , fBackendFormat(backendFormat) {} 41 42 ~PromiseImageCallbackContext() override; 43 backendFormat()44 const GrBackendFormat& backendFormat() const { return fBackendFormat; } 45 46 void setBackendTexture(const GrBackendTexture& backendTexture); 47 48 void destroyBackendTexture(); 49 fulfill()50 sk_sp<SkPromiseImageTexture> fulfill() { 51 ++fTotalFulfills; 52 return fPromiseImageTexture; 53 } 54 release()55 void release() { 56 ++fDoneCnt; 57 SkASSERT(fDoneCnt <= fNumImages); 58 } 59 wasAddedToImage()60 void wasAddedToImage() { fNumImages++; } 61 promiseImageTexture()62 const SkPromiseImageTexture* promiseImageTexture() const { 63 return fPromiseImageTexture.get(); 64 } 65 PromiseImageFulfillProc(void * textureContext)66 static sk_sp<SkPromiseImageTexture> PromiseImageFulfillProc(void* textureContext) { 67 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext); 68 return callbackContext->fulfill(); 69 } 70 PromiseImageReleaseProc(void * textureContext)71 static void PromiseImageReleaseProc(void* textureContext) { 72 auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext); 73 callbackContext->release(); 74 callbackContext->unref(); 75 } 76 77 private: 78 GrDirectContext* fContext; 79 GrBackendFormat fBackendFormat; 80 sk_sp<SkPromiseImageTexture> fPromiseImageTexture; 81 int fNumImages = 0; 82 int fTotalFulfills = 0; 83 int fDoneCnt = 0; 84 85 using INHERITED = SkRefCnt; 86 }; 87 88 // This class consolidates tracking & extraction of the original image data from an skp, 89 // the upload of said data to the GPU and the fulfillment of promise images. 90 // 91 // The way this works is: 92 // the original skp is converted to SkData and all its image info is extracted into this 93 // class and only indices into this class are left in the SkData (via deflateSKP) 94 // 95 // Prior to replaying in threads, all the images stored in this class are uploaded to the 96 // gpu and PromiseImageCallbackContexts are created for them (via uploadAllToGPU) 97 // 98 // Each thread reinflates the SkData into an SkPicture replacing all the indices w/ 99 // promise images (all using the same GrBackendTexture and getting a ref to the 100 // appropriate PromiseImageCallbackContext) (via reinflateSKP). 101 // 102 // This class is then reset - dropping all of its refs on the PromiseImageCallbackContexts 103 // 104 // Each done callback unrefs its PromiseImageCallbackContext so, once all the promise images 105 // are done, the PromiseImageCallbackContext is freed and its GrBackendTexture removed 106 // from VRAM 107 // 108 // Note: if DDLs are going to be replayed multiple times, the reset call can be delayed until 109 // all the replaying is complete. This will pin the GrBackendTextures in VRAM. 110 class DDLPromiseImageHelper { 111 public: DDLPromiseImageHelper(const SkYUVAPixmapInfo::SupportedDataTypes & supportedYUVADataTypes)112 DDLPromiseImageHelper(const SkYUVAPixmapInfo::SupportedDataTypes& supportedYUVADataTypes) 113 : fSupportedYUVADataTypes(supportedYUVADataTypes) {} 114 ~DDLPromiseImageHelper() = default; 115 116 // Convert the SkPicture into SkData replacing all the SkImages with an index. 117 sk_sp<SkData> deflateSKP(const SkPicture* inputPicture); 118 119 void createCallbackContexts(GrDirectContext*); 120 121 void uploadAllToGPU(SkTaskGroup*, GrDirectContext*); 122 void deleteAllFromGPU(SkTaskGroup*, GrDirectContext*); 123 124 // reinflate a deflated SKP, replacing all the indices with promise images. 125 sk_sp<SkPicture> reinflateSKP(SkDeferredDisplayListRecorder*, 126 SkData* compressedPicture, 127 SkTArray<sk_sp<SkImage>>* promiseImages) const; 128 129 // Remove this class' refs on the PromiseImageCallbackContexts reset()130 void reset() { fImageInfo.reset(); } 131 132 private: 133 // This is the information extracted into this class from the parsing of the skp file. 134 // Once it has all been uploaded to the GPU and distributed to the promise images, it 135 // is all dropped via "reset". 136 class PromiseImageInfo { 137 public: 138 PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii); 139 PromiseImageInfo(PromiseImageInfo&& other); 140 ~PromiseImageInfo(); 141 index()142 int index() const { return fIndex; } originalUniqueID()143 uint32_t originalUniqueID() const { return fOriginalUniqueID; } isYUV()144 bool isYUV() const { return fYUVAPixmaps.isValid(); } 145 overallWidth()146 int overallWidth() const { return fImageInfo.width(); } overallHeight()147 int overallHeight() const { return fImageInfo.height(); } overallColorType()148 SkColorType overallColorType() const { return fImageInfo.colorType(); } overallAlphaType()149 SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); } refOverallColorSpace()150 sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); } 151 yuvaInfo()152 const SkYUVAInfo& yuvaInfo() const { return fYUVAPixmaps.yuvaInfo(); } 153 yuvPixmap(int index)154 const SkPixmap& yuvPixmap(int index) const { 155 SkASSERT(this->isYUV()); 156 return fYUVAPixmaps.planes()[index]; 157 } 158 baseLevel()159 const SkBitmap& baseLevel() const { 160 SkASSERT(!this->isYUV()); 161 return fBaseLevel; 162 } 163 // This returns an array of all the available mipLevels - suitable for passing into 164 // createBackendTexture. 165 std::unique_ptr<SkPixmap[]> normalMipLevels() const; 166 int numMipLevels() const; 167 setCallbackContext(int index,sk_sp<PromiseImageCallbackContext> callbackContext)168 void setCallbackContext(int index, sk_sp<PromiseImageCallbackContext> callbackContext) { 169 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1)); 170 fCallbackContexts[index] = callbackContext; 171 } callbackContext(int index)172 PromiseImageCallbackContext* callbackContext(int index) const { 173 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1)); 174 return fCallbackContexts[index].get(); 175 } refCallbackContext(int index)176 sk_sp<PromiseImageCallbackContext> refCallbackContext(int index) const { 177 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1)); 178 return fCallbackContexts[index]; 179 } 180 mipMapped(int index)181 GrMipmapped mipMapped(int index) const { 182 if (this->isYUV()) { 183 return GrMipmapped::kNo; 184 } 185 return fMipLevels ? GrMipmapped::kYes : GrMipmapped::kNo; 186 } backendFormat(int index)187 const GrBackendFormat& backendFormat(int index) const { 188 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1)); 189 return fCallbackContexts[index]->backendFormat(); 190 } promiseTexture(int index)191 const SkPromiseImageTexture* promiseTexture(int index) const { 192 SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1)); 193 return fCallbackContexts[index]->promiseImageTexture(); 194 } 195 196 void setMipLevels(const SkBitmap& baseLevel, std::unique_ptr<SkMipmap> mipLevels); 197 198 /** Takes ownership of the plane data. */ setYUVPlanes(SkYUVAPixmaps yuvaPixmaps)199 void setYUVPlanes(SkYUVAPixmaps yuvaPixmaps) { fYUVAPixmaps = std::move(yuvaPixmaps); } 200 201 private: 202 const int fIndex; // index in the 'fImageInfo' array 203 const uint32_t fOriginalUniqueID; // original ID for deduping 204 205 const SkImageInfo fImageInfo; // info for the overarching image 206 207 // CPU-side cache of a normal SkImage's mipmap levels 208 SkBitmap fBaseLevel; 209 std::unique_ptr<SkMipmap> fMipLevels; 210 211 // CPU-side cache of a YUV SkImage's contents 212 SkYUVAPixmaps fYUVAPixmaps; 213 214 // Up to SkYUVASizeInfo::kMaxCount for a YUVA image. Only one for a normal image. 215 sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVASizeInfo::kMaxCount]; 216 }; 217 218 // This stack-based context allows each thread to re-inflate the image indices into 219 // promise images while still using the same GrBackendTexture. 220 struct PerRecorderContext { 221 SkDeferredDisplayListRecorder* fRecorder; 222 const DDLPromiseImageHelper* fHelper; 223 SkTArray<sk_sp<SkImage>>* fPromiseImages; 224 }; 225 226 static void CreateBETexturesForPromiseImage(GrDirectContext*, PromiseImageInfo*); 227 static void DeleteBETexturesForPromiseImage(PromiseImageInfo*); 228 229 static sk_sp<SkImage> CreatePromiseImages(const void* rawData, size_t length, void* ctxIn); 230 isValidID(int id)231 bool isValidID(int id) const { return id >= 0 && id < fImageInfo.count(); } getInfo(int id)232 const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; } 233 void uploadImage(GrDirectContext*, PromiseImageInfo*); 234 235 // returns -1 if not found 236 int findImage(SkImage* image) const; 237 238 // returns -1 on failure 239 int addImage(SkImage* image); 240 241 // returns -1 on failure 242 int findOrDefineImage(SkImage* image); 243 244 SkYUVAPixmapInfo::SupportedDataTypes fSupportedYUVADataTypes; 245 SkTArray<PromiseImageInfo> fImageInfo; 246 }; 247 248 #endif 249