| /* | |
| * 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/gpu/ganesh/GrContextThreadSafeProxy.h" | |
| #include "include/core/SkImageInfo.h" | |
| #include "include/gpu/ganesh/GrBackendSurface.h" | |
| #include "include/private/chromium/GrSurfaceCharacterization.h" | |
| #include "include/private/gpu/ganesh/GrTypesPriv.h" | |
| #include "src/gpu/ganesh/GrCaps.h" | |
| #include "src/gpu/ganesh/GrContextThreadSafeProxyPriv.h" | |
| #include "src/gpu/ganesh/GrThreadSafeCache.h" | |
| #include "src/gpu/ganesh/GrThreadSafePipelineBuilder.h" | |
| #include "src/text/gpu/TextBlobRedrawCoordinator.h" | |
| #include <memory> | |
| #include <utility> | |
| static uint32_t next_id() { | |
| static std::atomic<uint32_t> nextID{1}; | |
| uint32_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); | |
| } | |
| GrSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization( | |
| size_t cacheMaxResourceBytes, | |
| const SkImageInfo& ii, | |
| const GrBackendFormat& backendFormat, | |
| int sampleCnt, | |
| GrSurfaceOrigin origin, | |
| const SkSurfaceProps& surfaceProps, | |
| skgpu::Mipmapped isMipmapped, | |
| bool willUseGLFBO0, | |
| bool isTextureable, | |
| skgpu::Protected isProtected, | |
| bool vkRTSupportsInputAttachment, | |
| bool forVulkanSecondaryCommandBuffer) { | |
| SkASSERT(fCaps); | |
| if (!backendFormat.isValid()) { | |
| return {}; | |
| } | |
| SkASSERT(isTextureable || isMipmapped == skgpu::Mipmapped::kNo); | |
| 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 = skgpu::Mipmapped::kNo; | |
| } | |
| 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 (GrBackendApi::kVulkan == backendFormat.backend()) { | |
| if (!isValidCharacterizationForVulkan(fCaps, | |
| isTextureable, | |
| isMipmapped, | |
| isProtected, | |
| vkRTSupportsInputAttachment, | |
| forVulkanSecondaryCommandBuffer)) { | |
| return {}; | |
| } | |
| } | |
| return GrSurfaceCharacterization( | |
| sk_ref_sp<GrContextThreadSafeProxy>(this), | |
| cacheMaxResourceBytes, | |
| ii, | |
| backendFormat, | |
| origin, | |
| sampleCnt, | |
| GrSurfaceCharacterization::Textureable(isTextureable), | |
| isMipmapped, | |
| GrSurfaceCharacterization::UsesGLFBO0(willUseGLFBO0), | |
| GrSurfaceCharacterization::VkRTSupportsInputAttachment(vkRTSupportsInputAttachment), | |
| GrSurfaceCharacterization::VulkanSecondaryCBCompatible(forVulkanSecondaryCommandBuffer), | |
| isProtected, | |
| surfaceProps); | |
| } | |
| bool GrContextThreadSafeProxy::isValidCharacterizationForVulkan( | |
| sk_sp<const GrCaps>, | |
| bool isTextureable, | |
| skgpu::Mipmapped isMipmapped, | |
| skgpu::Protected isProtected, | |
| bool vkRTSupportsInputAttachment, | |
| bool forVulkanSecondaryCommandBuffer) { | |
| return false; // handled by a subclass | |
| } | |
| 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(SkTextureCompressionType 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)); | |
| } |