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