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