/* * 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 "SkDeferredDisplayListRecorder.h" #if SK_SUPPORT_GPU #include "GrContextPriv.h" #include "GrProxyProvider.h" #include "GrTexture.h" #include "SkGpuDevice.h" #include "SkGr.h" #include "SkSurface_Gpu.h" #endif #include "SkCanvas.h" // TODO: remove #include "SkDeferredDisplayList.h" #include "SkSurface.h" #include "SkSurfaceCharacterization.h" SkDeferredDisplayListRecorder::SkDeferredDisplayListRecorder( const SkSurfaceCharacterization& characterization) : fCharacterization(characterization) { } SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() { #if SK_SUPPORT_GPU && !defined(SK_RASTER_RECORDER_IMPLEMENTATION) auto proxyProvider = fContext->contextPriv().proxyProvider(); // DDL TODO: Remove this. DDL contexts should allow for deletion while still having live // uniquely keyed proxies. proxyProvider->removeAllUniqueKeys(); #endif } bool SkDeferredDisplayListRecorder::init() { SkASSERT(!fSurface); #ifdef SK_RASTER_RECORDER_IMPLEMENTATION // Use raster right now to allow threading const SkImageInfo ii = SkImageInfo::Make(fCharacterization.width(), fCharacterization.height(), kN32_SkColorType, kOpaque_SkAlphaType, fCharacterization.refColorSpace()); fSurface = SkSurface::MakeRaster(ii, &fCharacterization.surfaceProps()); return SkToBool(fSurface.get()); #else SkASSERT(!fLazyProxyData); #if SK_SUPPORT_GPU if (!fContext) { fContext = GrContextPriv::MakeDDL(fCharacterization.contextInfo()); if (!fContext) { return false; } } fLazyProxyData = sk_sp( new SkDeferredDisplayList::LazyProxyData); auto proxyProvider = fContext->contextPriv().proxyProvider(); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fOrigin = fCharacterization.origin(); desc.fWidth = fCharacterization.width(); desc.fHeight = fCharacterization.height(); desc.fConfig = fCharacterization.config(); desc.fSampleCnt = fCharacterization.stencilCount(); 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. sk_sp proxy = proxyProvider->createLazyRenderTargetProxy( [ lazyProxyData ] (GrResourceProvider* resourceProvider, GrSurfaceOrigin* /* outOrigin */) { if (!resourceProvider) { return sk_sp(); } // 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->priv().peekSurface()); return sk_ref_sp(lazyProxyData->fReplayDest->priv().peekSurface()); }, desc, GrProxyProvider::Textureable(fCharacterization.isTextureable()), GrMipMapped::kNo, SkBackingFit::kExact, SkBudgeted::kYes); sk_sp c = fContext->contextPriv().makeWrappedSurfaceContext( std::move(proxy), fCharacterization.refColorSpace(), &fCharacterization.surfaceProps()); fSurface = SkSurface_Gpu::MakeWrappedRenderTarget(fContext.get(), sk_ref_sp(c->asRenderTargetContext())); return SkToBool(fSurface.get()); #else return false; #endif #endif } SkCanvas* SkDeferredDisplayListRecorder::getCanvas() { if (!fSurface) { if (!this->init()) { return nullptr; } } return fSurface->getCanvas(); } std::unique_ptr SkDeferredDisplayListRecorder::detach() { #ifdef SK_RASTER_RECORDER_IMPLEMENTATION sk_sp img = fSurface->makeImageSnapshot(); fSurface.reset(); // TODO: need to wrap the opLists associated with the deferred draws // in the SkDeferredDisplayList. return std::unique_ptr( new SkDeferredDisplayList(fCharacterization, std::move(img))); #else #if SK_SUPPORT_GPU auto ddl = std::unique_ptr( new SkDeferredDisplayList(fCharacterization, std::move(fLazyProxyData))); fContext->contextPriv().moveOpListsToDDL(ddl.get()); return ddl; #else return nullptr; #endif #endif // SK_RASTER_RECORDER_IMPLEMENTATION }