blob: 9a85e56414ae99c797bd6720c42fc56b14e24437 [file] [log] [blame]
/*
* 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 SkImage_GpuBase_DEFINED
#define SkImage_GpuBase_DEFINED
#include "GrBackendSurface.h"
#include "GrTypesPriv.h"
#include "SkImage_Base.h"
#include "SkYUVAIndex.h"
class GrContext;
class SkColorSpace;
class SkImage_GpuBase : public SkImage_Base {
public:
SkImage_GpuBase(sk_sp<GrContext>, int width, int height, uint32_t uniqueID,
SkAlphaType, SkBudgeted, sk_sp<SkColorSpace>);
~SkImage_GpuBase() override;
GrContext* context() const final { return fContext.get(); }
bool getROPixels(SkBitmap*, CachingHint) const final;
sk_sp<SkImage> onMakeSubset(const SkIRect& subset) const final;
bool onReadPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
int srcX, int srcY, CachingHint) const override;
sk_sp<GrTextureProxy> asTextureProxyRef() const override {
// we shouldn't end up calling this
SkASSERT(false);
return this->INHERITED::asTextureProxyRef();
}
sk_sp<GrTextureProxy> asTextureProxyRef(GrContext*, const GrSamplerState&,
SkScalar scaleAdjust[2]) const final;
sk_sp<GrTextureProxy> refPinnedTextureProxy(uint32_t* uniqueID) const final {
*uniqueID = this->uniqueID();
return this->asTextureProxyRef();
}
GrBackendTexture onGetBackendTexture(bool flushPendingGrContextIO,
GrSurfaceOrigin* origin) const final;
GrTexture* onGetTexture() const final;
sk_sp<SkImage> onMakeColorSpace(sk_sp<SkColorSpace>) const final;
bool onIsValid(GrContext*) const final;
#if GR_TEST_UTILS
void resetContext(sk_sp<GrContext> newContext) {
SkASSERT(fContext->uniqueID() == newContext->uniqueID());
fContext = newContext;
}
#endif
static bool ValidateBackendTexture(GrContext* ctx, const GrBackendTexture& tex,
GrPixelConfig* config, SkColorType ct, SkAlphaType at,
sk_sp<SkColorSpace> cs);
static bool MakeTempTextureProxies(GrContext* ctx, const GrBackendTexture yuvaTextures[],
int numTextures, const SkYUVAIndex [4],
GrSurfaceOrigin imageOrigin,
sk_sp<GrTextureProxy> tempTextureProxies[4]);
static SkAlphaType GetAlphaTypeFromYUVAIndices(const SkYUVAIndex yuvaIndices[4]) {
return -1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex ? kPremul_SkAlphaType
: kOpaque_SkAlphaType;
}
typedef ReleaseContext TextureContext;
typedef void(*TextureFulfillProc)(TextureContext textureContext, GrBackendTexture* outTexture);
typedef void(*PromiseDoneProc)(TextureContext textureContext);
protected:
static bool RenderYUVAToRGBA(GrContext* ctx, GrRenderTargetContext* renderTargetContext,
const SkRect& rect, SkYUVColorSpace yuvColorSpace,
const sk_sp<GrTextureProxy> proxies[4],
const SkYUVAIndex yuvaIndices[4]);
sk_sp<GrContext> fContext;
const SkAlphaType fAlphaType; // alpha type for final image
const SkBudgeted fBudgeted;
sk_sp<SkColorSpace> fColorSpace; // color space for final image
private:
typedef SkImage_Base INHERITED;
};
/**
* This helper holds the normal hard ref for the Release proc as well as a hard ref on the DoneProc.
* Thus when a GrTexture is being released, it will unref both the ReleaseProc and DoneProc.
*/
class SkPromiseReleaseProcHelper : public GrReleaseProcHelper {
public:
SkPromiseReleaseProcHelper(SkImage_GpuBase::TextureReleaseProc releaseProc,
SkImage_GpuBase::TextureContext context,
sk_sp<GrReleaseProcHelper> doneHelper)
: INHERITED(releaseProc, context)
, fDoneProcHelper(std::move(doneHelper)) {
}
void weak_dispose() const override {
// Call the inherited weak_dispose first so that we call the ReleaseProc before the DoneProc
// if we hold the last ref to the DoneProc.
INHERITED::weak_dispose();
fDoneProcHelper.reset();
}
private:
mutable sk_sp<GrReleaseProcHelper> fDoneProcHelper;
typedef GrReleaseProcHelper INHERITED;
};
/**
* This helper class manages the ref counting for the the ReleaseProc and DoneProc for promise
* images. It holds a weak ref on the ReleaseProc (hard refs are owned by GrTextures). The weak ref
* allows us to reuse an outstanding ReleaseProc (because we dropped our GrTexture but the GrTexture
* isn't done on the GPU) without needing to call FulfillProc again. It also holds a hard ref on the
* DoneProc. The idea is that after every flush we may call the ReleaseProc so that the client can
* free up their GPU memory if they want to. The life time of the DoneProc matches that of any
* outstanding ReleaseProc as well as the PromiseImageHelper. Thus we won't call the DoneProc until
* all ReleaseProcs are finished and we are finished with the PromiseImageHelper (i.e. won't call
* FulfillProc again).
*/
class SkPromiseImageHelper {
public:
SkPromiseImageHelper()
: fFulfillProc(nullptr)
, fReleaseProc(nullptr)
, fContext(nullptr)
, fDoneHelper(nullptr) {
}
void set(SkImage_GpuBase::TextureFulfillProc fulfillProc,
SkImage_GpuBase::TextureReleaseProc releaseProc,
SkImage_GpuBase::PromiseDoneProc doneProc,
SkImage_GpuBase::TextureContext context) {
fFulfillProc = fulfillProc;
fReleaseProc = releaseProc;
fContext = context;
fDoneHelper.reset(new GrReleaseProcHelper(doneProc, context));
}
SkPromiseImageHelper(SkImage_GpuBase::TextureFulfillProc fulfillProc,
SkImage_GpuBase::TextureReleaseProc releaseProc,
SkImage_GpuBase::PromiseDoneProc doneProc,
SkImage_GpuBase::TextureContext context)
: fFulfillProc(fulfillProc)
, fReleaseProc(releaseProc)
, fContext(context)
, fDoneHelper(new GrReleaseProcHelper(doneProc, context)) {
}
bool isValid() { return SkToBool(fDoneHelper); }
void reset() {
this->resetReleaseHelper();
fDoneHelper.reset();
}
sk_sp<GrTexture> getTexture(GrResourceProvider* resourceProvider, GrPixelConfig config);
private:
// Weak unrefs fReleaseHelper and sets it to null
void resetReleaseHelper() {
if (fReleaseHelper) {
fReleaseHelper->weak_unref();
fReleaseHelper = nullptr;
}
}
SkImage_GpuBase::TextureFulfillProc fFulfillProc;
SkImage_GpuBase::TextureReleaseProc fReleaseProc;
SkImage_GpuBase::TextureContext fContext;
// We cache the GrBackendTexture so that if we deleted the GrTexture but the the release proc
// has yet not been called (this can happen on Vulkan), then we can create a new texture without
// needing to call the fulfill proc again.
GrBackendTexture fBackendTex;
// The fReleaseHelper is used to track a weak ref on the release proc. This helps us make sure
// we are always pairing fulfill and release proc calls correctly.
SkPromiseReleaseProcHelper* fReleaseHelper = nullptr;
// We don't want to call the fDoneHelper until we are done with the PromiseImageHelper and all
// ReleaseHelpers are finished. Thus we hold a hard ref here and we will pass a hard ref to each
// fReleaseHelper we make.
sk_sp<GrReleaseProcHelper> fDoneHelper;
};
#endif