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