* 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;
class DDLPromiseImageHelper {
public:
DDLPromiseImageHelper() = default;
~DDLPromiseImageHelper() = default;
sk_sp<SkData> deflateSKP(const SkPicture* inputPicture);
void uploadAllToGPU(GrContext* context);
sk_sp<SkPicture> reinflateSKP(SkDeferredDisplayListRecorder*,
SkData* compressedPicture,
SkTArray<sk_sp<SkImage>>* promiseImages) const;
void reset() { fImageInfo.reset(); }
private:
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;
};
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;
const uint32_t fOriginalUniqueID;
const SkImageInfo fImageInfo;
SkBitmap fBitmap;
sk_sp<SkCachedData> fYUVData;
SkYUVColorSpace fYUVColorSpace = kJPEG_SkYUVColorSpace;
SkYUVAIndex fYUVAIndices[SkYUVAIndex::kIndexCount];
SkPixmap fYUVPlanes[SkYUVASizeInfo::kMaxCount];
sk_sp<PromiseImageCallbackContext> fCallbackContexts[SkYUVASizeInfo::kMaxCount];
};
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*);
int findImage(SkImage* image) const;
int addImage(SkImage* image);
int findOrDefineImage(SkImage* image);
SkTArray<PromiseImageInfo> fImageInfo;
};
#endif