123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- /*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #ifndef PromiseImageHelper_DEFINED
- #define PromiseImageHelper_DEFINED
- #include "include/core/SkBitmap.h"
- #include "include/core/SkDeferredDisplayListRecorder.h"
- #include "include/core/SkPromiseImageTexture.h"
- #include "include/core/SkYUVAIndex.h"
- #include "include/core/SkYUVASizeInfo.h"
- #include "include/gpu/GrBackendSurface.h"
- #include "include/private/SkTArray.h"
- #include "src/core/SkCachedData.h"
- #include "src/core/SkTLazy.h"
- class GrContext;
- class SkImage;
- class SkPicture;
- struct SkYUVAIndex;
- // This class consolidates tracking & extraction of the original image data from an skp,
- // the upload of said data to the GPU and the fulfillment of promise images.
- //
- // The way this works is:
- // the original skp is converted to SkData and all its image info is extracted into this
- // class and only indices into this class are left in the SkData (via deflateSKP)
- //
- // Prior to replaying in threads, all the images stored in this class are uploaded to the
- // gpu and PromiseImageCallbackContexts are created for them (via uploadAllToGPU)
- //
- // Each thread reinflates the SkData into an SkPicture replacing all the indices w/
- // promise images (all using the same GrBackendTexture and getting a ref to the
- // appropriate PromiseImageCallbackContext) (via reinflateSKP).
- //
- // This class is then reset - dropping all of its refs on the PromiseImageCallbackContexts
- //
- // Each done callback unrefs its PromiseImageCallbackContext so, once all the promise images
- // are done, the PromiseImageCallbackContext is freed and its GrBackendTexture removed
- // from VRAM
- //
- // Note: if DDLs are going to be replayed multiple times, the reset call can be delayed until
- // all the replaying is complete. This will pin the GrBackendTextures in VRAM.
- class DDLPromiseImageHelper {
- public:
- DDLPromiseImageHelper() = default;
- ~DDLPromiseImageHelper() = default;
- // Convert the SkPicture into SkData replacing all the SkImages with an index.
- sk_sp<SkData> deflateSKP(const SkPicture* inputPicture);
- void uploadAllToGPU(GrContext* context);
- // reinflate a deflated SKP, replacing all the indices with promise images.
- sk_sp<SkPicture> reinflateSKP(SkDeferredDisplayListRecorder*,
- SkData* compressedPicture,
- SkTArray<sk_sp<SkImage>>* promiseImages) const;
- // Remove this class' refs on the PromiseImageCallbackContexts
- void reset() { fImageInfo.reset(); }
- private:
- // This class acts as a proxy for a GrBackendTexture that is part of an image.
- // Whenever a promise image is created for the image, the promise image receives a ref to
- // potentially several of these objects. Once all the promise images receive their done
- // callbacks this object is deleted - removing the GrBackendTexture from VRAM.
- // Note that while the DDLs are being created in the threads, the PromiseImageHelper holds
- // a ref on all the PromiseImageCallbackContexts. However, once all the threads are done
- // it drops all of its refs (via "reset").
- class PromiseImageCallbackContext : public SkRefCnt {
- public:
- PromiseImageCallbackContext(GrContext* context) : fContext(context) {}
- ~PromiseImageCallbackContext();
- void setBackendTexture(const GrBackendTexture& backendTexture);
- sk_sp<SkPromiseImageTexture> fulfill() {
- SkASSERT(fPromiseImageTexture);
- SkASSERT(fUnreleasedFulfills >= 0);
- ++fUnreleasedFulfills;
- ++fTotalFulfills;
- return fPromiseImageTexture;
- }
- void release() {
- SkASSERT(fUnreleasedFulfills > 0);
- --fUnreleasedFulfills;
- ++fTotalReleases;
- }
- void done() {
- ++fDoneCnt;
- SkASSERT(fDoneCnt <= fNumImages);
- }
- void wasAddedToImage() { fNumImages++; }
- const SkPromiseImageTexture* promiseImageTexture() const {
- return fPromiseImageTexture.get();
- }
- private:
- GrContext* fContext;
- sk_sp<SkPromiseImageTexture> fPromiseImageTexture;
- int fNumImages = 0;
- int fTotalFulfills = 0;
- int fTotalReleases = 0;
- int fUnreleasedFulfills = 0;
- int fDoneCnt = 0;
- typedef SkRefCnt INHERITED;
- };
- // This is the information extracted into this class from the parsing of the skp file.
- // Once it has all been uploaded to the GPU and distributed to the promise images, it
- // is all dropped via "reset".
- class PromiseImageInfo {
- public:
- PromiseImageInfo(int index, uint32_t originalUniqueID, const SkImageInfo& ii)
- : fIndex(index)
- , fOriginalUniqueID(originalUniqueID)
- , fImageInfo(ii) {
- }
- ~PromiseImageInfo() {}
- int index() const { return fIndex; }
- uint32_t originalUniqueID() const { return fOriginalUniqueID; }
- bool isYUV() const { return SkToBool(fYUVData.get()); }
- int overallWidth() const { return fImageInfo.width(); }
- int overallHeight() const { return fImageInfo.height(); }
- SkColorType overallColorType() const { return fImageInfo.colorType(); }
- SkAlphaType overallAlphaType() const { return fImageInfo.alphaType(); }
- sk_sp<SkColorSpace> refOverallColorSpace() const { return fImageInfo.refColorSpace(); }
- SkYUVColorSpace yuvColorSpace() const {
- SkASSERT(this->isYUV());
- return fYUVColorSpace;
- }
- const SkYUVAIndex* yuvaIndices() const {
- SkASSERT(this->isYUV());
- return fYUVAIndices;
- }
- const SkPixmap& yuvPixmap(int index) const {
- SkASSERT(this->isYUV());
- SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
- return fYUVPlanes[index];
- }
- const SkBitmap& normalBitmap() const {
- SkASSERT(!this->isYUV());
- return fBitmap;
- }
- void setCallbackContext(int index, sk_sp<PromiseImageCallbackContext> callbackContext) {
- SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
- fCallbackContexts[index] = callbackContext;
- }
- PromiseImageCallbackContext* callbackContext(int index) const {
- SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
- return fCallbackContexts[index].get();
- }
- sk_sp<PromiseImageCallbackContext> refCallbackContext(int index) const {
- SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
- return fCallbackContexts[index];
- }
- const SkPromiseImageTexture* promiseTexture(int index) const {
- SkASSERT(index >= 0 && index < (this->isYUV() ? SkYUVASizeInfo::kMaxCount : 1));
- return fCallbackContexts[index]->promiseImageTexture();
- }
- void setNormalBitmap(const SkBitmap& bm) { fBitmap = bm; }
- void setYUVData(sk_sp<SkCachedData> yuvData,
- SkYUVAIndex yuvaIndices[SkYUVAIndex::kIndexCount],
- SkYUVColorSpace cs) {
- fYUVData = yuvData;
- memcpy(fYUVAIndices, yuvaIndices, sizeof(fYUVAIndices));
- fYUVColorSpace = cs;
- }
- void addYUVPlane(int index, const SkImageInfo& ii, const void* plane, size_t widthBytes) {
- SkASSERT(this->isYUV());
- SkASSERT(index >= 0 && index < SkYUVASizeInfo::kMaxCount);
- fYUVPlanes[index].reset(ii, plane, widthBytes);
- }
- private:
- const int fIndex; // index in the 'fImageInfo' array
- const uint32_t fOriginalUniqueID; // original ID for deduping
- const SkImageInfo fImageInfo; // info for the overarching image
- // CPU-side cache of a normal SkImage's contents
- SkBitmap fBitmap;
- // CPU-side cache of a YUV SkImage's contents
- sk_sp<SkCachedData> fYUVData; // when !null, this is a YUV image
- SkYUVColorSpace fYUVColorSpace = kJPEG_SkYUVColorSpace;
- SkYUVAIndex fYUVAIndices[SkYUVAIndex::kIndexCount];
- SkPixmap fYUVPlanes[SkYUVASizeInfo::kMaxCount];
- // Up to SkYUVASizeInfo::kMaxCount for a YUVA image. Only one for a normal image.
- sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVASizeInfo::kMaxCount];
- };
- // This stack-based context allows each thread to re-inflate the image indices into
- // promise images while still using the same GrBackendTexture.
- struct PerRecorderContext {
- SkDeferredDisplayListRecorder* fRecorder;
- const DDLPromiseImageHelper* fHelper;
- SkTArray<sk_sp<SkImage>>* fPromiseImages;
- };
- static sk_sp<SkPromiseImageTexture> PromiseImageFulfillProc(void* textureContext) {
- auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
- return callbackContext->fulfill();
- }
- static void PromiseImageReleaseProc(void* textureContext) {
- auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
- callbackContext->release();
- }
- static void PromiseImageDoneProc(void* textureContext) {
- auto callbackContext = static_cast<PromiseImageCallbackContext*>(textureContext);
- callbackContext->done();
- callbackContext->unref();
- }
- static sk_sp<SkImage> PromiseImageCreator(const void* rawData, size_t length, void* ctxIn);
- bool isValidID(int id) const { return id >= 0 && id < fImageInfo.count(); }
- const PromiseImageInfo& getInfo(int id) const { return fImageInfo[id]; }
- void uploadImage(GrContext*, PromiseImageInfo*);
- // returns -1 if not found
- int findImage(SkImage* image) const;
- // returns -1 on failure
- int addImage(SkImage* image);
- // returns -1 on failure
- int findOrDefineImage(SkImage* image);
- SkTArray<PromiseImageInfo> fImageInfo;
- };
- #endif
|