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