1/* 2 * Copyright 2019 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include <memory> 9 10#include "include/gpu/GrContextThreadSafeProxy.h" 11#include "src/gpu/GrContextThreadSafeProxyPriv.h" 12 13#include "include/core/SkSurfaceCharacterization.h" 14#include "src/gpu/GrBaseContextPriv.h" 15#include "src/gpu/GrCaps.h" 16#include "src/gpu/GrThreadSafeCache.h" 17#include "src/gpu/GrThreadSafePipelineBuilder.h" 18#include "src/gpu/effects/GrSkSLFP.h" 19#include "src/image/SkSurface_Gpu.h" 20 21#ifdef SK_VULKAN 22#include "src/gpu/vk/GrVkCaps.h" 23#endif 24 25static int32_t next_id() { 26 static std::atomic<int32_t> nextID{1}; 27 int32_t id; 28 do { 29 id = nextID.fetch_add(1, std::memory_order_relaxed); 30 } while (id == SK_InvalidGenID); 31 return id; 32} 33 34GrContextThreadSafeProxy::GrContextThreadSafeProxy(GrBackendApi backend, 35 const GrContextOptions& options) 36 : fBackend(backend), fOptions(options), fContextID(next_id()) { 37} 38 39GrContextThreadSafeProxy::~GrContextThreadSafeProxy() = default; 40 41void GrContextThreadSafeProxy::init(sk_sp<const GrCaps> caps, 42 sk_sp<GrThreadSafePipelineBuilder> pipelineBuilder) { 43 fCaps = std::move(caps); 44 fTextBlobCache = std::make_unique<GrTextBlobCache>(fContextID); 45 fThreadSafeCache = std::make_unique<GrThreadSafeCache>(); 46 fPipelineBuilder = std::move(pipelineBuilder); 47} 48 49SkSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization( 50 size_t cacheMaxResourceBytes, 51 const SkImageInfo& ii, const GrBackendFormat& backendFormat, 52 int sampleCnt, GrSurfaceOrigin origin, 53 const SkSurfaceProps& surfaceProps, 54 bool isMipMapped, bool willUseGLFBO0, bool isTextureable, 55 GrProtected isProtected, bool vkRTSupportsInputAttachment, 56 bool forVulkanSecondaryCommandBuffer) { 57 SkASSERT(fCaps); 58 if (!backendFormat.isValid()) { 59 return {}; 60 } 61 62 SkASSERT(isTextureable || !isMipMapped); 63 64 if (GrBackendApi::kOpenGL != backendFormat.backend() && willUseGLFBO0) { 65 // The willUseGLFBO0 flags can only be used for a GL backend. 66 return {}; 67 } 68 69 if (GrBackendApi::kVulkan != backendFormat.backend() && 70 (vkRTSupportsInputAttachment || forVulkanSecondaryCommandBuffer)) { 71 // The vkRTSupportsInputAttachment and forVulkanSecondaryCommandBuffer flags can only be 72 // used for a Vulkan backend. 73 return {}; 74 } 75 76 if (!fCaps->mipmapSupport()) { 77 isMipMapped = false; 78 } 79 80 if (ii.width() < 1 || ii.width() > fCaps->maxRenderTargetSize() || 81 ii.height() < 1 || ii.height() > fCaps->maxRenderTargetSize()) { 82 return {}; 83 } 84 85 GrColorType grColorType = SkColorTypeToGrColorType(ii.colorType()); 86 87 if (!fCaps->areColorTypeAndFormatCompatible(grColorType, backendFormat)) { 88 return {}; 89 } 90 91 if (!fCaps->isFormatAsColorTypeRenderable(grColorType, backendFormat, sampleCnt)) { 92 return {}; 93 } 94 95 sampleCnt = fCaps->getRenderTargetSampleCount(sampleCnt, backendFormat); 96 SkASSERT(sampleCnt); 97 98 if (willUseGLFBO0 && isTextureable) { 99 return {}; 100 } 101 102 if (isTextureable && !fCaps->isFormatTexturable(backendFormat, backendFormat.textureType())) { 103 // Skia doesn't agree that this is textureable. 104 return {}; 105 } 106 107 if (forVulkanSecondaryCommandBuffer && 108 (isTextureable || isMipMapped || willUseGLFBO0 || vkRTSupportsInputAttachment)) { 109 return {}; 110 } 111 112 if (GrBackendApi::kVulkan == backendFormat.backend()) { 113 if (GrBackendApi::kVulkan != fBackend) { 114 return {}; 115 } 116 117#ifdef SK_VULKAN 118 const GrVkCaps* vkCaps = (const GrVkCaps*) fCaps.get(); 119 120 // The protection status of the characterization and the context need to match 121 if (isProtected != GrProtected(vkCaps->supportsProtectedMemory())) { 122 return {}; 123 } 124#endif 125 } 126 127 return SkSurfaceCharacterization( 128 sk_ref_sp<GrContextThreadSafeProxy>(this), 129 cacheMaxResourceBytes, ii, backendFormat, 130 origin, sampleCnt, 131 SkSurfaceCharacterization::Textureable(isTextureable), 132 SkSurfaceCharacterization::MipMapped(isMipMapped), 133 SkSurfaceCharacterization::UsesGLFBO0(willUseGLFBO0), 134 SkSurfaceCharacterization::VkRTSupportsInputAttachment(vkRTSupportsInputAttachment), 135 SkSurfaceCharacterization::VulkanSecondaryCBCompatible(forVulkanSecondaryCommandBuffer), 136 isProtected, 137 surfaceProps); 138} 139 140GrBackendFormat GrContextThreadSafeProxy::defaultBackendFormat(SkColorType skColorType, 141 GrRenderable renderable) const { 142 SkASSERT(fCaps); 143 GrColorType grColorType = SkColorTypeToGrColorType(skColorType); 144 145 GrBackendFormat format = fCaps->getDefaultBackendFormat(grColorType, renderable); 146 if (!format.isValid()) { 147 return GrBackendFormat(); 148 } 149 150 SkASSERT(renderable == GrRenderable::kNo || 151 fCaps->isFormatAsColorTypeRenderable(grColorType, format)); 152 153 return format; 154} 155 156GrBackendFormat GrContextThreadSafeProxy::compressedBackendFormat(SkImage::CompressionType c) const { 157 SkASSERT(fCaps); 158 159 GrBackendFormat format = fCaps->getBackendFormatFromCompressionType(c); 160 161 SkASSERT(!format.isValid() || fCaps->isFormatTexturable(format, GrTextureType::k2D)); 162 return format; 163} 164 165void GrContextThreadSafeProxy::abandonContext() { 166 if (!fAbandoned.exchange(true)) { 167 fTextBlobCache->freeAll(); 168 } 169} 170 171bool GrContextThreadSafeProxy::abandoned() const { 172 return fAbandoned; 173} 174 175//////////////////////////////////////////////////////////////////////////////// 176sk_sp<GrContextThreadSafeProxy> GrContextThreadSafeProxyPriv::Make( 177 GrBackendApi backend, 178 const GrContextOptions& options) { 179 return sk_sp<GrContextThreadSafeProxy>(new GrContextThreadSafeProxy(backend, options)); 180} 181 182void GrContextThreadSafeProxyPriv::init(sk_sp<const GrCaps> caps, 183 sk_sp<GrThreadSafePipelineBuilder> builder) const { 184 fProxy->init(std::move(caps), std::move(builder)); 185} 186 187