Add ddl support to drawing to wrapped vulkan secondary command buffers. Bug: skia: Change-Id: I3ddb6b1e923b8c1733b6a0e219efffa36e665fa2 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/189282 Commit-Queue: Greg Daniel <egdaniel@google.com> Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/include/core/SkSurfaceCharacterization.h b/include/core/SkSurfaceCharacterization.h index 5e6066c..4d0aa2b 100644 --- a/include/core/SkSurfaceCharacterization.h +++ b/include/core/SkSurfaceCharacterization.h
@@ -86,6 +86,7 @@ private: friend class SkSurface_Gpu; // for 'set' & 'config' + friend class GrVkSecondaryCBDrawContext; // for 'set' & 'config' friend class GrContextThreadSafeProxy; // for private ctor friend class SkDeferredDisplayListRecorder; // for 'config' friend class SkSurface; // for 'config'
diff --git a/include/private/GrRenderTargetProxy.h b/include/private/GrRenderTargetProxy.h index 3cedf74..4eb6be6 100644 --- a/include/private/GrRenderTargetProxy.h +++ b/include/private/GrRenderTargetProxy.h
@@ -71,6 +71,8 @@ GrRenderTargetProxy(const GrCaps&, const GrBackendFormat&, const GrSurfaceDesc&, GrSurfaceOrigin, SkBackingFit, SkBudgeted, GrInternalSurfaceFlags); + enum class WrapsVkSecondaryCB : bool { kNo = false, kYes = true }; + // Lazy-callback version // There are two main use cases for lazily-instantiated proxies: // basic knowledge - width, height, config, samples, origin are known @@ -83,10 +85,10 @@ // know the final size until flush time. GrRenderTargetProxy(LazyInstantiateCallback&&, LazyInstantiationType lazyType, const GrBackendFormat&, const GrSurfaceDesc&, GrSurfaceOrigin, - SkBackingFit, SkBudgeted, GrInternalSurfaceFlags); + SkBackingFit, SkBudgeted, GrInternalSurfaceFlags, + WrapsVkSecondaryCB wrapsVkSecondaryCB); // Wrapped version - enum class WrapsVkSecondaryCB : bool { kNo = false, kYes = true }; GrRenderTargetProxy(sk_sp<GrSurface>, GrSurfaceOrigin, WrapsVkSecondaryCB wrapsVkSecondaryCB = WrapsVkSecondaryCB::kNo);
diff --git a/src/core/SkDeferredDisplayListRecorder.cpp b/src/core/SkDeferredDisplayListRecorder.cpp index 2422de7..8063349 100644 --- a/src/core/SkDeferredDisplayListRecorder.cpp +++ b/src/core/SkDeferredDisplayListRecorder.cpp
@@ -115,6 +115,18 @@ } } + 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; + } + } + GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; desc.fWidth = fCharacterization.width(); @@ -163,7 +175,8 @@ surfaceFlags, optionalTextureInfo, SkBackingFit::kExact, - SkBudgeted::kYes); + SkBudgeted::kYes, + fCharacterization.vulkanSecondaryCBCompatible()); sk_sp<GrSurfaceContext> c = fContext->priv().makeWrappedSurfaceContext( std::move(proxy),
diff --git a/src/gpu/GrProxyProvider.cpp b/src/gpu/GrProxyProvider.cpp index d65320a..d4f5555 100644 --- a/src/gpu/GrProxyProvider.cpp +++ b/src/gpu/GrProxyProvider.cpp
@@ -691,7 +691,8 @@ sk_sp<GrRenderTargetProxy> GrProxyProvider::createLazyRenderTargetProxy( LazyInstantiateCallback&& callback, const GrBackendFormat& format, const GrSurfaceDesc& desc, GrSurfaceOrigin origin, GrInternalSurfaceFlags surfaceFlags, - const TextureInfo* textureInfo, SkBackingFit fit, SkBudgeted budgeted) { + const TextureInfo* textureInfo, SkBackingFit fit, SkBudgeted budgeted, + bool wrapsVkSecondaryCB) { SkASSERT((desc.fWidth <= 0 && desc.fHeight <= 0) || (desc.fWidth > 0 && desc.fHeight > 0)); @@ -714,13 +715,21 @@ : LazyInstantiationType::kMultipleUse; if (textureInfo) { + // Wrapped vulkan secondary command buffers don't support texturing since we won't have an + // actual VkImage to texture from. + SkASSERT(!wrapsVkSecondaryCB); return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy( std::move(callback), lazyType, format, desc, origin, textureInfo->fMipMapped, fit, budgeted, surfaceFlags)); } + GrRenderTargetProxy::WrapsVkSecondaryCB vkSCB = + wrapsVkSecondaryCB ? GrRenderTargetProxy::WrapsVkSecondaryCB::kYes + : GrRenderTargetProxy::WrapsVkSecondaryCB::kNo; + return sk_sp<GrRenderTargetProxy>(new GrRenderTargetProxy( - std::move(callback), lazyType, format, desc, origin, fit, budgeted, surfaceFlags)); + std::move(callback), lazyType, format, desc, origin, fit, budgeted, surfaceFlags, + vkSCB)); } sk_sp<GrTextureProxy> GrProxyProvider::MakeFullyLazyProxy(LazyInstantiateCallback&& callback,
diff --git a/src/gpu/GrProxyProvider.h b/src/gpu/GrProxyProvider.h index 8f3007d..40f2e62 100644 --- a/src/gpu/GrProxyProvider.h +++ b/src/gpu/GrProxyProvider.h
@@ -180,7 +180,8 @@ GrInternalSurfaceFlags, const TextureInfo*, SkBackingFit, - SkBudgeted); + SkBudgeted, + bool wrapsVkSecondaryCB); /** * Fully lazy proxies have unspecified width and height. Methods that rely on those values
diff --git a/src/gpu/GrRenderTargetProxy.cpp b/src/gpu/GrRenderTargetProxy.cpp index 3f7b7e0..a9f23ff 100644 --- a/src/gpu/GrRenderTargetProxy.cpp +++ b/src/gpu/GrRenderTargetProxy.cpp
@@ -39,12 +39,13 @@ LazyInstantiationType lazyType, const GrBackendFormat& format, const GrSurfaceDesc& desc, GrSurfaceOrigin origin, SkBackingFit fit, - SkBudgeted budgeted, GrInternalSurfaceFlags surfaceFlags) + SkBudgeted budgeted, GrInternalSurfaceFlags surfaceFlags, + WrapsVkSecondaryCB wrapsVkSecondaryCB) : INHERITED(std::move(callback), lazyType, format, desc, origin, fit, budgeted, surfaceFlags) , fSampleCnt(desc.fSampleCnt) , fNeedsStencil(false) - , fWrapsVkSecondaryCB(WrapsVkSecondaryCB::kNo) { + , fWrapsVkSecondaryCB(wrapsVkSecondaryCB) { SkASSERT(SkToBool(kRenderTarget_GrSurfaceFlag & desc.fFlags)); }
diff --git a/src/gpu/GrTextureRenderTargetProxy.cpp b/src/gpu/GrTextureRenderTargetProxy.cpp index 3e52b2c..d217876 100644 --- a/src/gpu/GrTextureRenderTargetProxy.cpp +++ b/src/gpu/GrTextureRenderTargetProxy.cpp
@@ -46,7 +46,7 @@ // Since we have virtual inheritance, we initialize GrSurfaceProxy directly. Send null // callbacks to the texture and RT proxies simply to route to the appropriate constructors. , GrRenderTargetProxy(LazyInstantiateCallback(), lazyType, format, desc, origin, fit, - budgeted, surfaceFlags) + budgeted, surfaceFlags, WrapsVkSecondaryCB::kNo) , GrTextureProxy(LazyInstantiateCallback(), lazyType, format, desc, origin, mipMapped, fit, budgeted, surfaceFlags) {}
diff --git a/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp b/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp index 7618141..8083f57 100644 --- a/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp +++ b/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp
@@ -9,10 +9,13 @@ #include "GrContext.h" #include "GrContextPriv.h" +#include "GrContextThreadSafeProxyPriv.h" #include "GrRenderTargetContext.h" +#include "SkDeferredDisplayList.h" #include "SkGpuDevice.h" #include "SkImageInfo.h" -#include "SkSurfaceProps.h" +#include "SkSurfaceCharacterization.h" +#include "SkSurfacePriv.h" #include "vk/GrVkTypes.h" sk_sp<GrVkSecondaryCBDrawContext> GrVkSecondaryCBDrawContext::Make(GrContext* ctx, @@ -39,11 +42,14 @@ return nullptr; } - return sk_sp<GrVkSecondaryCBDrawContext>(new GrVkSecondaryCBDrawContext(std::move(device))); + return sk_sp<GrVkSecondaryCBDrawContext>(new GrVkSecondaryCBDrawContext(std::move(device), + props)); } -GrVkSecondaryCBDrawContext::GrVkSecondaryCBDrawContext(sk_sp<SkGpuDevice> device) - : fDevice(device) {} +GrVkSecondaryCBDrawContext::GrVkSecondaryCBDrawContext(sk_sp<SkGpuDevice> device, + const SkSurfaceProps* props) + : fDevice(device) + , fProps(SkSurfacePropsCopyOrDefault(props)) {} GrVkSecondaryCBDrawContext::~GrVkSecondaryCBDrawContext() { SkASSERT(!fDevice); @@ -71,3 +77,96 @@ fDevice.reset(); } +bool GrVkSecondaryCBDrawContext::characterize(SkSurfaceCharacterization* characterization) const { + GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext(); + GrContext* ctx = fDevice->context(); + + int maxResourceCount; + size_t maxResourceBytes; + ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes); + + // We current don't support textured GrVkSecondaryCBDrawContexts. + SkASSERT(!rtc->asTextureProxy()); + + // TODO: the addition of colorType to the surfaceContext should remove this calculation + SkColorType ct; + if (!GrPixelConfigToColorType(rtc->colorSpaceInfo().config(), &ct)) { + return false; + } + + SkImageInfo ii = SkImageInfo::Make(rtc->width(), rtc->height(), ct, kPremul_SkAlphaType, + rtc->colorSpaceInfo().refColorSpace()); + + characterization->set(ctx->threadSafeProxy(), maxResourceBytes, ii, rtc->origin(), + rtc->colorSpaceInfo().config(), rtc->fsaaType(), rtc->numStencilSamples(), + SkSurfaceCharacterization::Textureable(false), + SkSurfaceCharacterization::MipMapped(false), + SkSurfaceCharacterization::UsesGLFBO0(false), + SkSurfaceCharacterization::VulkanSecondaryCBCompatible(true), + this->props()); + + return true; +} + +bool GrVkSecondaryCBDrawContext::isCompatible( + const SkSurfaceCharacterization& characterization) const { + GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext(); + GrContext* ctx = fDevice->context(); + + if (!characterization.isValid()) { + return false; + } + + if (!characterization.vulkanSecondaryCBCompatible()) { + return false; + } + + // As long as the current state in the context allows for greater or equal resources, + // we allow the DDL to be replayed. + // DDL TODO: should we just remove the resource check and ignore the cache limits on playback? + int maxResourceCount; + size_t maxResourceBytes; + ctx->getResourceCacheLimits(&maxResourceCount, &maxResourceBytes); + + if (characterization.isTextureable()) { + // We don't support textureable DDL when rendering to a GrVkSecondaryCBDrawContext. + return false; + } + + if (characterization.usesGLFBO0()) { + return false; + } + + // TODO: the addition of colorType to the surfaceContext should remove this calculation + SkColorType rtcColorType; + if (!GrPixelConfigToColorType(rtc->colorSpaceInfo().config(), &rtcColorType)) { + return false; + } + + return characterization.contextInfo() && characterization.contextInfo()->priv().matches(ctx) && + characterization.cacheMaxResourceBytes() <= maxResourceBytes && + characterization.origin() == rtc->origin() && + characterization.config() == rtc->colorSpaceInfo().config() && + characterization.width() == rtc->width() && + characterization.height() == rtc->height() && + characterization.colorType() == rtcColorType && + characterization.fsaaType() == rtc->fsaaType() && + characterization.stencilCount() == rtc->numStencilSamples() && + SkColorSpace::Equals(characterization.colorSpace(), + rtc->colorSpaceInfo().colorSpace()) && + characterization.surfaceProps() == rtc->surfaceProps(); +} + +bool GrVkSecondaryCBDrawContext::draw(SkDeferredDisplayList* ddl) { + if (!ddl || !this->isCompatible(ddl->characterization())) { + return false; + } + + GrRenderTargetContext* rtc = fDevice->accessRenderTargetContext(); + GrContext* ctx = fDevice->context(); + + ctx->priv().copyOpListsFromDDL(ddl, rtc->asRenderTargetProxy()); + return true; +} + +
diff --git a/src/gpu/vk/GrVkSecondaryCBDrawContext.h b/src/gpu/vk/GrVkSecondaryCBDrawContext.h index c6ea9f9..23d6903 100644 --- a/src/gpu/vk/GrVkSecondaryCBDrawContext.h +++ b/src/gpu/vk/GrVkSecondaryCBDrawContext.h
@@ -10,6 +10,7 @@ #include "SkTypes.h" #include "SkRefCnt.h" +#include "SkSurfaceProps.h" class GrBackendSemaphore; class GrContext; @@ -91,15 +92,20 @@ // are still in use by the GPU. void releaseResources(); + const SkSurfaceProps& props() const { return fProps; } + // TODO: Fill out these calls to support DDL bool characterize(SkSurfaceCharacterization* characterization) const; bool draw(SkDeferredDisplayList* deferredDisplayList); private: - explicit GrVkSecondaryCBDrawContext(sk_sp<SkGpuDevice>); + explicit GrVkSecondaryCBDrawContext(sk_sp<SkGpuDevice>, const SkSurfaceProps*); + + bool isCompatible(const SkSurfaceCharacterization& characterization) const; sk_sp<SkGpuDevice> fDevice; std::unique_ptr<SkCanvas> fCachedCanvas; + const SkSurfaceProps fProps; typedef SkRefCnt INHERITED; };
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp index 2df1e9d..aa83d1f 100644 --- a/src/image/SkSurface_Gpu.cpp +++ b/src/image/SkSurface_Gpu.cpp
@@ -212,6 +212,10 @@ return false; } + if (characterization.vulkanSecondaryCBCompatible()) { + return false; + } + // As long as the current state if the context allows for greater or equal resources, // we allow the DDL to be replayed. // DDL TODO: should we just remove the resource check and ignore the cache limits on playback?