blob: 1149c15d55253477b07c9bf175da468c15d1a7f7 [file] [log] [blame]
/*
* 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<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() { return nullptr; }
sk_sp<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
const GrBackendFormat& backendFormat,
int width,
int height,
GrMipMapped mipMapped,
GrSurfaceOrigin origin,
SkColorType colorType,
SkAlphaType alphaType,
sk_sp<SkColorSpace> colorSpace,
PromiseImageTextureFulfillProc textureFulfillProc,
PromiseImageTextureReleaseProc textureReleaseProc,
PromiseImageTextureDoneProc textureDoneProc,
PromiseImageTextureContext textureContext,
PromiseImageApiVersion) {
return nullptr;
}
sk_sp<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
SkYUVColorSpace yuvColorSpace,
const GrBackendFormat yuvaFormats[],
const SkISize yuvaSizes[],
const SkYUVAIndex yuvaIndices[4],
int imageWidth,
int imageHeight,
GrSurfaceOrigin imageOrigin,
sk_sp<SkColorSpace> 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<SkDeferredDisplayList::LazyProxyData>(
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<SkDeferredDisplayList::LazyProxyData> 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;
}
// FIXME: Why do we use GrMipMapped::kNo instead of SkSurfaceCharacterization::fIsMipMapped?
static constexpr GrProxyProvider::TextureInfo kTextureInfo{GrMipMapped::kNo,
GrTextureType::k2D};
const GrProxyProvider::TextureInfo* optionalTextureInfo = nullptr;
if (fCharacterization.isTextureable()) {
optionalTextureInfo = &kTextureInfo;
}
sk_sp<GrRenderTargetProxy> 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<GrSurface>(lazyProxyData->fReplayDest->peekSurface());
return GrSurfaceProxy::LazyCallbackResult(std::move(surface));
},
fCharacterization.backendFormat(),
desc,
fCharacterization.sampleCount(),
fCharacterization.origin(),
surfaceFlags,
optionalTextureInfo,
GrMipMapsStatus::kNotAllocated,
SkBackingFit::kExact,
SkBudgeted::kYes,
fCharacterization.isProtected(),
fCharacterization.vulkanSecondaryCBCompatible(),
GrSurfaceProxy::UseAllocator::kYes);
if (!proxy) {
return false;
}
auto c = fContext->priv().makeWrappedSurfaceContext(std::move(proxy),
grColorType,
kPremul_SkAlphaType,
fCharacterization.refColorSpace(),
&fCharacterization.surfaceProps());
SkASSERT(c->asRenderTargetContext());
std::unique_ptr<GrRenderTargetContext> rtc(c.release()->asRenderTargetContext());
fSurface = SkSurface_Gpu::MakeWrappedRenderTarget(fContext.get(), std::move(rtc));
return SkToBool(fSurface.get());
}
SkCanvas* SkDeferredDisplayListRecorder::getCanvas() {
if (!fContext) {
return nullptr;
}
if (!fSurface && !this->init()) {
return nullptr;
}
return fSurface->getCanvas();
}
std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() {
if (!fContext) {
return nullptr;
}
if (fSurface) {
SkCanvas* canvas = fSurface->getCanvas();
canvas->restoreToCount(0);
}
auto ddl = std::unique_ptr<SkDeferredDisplayList>(
new SkDeferredDisplayList(fCharacterization, std::move(fLazyProxyData)));
fContext->priv().moveRenderTasksToDDL(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<SkImage> SkDeferredDisplayListRecorder::makePromiseTexture(
const GrBackendFormat& backendFormat,
int width,
int height,
GrMipMapped mipMapped,
GrSurfaceOrigin origin,
SkColorType colorType,
SkAlphaType alphaType,
sk_sp<SkColorSpace> 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<SkImage> SkDeferredDisplayListRecorder::makeYUVAPromiseTexture(
SkYUVColorSpace yuvColorSpace,
const GrBackendFormat yuvaFormats[],
const SkISize yuvaSizes[],
const SkYUVAIndex yuvaIndices[4],
int imageWidth,
int imageHeight,
GrSurfaceOrigin imageOrigin,
sk_sp<SkColorSpace> 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