1 /*
2 * Copyright 2011 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 "GrContext.h"
9 #include "GrBackendSemaphore.h"
10 #include "GrDrawingManager.h"
11 #include "GrGpu.h"
12 #include "GrMemoryPool.h"
13 #include "GrPathRendererChain.h"
14 #include "GrProxyProvider.h"
15 #include "GrRenderTargetProxy.h"
16 #include "GrResourceCache.h"
17 #include "GrResourceProvider.h"
18 #include "GrSemaphore.h"
19 #include "GrSoftwarePathRenderer.h"
20 #include "GrTracing.h"
21 #include "SkDeferredDisplayList.h"
22 #include "SkGr.h"
23 #include "SkImageInfoPriv.h"
24 #include "SkMakeUnique.h"
25 #include "SkSurface_Gpu.h"
26 #include "SkTaskGroup.h"
27 #include "SkTraceMemoryDump.h"
28 #include "effects/GrConfigConversionEffect.h"
29 #include "effects/GrSkSLFP.h"
30 #include "ccpr/GrCoverageCountingPathRenderer.h"
31 #include "text/GrTextBlobCache.h"
32 #include "text/GrTextContext.h"
33 #include <atomic>
34 #include <unordered_map>
35
36 #define ASSERT_OWNED_PROXY(P) \
37 SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == this)
38
39 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
40 #define ASSERT_SINGLE_OWNER \
41 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
42 #define RETURN_IF_ABANDONED if (this->abandoned()) { return; }
43 #define RETURN_FALSE_IF_ABANDONED if (this->abandoned()) { return false; }
44 #define RETURN_NULL_IF_ABANDONED if (this->abandoned()) { return nullptr; }
45
46 ////////////////////////////////////////////////////////////////////////////////
47
GrContext(GrBackendApi backend,const GrContextOptions & options,int32_t contextID)48 GrContext::GrContext(GrBackendApi backend, const GrContextOptions& options, int32_t contextID)
49 : INHERITED(backend, options, contextID) {
50 fResourceCache = nullptr;
51 fResourceProvider = nullptr;
52 }
53
~GrContext()54 GrContext::~GrContext() {
55 ASSERT_SINGLE_OWNER
56
57 if (this->drawingManager()) {
58 this->drawingManager()->cleanup();
59 }
60 delete fResourceProvider;
61 delete fResourceCache;
62 }
63
init(sk_sp<const GrCaps> caps,sk_sp<GrSkSLFPFactoryCache> FPFactoryCache)64 bool GrContext::init(sk_sp<const GrCaps> caps, sk_sp<GrSkSLFPFactoryCache> FPFactoryCache) {
65 ASSERT_SINGLE_OWNER
66 SkASSERT(fThreadSafeProxy); // needs to have been initialized by derived classes
67 SkASSERT(this->proxyProvider());
68
69 if (!INHERITED::init(std::move(caps), std::move(FPFactoryCache))) {
70 return false;
71 }
72
73 SkASSERT(this->caps());
74 SkASSERT(this->getGrStrikeCache());
75 SkASSERT(this->getTextBlobCache());
76
77 if (fGpu) {
78 fResourceCache = new GrResourceCache(this->caps(), this->singleOwner(), this->contextID());
79 fResourceProvider = new GrResourceProvider(fGpu.get(), fResourceCache, this->singleOwner(),
80 this->explicitlyAllocateGPUResources());
81 }
82
83 if (fResourceCache) {
84 fResourceCache->setProxyProvider(this->proxyProvider());
85 }
86
87 fDidTestPMConversions = false;
88
89 // DDL TODO: we need to think through how the task group & persistent cache
90 // get passed on to/shared between all the DDLRecorders created with this context.
91 if (this->options().fExecutor) {
92 fTaskGroup = skstd::make_unique<SkTaskGroup>(*this->options().fExecutor);
93 }
94
95 fPersistentCache = this->options().fPersistentCache;
96
97 return true;
98 }
99
threadSafeProxy()100 sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
101 return fThreadSafeProxy;
102 }
103
104 //////////////////////////////////////////////////////////////////////////////
105
abandonContext()106 void GrContext::abandonContext() {
107 if (this->abandoned()) {
108 return;
109 }
110
111 INHERITED::abandonContext();
112
113 fResourceProvider->abandon();
114
115 // Need to cleanup the drawing manager first so all the render targets
116 // will be released/forgotten before they too are abandoned.
117 this->drawingManager()->cleanup();
118
119 // abandon first to so destructors
120 // don't try to free the resources in the API.
121 fResourceCache->abandonAll();
122
123 fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
124 }
125
releaseResourcesAndAbandonContext()126 void GrContext::releaseResourcesAndAbandonContext() {
127 if (this->abandoned()) {
128 return;
129 }
130
131 INHERITED::abandonContext();
132
133 fResourceProvider->abandon();
134
135 // Need to cleanup the drawing manager first so all the render targets
136 // will be released/forgotten before they too are abandoned.
137 this->drawingManager()->cleanup();
138
139 // Release all resources in the backend 3D API.
140 fResourceCache->releaseAll();
141
142 fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
143 }
144
resetGLTextureBindings()145 void GrContext::resetGLTextureBindings() {
146 if (this->abandoned() || this->backend() != GrBackendApi::kOpenGL) {
147 return;
148 }
149 fGpu->resetTextureBindings();
150 }
151
resetContext(uint32_t state)152 void GrContext::resetContext(uint32_t state) {
153 ASSERT_SINGLE_OWNER
154 fGpu->markContextDirty(state);
155 }
156
freeGpuResources()157 void GrContext::freeGpuResources() {
158 ASSERT_SINGLE_OWNER
159
160 // TODO: the glyph cache doesn't hold any GpuResources so this call should not be needed here.
161 // Some slack in the GrTextBlob's implementation requires it though. That could be fixed.
162 this->getGrStrikeCache()->freeAll();
163
164 this->drawingManager()->freeGpuResources();
165
166 fResourceCache->purgeAllUnlocked();
167 }
168
purgeUnlockedResources(bool scratchResourcesOnly)169 void GrContext::purgeUnlockedResources(bool scratchResourcesOnly) {
170 ASSERT_SINGLE_OWNER
171 fResourceCache->purgeUnlockedResources(scratchResourcesOnly);
172 fResourceCache->purgeAsNeeded();
173
174 // The textBlob Cache doesn't actually hold any GPU resource but this is a convenient
175 // place to purge stale blobs
176 this->getTextBlobCache()->purgeStaleBlobs();
177 }
178
performDeferredCleanup(std::chrono::milliseconds msNotUsed)179 void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) {
180 ASSERT_SINGLE_OWNER
181
182 auto purgeTime = GrStdSteadyClock::now() - msNotUsed;
183
184 fResourceCache->purgeAsNeeded();
185 fResourceCache->purgeResourcesNotUsedSince(purgeTime);
186
187 if (auto ccpr = this->drawingManager()->getCoverageCountingPathRenderer()) {
188 ccpr->purgeCacheEntriesOlderThan(this->proxyProvider(), purgeTime);
189 }
190
191 // The textBlob Cache doesn't actually hold any GPU resource but this is a convenient
192 // place to purge stale blobs
193 this->getTextBlobCache()->purgeStaleBlobs();
194 }
195
purgeUnlockedResources(size_t bytesToPurge,bool preferScratchResources)196 void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
197 ASSERT_SINGLE_OWNER
198 fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources);
199 }
200
getResourceCacheUsage(int * resourceCount,size_t * resourceBytes) const201 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
202 ASSERT_SINGLE_OWNER
203
204 if (resourceCount) {
205 *resourceCount = fResourceCache->getBudgetedResourceCount();
206 }
207 if (resourceBytes) {
208 *resourceBytes = fResourceCache->getBudgetedResourceBytes();
209 }
210 }
211
getResourceCachePurgeableBytes() const212 size_t GrContext::getResourceCachePurgeableBytes() const {
213 ASSERT_SINGLE_OWNER
214 return fResourceCache->getPurgeableBytes();
215 }
216
217 ////////////////////////////////////////////////////////////////////////////////
218
maxTextureSize() const219 int GrContext::maxTextureSize() const { return this->caps()->maxTextureSize(); }
220
maxRenderTargetSize() const221 int GrContext::maxRenderTargetSize() const { return this->caps()->maxRenderTargetSize(); }
222
colorTypeSupportedAsImage(SkColorType colorType) const223 bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const {
224 GrPixelConfig config = SkColorType2GrPixelConfig(colorType);
225 return this->caps()->isConfigTexturable(config);
226 }
227
maxSurfaceSampleCountForColorType(SkColorType colorType) const228 int GrContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const {
229 GrPixelConfig config = SkColorType2GrPixelConfig(colorType);
230 return this->caps()->maxRenderTargetSampleCount(config);
231 }
232
233 ////////////////////////////////////////////////////////////////////////////////
234
wait(int numSemaphores,const GrBackendSemaphore waitSemaphores[])235 bool GrContext::wait(int numSemaphores, const GrBackendSemaphore waitSemaphores[]) {
236 if (!fGpu || fGpu->caps()->fenceSyncSupport()) {
237 return false;
238 }
239 for (int i = 0; i < numSemaphores; ++i) {
240 sk_sp<GrSemaphore> sema = fResourceProvider->wrapBackendSemaphore(
241 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
242 kAdopt_GrWrapOwnership);
243 fGpu->waitSemaphore(std::move(sema));
244 }
245 return true;
246 }
247
248
249 ////////////////////////////////////////////////////////////////////////////////
250
flush()251 void GrContext::flush() {
252 ASSERT_SINGLE_OWNER
253 RETURN_IF_ABANDONED
254
255 this->drawingManager()->flush(nullptr, SkSurface::BackendSurfaceAccess::kNoAccess,
256 kNone_GrFlushFlags, 0, nullptr, nullptr, nullptr);
257 }
258
flush(GrFlushFlags flags,int numSemaphores,GrBackendSemaphore signalSemaphores[],GrGpuFinishedProc finishedProc,GrGpuFinishedContext finishedContext)259 GrSemaphoresSubmitted GrContext::flush(GrFlushFlags flags, int numSemaphores,
260 GrBackendSemaphore signalSemaphores[],
261 GrGpuFinishedProc finishedProc,
262 GrGpuFinishedContext finishedContext) {
263 ASSERT_SINGLE_OWNER
264 if (this->abandoned()) {
265 return GrSemaphoresSubmitted::kNo;
266 }
267
268 return this->drawingManager()->flush(nullptr, SkSurface::BackendSurfaceAccess::kNoAccess,
269 flags, numSemaphores, signalSemaphores, finishedProc,
270 finishedContext);
271 }
272
273 ////////////////////////////////////////////////////////////////////////////////
274
storeVkPipelineCacheData()275 void GrContext::storeVkPipelineCacheData() {
276 if (fGpu) {
277 fGpu->storeVkPipelineCacheData();
278 }
279 }
280
281 ////////////////////////////////////////////////////////////////////////////////
282
createPMToUPMEffect(std::unique_ptr<GrFragmentProcessor> fp)283 std::unique_ptr<GrFragmentProcessor> GrContext::createPMToUPMEffect(
284 std::unique_ptr<GrFragmentProcessor> fp) {
285 ASSERT_SINGLE_OWNER
286 // We should have already called this->validPMUPMConversionExists() in this case
287 SkASSERT(fDidTestPMConversions);
288 // ...and it should have succeeded
289 SkASSERT(this->validPMUPMConversionExists());
290
291 return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToUnpremul);
292 }
293
createUPMToPMEffect(std::unique_ptr<GrFragmentProcessor> fp)294 std::unique_ptr<GrFragmentProcessor> GrContext::createUPMToPMEffect(
295 std::unique_ptr<GrFragmentProcessor> fp) {
296 ASSERT_SINGLE_OWNER
297 // We should have already called this->validPMUPMConversionExists() in this case
298 SkASSERT(fDidTestPMConversions);
299 // ...and it should have succeeded
300 SkASSERT(this->validPMUPMConversionExists());
301
302 return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToPremul);
303 }
304
validPMUPMConversionExists()305 bool GrContext::validPMUPMConversionExists() {
306 ASSERT_SINGLE_OWNER
307 if (!fDidTestPMConversions) {
308 fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this);
309 fDidTestPMConversions = true;
310 }
311
312 // The PM<->UPM tests fail or succeed together so we only need to check one.
313 return fPMUPMConversionsRoundTrip;
314 }
315
supportsDistanceFieldText() const316 bool GrContext::supportsDistanceFieldText() const {
317 return this->caps()->shaderCaps()->supportsDistanceFieldText();
318 }
319
320 //////////////////////////////////////////////////////////////////////////////
321
322 // DDL TODO: remove 'maxResources'
getResourceCacheLimits(int * maxResources,size_t * maxResourceBytes) const323 void GrContext::getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const {
324 ASSERT_SINGLE_OWNER
325 if (maxResources) {
326 *maxResources = fResourceCache->getMaxResourceCount();
327 }
328 if (maxResourceBytes) {
329 *maxResourceBytes = fResourceCache->getMaxResourceBytes();
330 }
331 }
332
setResourceCacheLimits(int maxResources,size_t maxResourceBytes)333 void GrContext::setResourceCacheLimits(int maxResources, size_t maxResourceBytes) {
334 ASSERT_SINGLE_OWNER
335 fResourceCache->setLimits(maxResources, maxResourceBytes);
336 }
337
338 //////////////////////////////////////////////////////////////////////////////
dumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump) const339 void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
340 ASSERT_SINGLE_OWNER
341 fResourceCache->dumpMemoryStatistics(traceMemoryDump);
342 traceMemoryDump->dumpNumericValue("skia/gr_text_blob_cache", "size", "bytes",
343 this->getTextBlobCache()->usedBytes());
344 }
345
346