| /* |
| * Copyright 2019 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/private/chromium/GrVkSecondaryCBDrawContext.h" |
| |
| #include "include/core/SkImageInfo.h" |
| #include "include/gpu/GrDirectContext.h" |
| #include "include/gpu/GrRecordingContext.h" |
| #include "include/gpu/ganesh/vk/GrVkBackendSurface.h" |
| #include "include/gpu/vk/GrVkTypes.h" |
| #include "include/private/chromium/GrDeferredDisplayList.h" |
| #include "include/private/chromium/GrSurfaceCharacterization.h" |
| #include "src/core/SkSurfacePriv.h" |
| #include "src/gpu/ganesh/GrContextThreadSafeProxyPriv.h" |
| #include "src/gpu/ganesh/GrDirectContextPriv.h" |
| #include "src/gpu/ganesh/GrProxyProvider.h" |
| #include "src/gpu/ganesh/GrRecordingContextPriv.h" |
| #include "src/gpu/ganesh/GrRenderTarget.h" |
| #include "src/gpu/ganesh/GrRenderTargetProxy.h" |
| #include "src/gpu/ganesh/GrResourceProvider.h" |
| #include "src/gpu/ganesh/GrSurfaceProxyView.h" |
| |
| sk_sp<GrVkSecondaryCBDrawContext> GrVkSecondaryCBDrawContext::Make(GrRecordingContext* rContext, |
| const SkImageInfo& imageInfo, |
| const GrVkDrawableInfo& vkInfo, |
| const SkSurfaceProps* props) { |
| if (!rContext) { |
| return nullptr; |
| } |
| |
| if (rContext->backend() != GrBackendApi::kVulkan) { |
| return nullptr; |
| } |
| |
| |
| GrProxyProvider* gpp = rContext->priv().proxyProvider(); |
| if (gpp->isAbandoned()) { |
| return nullptr; |
| } |
| |
| GrResourceProvider* resourceProvider = gpp->resourceProvider(); |
| if (!resourceProvider) { |
| return nullptr; |
| } |
| |
| sk_sp<GrRenderTarget> rt = resourceProvider->wrapVulkanSecondaryCBAsRenderTarget(imageInfo, |
| vkInfo); |
| if (!rt) { |
| return nullptr; |
| } |
| |
| SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable |
| SkASSERT(!rt->getUniqueKey().isValid()); |
| // This proxy should be unbudgeted because we're just wrapping an external resource |
| SkASSERT(GrBudgetedType::kBudgeted != rt->resourcePriv().budgetedType()); |
| |
| GrColorType colorType = SkColorTypeToGrColorType(imageInfo.colorType()); |
| |
| if (!gpp->caps()->isFormatAsColorTypeRenderable( |
| colorType, GrBackendFormats::MakeVk(vkInfo.fFormat), /*sampleCount=*/1)) { |
| return nullptr; |
| } |
| |
| sk_sp<GrRenderTargetProxy> proxy( |
| new GrRenderTargetProxy(std::move(rt), |
| GrSurfaceProxy::UseAllocator::kNo, |
| GrRenderTargetProxy::WrapsVkSecondaryCB::kYes)); |
| |
| if (!proxy) { |
| return nullptr; |
| } |
| |
| SkASSERT(proxy->isInstantiated()); |
| |
| auto device = rContext->priv().createDevice(SkColorTypeToGrColorType(imageInfo.colorType()), |
| std::move(proxy), |
| imageInfo.refColorSpace(), |
| kTopLeft_GrSurfaceOrigin, |
| SkSurfacePropsCopyOrDefault(props), |
| skgpu::ganesh::Device::InitContents::kUninit); |
| if (!device) { |
| return nullptr; |
| } |
| |
| return sk_sp<GrVkSecondaryCBDrawContext>(new GrVkSecondaryCBDrawContext(std::move(device), |
| props)); |
| } |
| |
| GrVkSecondaryCBDrawContext::GrVkSecondaryCBDrawContext(sk_sp<skgpu::ganesh::Device> device, |
| const SkSurfaceProps* props) |
| : fDevice(std::move(device)), fProps(SkSurfacePropsCopyOrDefault(props)) {} |
| |
| GrVkSecondaryCBDrawContext::~GrVkSecondaryCBDrawContext() { |
| SkASSERT(!fDevice); |
| SkASSERT(!fCachedCanvas.get()); |
| } |
| |
| SkCanvas* GrVkSecondaryCBDrawContext::getCanvas() { |
| if (!fCachedCanvas) { |
| fCachedCanvas = std::make_unique<SkCanvas>(fDevice); |
| } |
| return fCachedCanvas.get(); |
| } |
| |
| void GrVkSecondaryCBDrawContext::flush() { |
| auto dContext = GrAsDirectContext(fDevice->recordingContext()); |
| |
| if (dContext) { |
| dContext->priv().flushSurface(fDevice->targetProxy()); |
| dContext->submit(); |
| } |
| } |
| |
| bool GrVkSecondaryCBDrawContext::wait(int numSemaphores, |
| const GrBackendSemaphore waitSemaphores[], |
| bool deleteSemaphoresAfterWait) { |
| return fDevice->wait(numSemaphores, waitSemaphores, deleteSemaphoresAfterWait); |
| } |
| |
| void GrVkSecondaryCBDrawContext::releaseResources() { |
| fCachedCanvas.reset(); |
| fDevice.reset(); |
| } |
| |
| bool GrVkSecondaryCBDrawContext::characterize(GrSurfaceCharacterization* characterization) const { |
| auto direct = fDevice->recordingContext()->asDirectContext(); |
| if (!direct) { |
| return false; |
| } |
| |
| SkImageInfo ii = fDevice->imageInfo(); |
| if (ii.colorType() == kUnknown_SkColorType) { |
| return false; |
| } |
| |
| GrSurfaceProxyView readSurfaceView = fDevice->readSurfaceView(); |
| size_t maxResourceBytes = direct->getResourceCacheLimit(); |
| |
| // We current don't support textured GrVkSecondaryCBDrawContexts. |
| SkASSERT(!readSurfaceView.asTextureProxy()); |
| |
| GrBackendFormat format = readSurfaceView.asRenderTargetProxy()->backendFormat(); |
| int numSamples = readSurfaceView.asRenderTargetProxy()->numSamples(); |
| GrProtected isProtected = readSurfaceView.asRenderTargetProxy()->isProtected(); |
| |
| characterization->set(direct->threadSafeProxy(), |
| maxResourceBytes, |
| ii, |
| format, |
| readSurfaceView.origin(), |
| numSamples, |
| GrSurfaceCharacterization::Textureable(false), |
| skgpu::Mipmapped::kNo, |
| GrSurfaceCharacterization::UsesGLFBO0(false), |
| GrSurfaceCharacterization::VkRTSupportsInputAttachment(false), |
| GrSurfaceCharacterization::VulkanSecondaryCBCompatible(true), |
| isProtected, |
| this->props()); |
| |
| return true; |
| } |
| |
| bool GrVkSecondaryCBDrawContext::isCompatible( |
| const GrSurfaceCharacterization& characterization) const { |
| |
| auto dContext = fDevice->recordingContext()->asDirectContext(); |
| if (!dContext) { |
| return false; |
| } |
| |
| if (!characterization.isValid()) { |
| return false; |
| } |
| |
| if (!characterization.vulkanSecondaryCBCompatible()) { |
| return false; |
| } |
| |
| if (characterization.isTextureable()) { |
| // We don't support textureable DDL when rendering to a GrVkSecondaryCBDrawContext. |
| return false; |
| } |
| |
| if (characterization.usesGLFBO0()) { |
| return false; |
| } |
| |
| SkImageInfo ii = fDevice->imageInfo(); |
| if (ii.colorType() == kUnknown_SkColorType) { |
| return false; |
| } |
| |
| GrSurfaceProxyView readSurfaceView = fDevice->readSurfaceView(); |
| // 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? |
| size_t maxResourceBytes = dContext->getResourceCacheLimit(); |
| |
| GrBackendFormat format = readSurfaceView.asRenderTargetProxy()->backendFormat(); |
| int numSamples = readSurfaceView.asRenderTargetProxy()->numSamples(); |
| GrProtected isProtected = readSurfaceView.asRenderTargetProxy()->isProtected(); |
| |
| return characterization.contextInfo() && |
| characterization.contextInfo()->priv().matches(dContext) && |
| characterization.cacheMaxResourceBytes() <= maxResourceBytes && |
| characterization.origin() == readSurfaceView.origin() && |
| characterization.backendFormat() == format && |
| characterization.width() == ii.width() && |
| characterization.height() == ii.height() && |
| characterization.colorType() == ii.colorType() && |
| characterization.sampleCount() == numSamples && |
| SkColorSpace::Equals(characterization.colorSpace(), ii.colorInfo().colorSpace()) && |
| characterization.isProtected() == isProtected && |
| characterization.surfaceProps() == fDevice->surfaceProps(); |
| } |
| |
| #ifndef SK_DDL_IS_UNIQUE_POINTER |
| bool GrVkSecondaryCBDrawContext::draw(sk_sp<const GrDeferredDisplayList> ddl) { |
| #else |
| bool GrVkSecondaryCBDrawContext::draw(const GrDeferredDisplayList* ddl) { |
| #endif |
| if (!ddl || !this->isCompatible(ddl->characterization())) { |
| return false; |
| } |
| |
| auto direct = fDevice->recordingContext()->asDirectContext(); |
| if (!direct) { |
| return false; |
| } |
| |
| GrSurfaceProxyView readSurfaceView = fDevice->readSurfaceView(); |
| |
| direct->priv().createDDLTask(std::move(ddl), readSurfaceView.asRenderTargetProxyRef()); |
| return true; |
| } |