/* * Copyright 2017 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkDeferredDisplayListRecorder.h" #include "include/core/SkSurface.h" #include "include/core/SkSurfaceCharacterization.h" #include "include/private/SkDeferredDisplayList.h" #include "src/core/SkMessageBus.h" #if !SK_SUPPORT_GPU SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization&) {} SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() {} bool SkDeferredDisplayListRecorder::init() { return false; } SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { return nullptr; } std::unique_ptr SkDeferredDisplayListRecorder::detach() { return nullptr; } sk_sp SkDeferredDisplayListRecorder::makePromiseTexture( const GrBackendFormat& backendFormat, int width, int height, GrMipMapped mipMapped, GrSurfaceOrigin origin, SkColorType colorType, SkAlphaType alphaType, sk_sp colorSpace, PromiseImageTextureFulfillProc textureFulfillProc, PromiseImageTextureReleaseProc textureReleaseProc, PromiseImageTextureDoneProc textureDoneProc, PromiseImageTextureContext textureContext, PromiseImageApiVersion) { return nullptr; } sk_sp SkDeferredDisplayListRecorder::makeYUVAPromiseTexture( SkYUVColorSpace yuvColorSpace, const GrBackendFormat yuvaFormats[], const SkISize yuvaSizes[], const SkYUVAIndex yuvaIndices[4], int imageWidth, int imageHeight, GrSurfaceOrigin imageOrigin, sk_sp imageColorSpace, PromiseImageTextureFulfillProc textureFulfillProc, PromiseImageTextureReleaseProc textureReleaseProc, PromiseImageTextureDoneProc textureDoneProc, PromiseImageTextureContext textureContexts[], PromiseImageApiVersion) { return nullptr; } #else #include "include/core/SkPromiseImageTexture.h" #include "include/core/SkYUVASizeInfo.h" #include "include/gpu/GrTexture.h" #include "src/core/SkMakeUnique.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrProxyProvider.h" #include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/SkGr.h" #include "src/image/SkImage_Gpu.h" #include "src/image/SkImage_GpuYUVA.h" #include "src/image/SkSurface_Gpu.h" SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder(const SkSurfaceCharacterization& c) : fCharacterization(c) { if (fCharacterization.isValid()) { fContext = GrContextPriv::MakeDDL(fCharacterization.refContextInfo()); } } SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() { if (fContext) { auto proxyProvider = fContext->priv().proxyProvider(); // This allows the uniquely keyed proxies to keep their keys but removes their back // pointer to the about-to-be-deleted proxy provider. The proxies will use their // unique key to reattach to cached versions of themselves or to appropriately tag new // resources (if a cached version was not found). This system operates independent of // the replaying context's proxy provider (i.e., these uniquely keyed proxies will not // appear in the replaying proxy providers uniquely keyed proxy map). This should be fine // since no one else should be trying to reconnect to the orphaned proxies and orphaned // proxies from different DDLs that share the same key should simply reconnect to the // same cached resource. proxyProvider->orphanAllUniqueKeys(); } } bool SkDeferredDisplayListRecorder::init() { SkASSERT(fContext); SkASSERT(!fLazyProxyData); SkASSERT(!fSurface); if (!fCharacterization.isValid()) { return false; } fLazyProxyData = sk_sp( new SkDeferredDisplayList::LazyProxyData); auto proxyProvider = fContext->priv().proxyProvider(); const GrCaps* caps = fContext->priv().caps(); bool usesGLFBO0 = fCharacterization.usesGLFBO0(); if (usesGLFBO0) { if (GrBackendApi::kOpenGL != fContext->backend() || fCharacterization.isTextureable()) { return false; } } if (fCharacterization.vulkanSecondaryCBCompatible()) { // Because of the restrictive API allowed for a GrVkSecondaryCBDrawContext, we know ahead // of time that we don't be able to support certain parameter combinations. Specifially we // fail on usesGLFBO0 since we can't mix GL and Vulkan. We can't have a texturable object. // And finally the GrVkSecondaryCBDrawContext always assumes a top left origin. if (usesGLFBO0 || fCharacterization.isTextureable() || fCharacterization.origin() == kBottomLeft_GrSurfaceOrigin) { return false; } } GrColorType grColorType = SkColorTypeToGrColorType(fCharacterization.colorType()); GrPixelConfig config = caps->getConfigFromBackendFormat(fCharacterization.backendFormat(), grColorType); if (config == kUnknown_GrPixelConfig) { return false; } GrSurfaceDesc desc; desc.fWidth = fCharacterization.width(); desc.fHeight = fCharacterization.height(); desc.fConfig = config; sk_sp lazyProxyData = fLazyProxyData; // What we're doing here is we're creating a lazy proxy to back the SkSurface. The lazy // proxy, when instantiated, will use the GrRenderTarget that backs the SkSurface that the // DDL is being replayed into. GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone; if (usesGLFBO0) { surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0; } static constexpr GrProxyProvider::TextureInfo kTextureInfo{GrMipMapped::kNo, GrTextureType::k2D}; const GrProxyProvider::TextureInfo* optionalTextureInfo = nullptr; if (fCharacterization.isTextureable()) { optionalTextureInfo = &kTextureInfo; } sk_sp proxy = proxyProvider->createLazyRenderTargetProxy( [lazyProxyData](GrResourceProvider* resourceProvider) { // The proxy backing the destination surface had better have been instantiated // prior to the proxy backing the DLL's surface. Steal its GrRenderTarget. SkASSERT(lazyProxyData->fReplayDest->peekSurface()); auto surface = sk_ref_sp(lazyProxyData->fReplayDest->peekSurface()); return GrSurfaceProxy::LazyInstantiationResult(std::move(surface)); }, fCharacterization.backendFormat(), desc, fCharacterization.sampleCount(), fCharacterization.origin(), surfaceFlags, optionalTextureInfo, SkBackingFit::kExact, SkBudgeted::kYes, fCharacterization.isProtected(), fCharacterization.vulkanSecondaryCBCompatible()); if (!proxy) { return false; } sk_sp c = fContext->priv().makeWrappedSurfaceContext( std::move(proxy), grColorType, kPremul_SkAlphaType, fCharacterization.refColorSpace(), &fCharacterization.surfaceProps()); fSurface = SkSurface_Gpu::MakeWrappedRenderTarget(fContext.get(), sk_ref_sp(c->asRenderTargetContext())); return SkToBool(fSurface.get()); } SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { if (!fContext) { return nullptr; } if (!fSurface && !this->init()) { return nullptr; } return fSurface->getCanvas(); } std::unique_ptr SkDeferredDisplayListRecorder::detach() { if (!fContext) { return nullptr; } if (fSurface) { SkCanvas* canvas = fSurface->getCanvas(); canvas->restoreToCount(0); } auto ddl = std::unique_ptr( new SkDeferredDisplayList(fCharacterization, std::move(fLazyProxyData))); fContext->priv().moveOpListsToDDL(ddl.get()); // We want a new lazy proxy target for each recorded DDL so force the (lazy proxy-backed) // SkSurface to be regenerated for each DDL. fSurface = nullptr; return ddl; } sk_sp SkDeferredDisplayListRecorder::makePromiseTexture( const GrBackendFormat& backendFormat, int width, int height, GrMipMapped mipMapped, GrSurfaceOrigin origin, SkColorType colorType, SkAlphaType alphaType, sk_sp colorSpace, PromiseImageTextureFulfillProc textureFulfillProc, PromiseImageTextureReleaseProc textureReleaseProc, PromiseImageTextureDoneProc textureDoneProc, PromiseImageTextureContext textureContext, PromiseImageApiVersion version) { if (!fContext) { return nullptr; } return SkImage_Gpu::MakePromiseTexture(fContext.get(), backendFormat, width, height, mipMapped, origin, colorType, alphaType, std::move(colorSpace), textureFulfillProc, textureReleaseProc, textureDoneProc, textureContext, version); } sk_sp SkDeferredDisplayListRecorder::makeYUVAPromiseTexture( SkYUVColorSpace yuvColorSpace, const GrBackendFormat yuvaFormats[], const SkISize yuvaSizes[], const SkYUVAIndex yuvaIndices[4], int imageWidth, int imageHeight, GrSurfaceOrigin imageOrigin, sk_sp imageColorSpace, PromiseImageTextureFulfillProc textureFulfillProc, PromiseImageTextureReleaseProc textureReleaseProc, PromiseImageTextureDoneProc textureDoneProc, PromiseImageTextureContext textureContexts[], PromiseImageApiVersion version) { if (!fContext) { return nullptr; } return SkImage_GpuYUVA::MakePromiseYUVATexture(fContext.get(), yuvColorSpace, yuvaFormats, yuvaSizes, yuvaIndices, imageWidth, imageHeight, imageOrigin, std::move(imageColorSpace), textureFulfillProc, textureReleaseProc, textureDoneProc, textureContexts, version); } #endif