| /* |
| * 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 <memory> |
| |
| #include "include/gpu/GrContextThreadSafeProxy.h" |
| #include "src/gpu/ganesh/GrContextThreadSafeProxyPriv.h" |
| |
| #include "include/core/SkSurfaceCharacterization.h" |
| #include "src/gpu/ganesh/GrBaseContextPriv.h" |
| #include "src/gpu/ganesh/GrCaps.h" |
| #include "src/gpu/ganesh/GrThreadSafeCache.h" |
| #include "src/gpu/ganesh/GrThreadSafePipelineBuilder.h" |
| #include "src/gpu/ganesh/effects/GrSkSLFP.h" |
| #include "src/image/SkSurface_Gpu.h" |
| |
| #ifdef SK_VULKAN |
| #include "src/gpu/ganesh/vk/GrVkCaps.h" |
| #endif |
| |
| static int32_t next_id() { |
| static std::atomic<int32_t> nextID{1}; |
| int32_t id; |
| do { |
| id = nextID.fetch_add(1, std::memory_order_relaxed); |
| } while (id == SK_InvalidGenID); |
| return id; |
| } |
| |
| GrContextThreadSafeProxy::GrContextThreadSafeProxy(GrBackendApi backend, |
| const GrContextOptions& options) |
| : fBackend(backend), fOptions(options), fContextID(next_id()) { |
| } |
| |
| GrContextThreadSafeProxy::~GrContextThreadSafeProxy() = default; |
| |
| void GrContextThreadSafeProxy::init(sk_sp<const GrCaps> caps, |
| sk_sp<GrThreadSafePipelineBuilder> pipelineBuilder) { |
| fCaps = std::move(caps); |
| fTextBlobRedrawCoordinator = |
| std::make_unique<sktext::gpu::TextBlobRedrawCoordinator>(fContextID); |
| fThreadSafeCache = std::make_unique<GrThreadSafeCache>(); |
| fPipelineBuilder = std::move(pipelineBuilder); |
| } |
| |
| SkSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization( |
| size_t cacheMaxResourceBytes, |
| const SkImageInfo& ii, const GrBackendFormat& backendFormat, |
| int sampleCnt, GrSurfaceOrigin origin, |
| const SkSurfaceProps& surfaceProps, |
| bool isMipMapped, bool willUseGLFBO0, bool isTextureable, |
| GrProtected isProtected, bool vkRTSupportsInputAttachment, |
| bool forVulkanSecondaryCommandBuffer) { |
| SkASSERT(fCaps); |
| if (!backendFormat.isValid()) { |
| return {}; |
| } |
| |
| SkASSERT(isTextureable || !isMipMapped); |
| |
| if (GrBackendApi::kOpenGL != backendFormat.backend() && willUseGLFBO0) { |
| // The willUseGLFBO0 flags can only be used for a GL backend. |
| return {}; |
| } |
| |
| if (GrBackendApi::kVulkan != backendFormat.backend() && |
| (vkRTSupportsInputAttachment || forVulkanSecondaryCommandBuffer)) { |
| // The vkRTSupportsInputAttachment and forVulkanSecondaryCommandBuffer flags can only be |
| // used for a Vulkan backend. |
| return {}; |
| } |
| |
| if (!fCaps->mipmapSupport()) { |
| isMipMapped = false; |
| } |
| |
| if (ii.width() < 1 || ii.width() > fCaps->maxRenderTargetSize() || |
| ii.height() < 1 || ii.height() > fCaps->maxRenderTargetSize()) { |
| return {}; |
| } |
| |
| GrColorType grColorType = SkColorTypeToGrColorType(ii.colorType()); |
| |
| if (!fCaps->areColorTypeAndFormatCompatible(grColorType, backendFormat)) { |
| return {}; |
| } |
| |
| if (!fCaps->isFormatAsColorTypeRenderable(grColorType, backendFormat, sampleCnt)) { |
| return {}; |
| } |
| |
| sampleCnt = fCaps->getRenderTargetSampleCount(sampleCnt, backendFormat); |
| SkASSERT(sampleCnt); |
| |
| if (willUseGLFBO0 && isTextureable) { |
| return {}; |
| } |
| |
| if (isTextureable && !fCaps->isFormatTexturable(backendFormat, backendFormat.textureType())) { |
| // Skia doesn't agree that this is textureable. |
| return {}; |
| } |
| |
| if (forVulkanSecondaryCommandBuffer && |
| (isTextureable || isMipMapped || willUseGLFBO0 || vkRTSupportsInputAttachment)) { |
| return {}; |
| } |
| |
| if (GrBackendApi::kVulkan == backendFormat.backend()) { |
| if (GrBackendApi::kVulkan != fBackend) { |
| return {}; |
| } |
| |
| #ifdef SK_VULKAN |
| const GrVkCaps* vkCaps = (const GrVkCaps*) fCaps.get(); |
| |
| // The protection status of the characterization and the context need to match |
| if (isProtected != GrProtected(vkCaps->supportsProtectedMemory())) { |
| return {}; |
| } |
| #endif |
| } |
| |
| return SkSurfaceCharacterization( |
| sk_ref_sp<GrContextThreadSafeProxy>(this), |
| cacheMaxResourceBytes, ii, backendFormat, |
| origin, sampleCnt, |
| SkSurfaceCharacterization::Textureable(isTextureable), |
| SkSurfaceCharacterization::MipMapped(isMipMapped), |
| SkSurfaceCharacterization::UsesGLFBO0(willUseGLFBO0), |
| SkSurfaceCharacterization::VkRTSupportsInputAttachment(vkRTSupportsInputAttachment), |
| SkSurfaceCharacterization::VulkanSecondaryCBCompatible(forVulkanSecondaryCommandBuffer), |
| isProtected, |
| surfaceProps); |
| } |
| |
| GrBackendFormat GrContextThreadSafeProxy::defaultBackendFormat(SkColorType skColorType, |
| GrRenderable renderable) const { |
| SkASSERT(fCaps); |
| GrColorType grColorType = SkColorTypeToGrColorType(skColorType); |
| |
| GrBackendFormat format = fCaps->getDefaultBackendFormat(grColorType, renderable); |
| if (!format.isValid()) { |
| return GrBackendFormat(); |
| } |
| |
| SkASSERT(renderable == GrRenderable::kNo || |
| fCaps->isFormatAsColorTypeRenderable(grColorType, format)); |
| |
| return format; |
| } |
| |
| GrBackendFormat GrContextThreadSafeProxy::compressedBackendFormat(SkImage::CompressionType c) const { |
| SkASSERT(fCaps); |
| |
| GrBackendFormat format = fCaps->getBackendFormatFromCompressionType(c); |
| |
| SkASSERT(!format.isValid() || fCaps->isFormatTexturable(format, GrTextureType::k2D)); |
| return format; |
| } |
| |
| int GrContextThreadSafeProxy::maxSurfaceSampleCountForColorType(SkColorType colorType) const { |
| SkASSERT(fCaps); |
| |
| GrBackendFormat format = fCaps->getDefaultBackendFormat(SkColorTypeToGrColorType(colorType), |
| GrRenderable::kYes); |
| return fCaps->maxRenderTargetSampleCount(format); |
| } |
| |
| void GrContextThreadSafeProxy::abandonContext() { |
| if (!fAbandoned.exchange(true)) { |
| fTextBlobRedrawCoordinator->freeAll(); |
| } |
| } |
| |
| bool GrContextThreadSafeProxy::abandoned() const { |
| return fAbandoned; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////// |
| sk_sp<GrContextThreadSafeProxy> GrContextThreadSafeProxyPriv::Make( |
| GrBackendApi backend, |
| const GrContextOptions& options) { |
| return sk_sp<GrContextThreadSafeProxy>(new GrContextThreadSafeProxy(backend, options)); |
| } |
| |
| void GrContextThreadSafeProxyPriv::init(sk_sp<const GrCaps> caps, |
| sk_sp<GrThreadSafePipelineBuilder> builder) const { |
| fProxy->init(std::move(caps), std::move(builder)); |
| } |