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 
next_id()25 static 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 
GrContextThreadSafeProxy(GrBackendApi backend, const GrContextOptions& options)34 GrContextThreadSafeProxy::GrContextThreadSafeProxy(GrBackendApi backend,
35                                                    const GrContextOptions& options)
36         : fBackend(backend), fOptions(options), fContextID(next_id()) {
37 }
38 
39 GrContextThreadSafeProxy::~GrContextThreadSafeProxy() = default;
40 
init(sk_sp<const GrCaps> caps, sk_sp<GrThreadSafePipelineBuilder> pipelineBuilder)41 void 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 
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)49 SkSurfaceCharacterization 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 
defaultBackendFormat(SkColorType skColorType, GrRenderable renderable) const140 GrBackendFormat 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 
compressedBackendFormat(SkImage::CompressionType c) const156 GrBackendFormat 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 
abandonContext()165 void GrContextThreadSafeProxy::abandonContext() {
166     if (!fAbandoned.exchange(true)) {
167         fTextBlobCache->freeAll();
168     }
169 }
170 
abandoned() const171 bool GrContextThreadSafeProxy::abandoned() const {
172     return fAbandoned;
173 }
174 
175 ////////////////////////////////////////////////////////////////////////////////
Make( GrBackendApi backend, const GrContextOptions& options)176 sk_sp<GrContextThreadSafeProxy> GrContextThreadSafeProxyPriv::Make(
177                              GrBackendApi backend,
178                              const GrContextOptions& options) {
179     return sk_sp<GrContextThreadSafeProxy>(new GrContextThreadSafeProxy(backend, options));
180 }
181 
init(sk_sp<const GrCaps> caps, sk_sp<GrThreadSafePipelineBuilder> builder) const182 void 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