| /* |
| * 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 |