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 48 GrContext::GrContext(GrBackendApi backend, const GrContextOptions& options, int32_t contextID) 49 : INHERITED(backend, options, contextID) { 50 fResourceCache = nullptr; 51 fResourceProvider = nullptr; 52 } 53 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 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 100 sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() { 101 return fThreadSafeProxy; 102 } 103 104 ////////////////////////////////////////////////////////////////////////////// 105 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 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 145 void GrContext::resetGLTextureBindings() { 146 if (this->abandoned() || this->backend() != GrBackendApi::kOpenGL) { 147 return; 148 } 149 fGpu->resetTextureBindings(); 150 } 151 152 void GrContext::resetContext(uint32_t state) { 153 ASSERT_SINGLE_OWNER 154 fGpu->markContextDirty(state); 155 } 156 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 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 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 196 void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) { 197 ASSERT_SINGLE_OWNER 198 fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources); 199 } 200 201 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 212 size_t GrContext::getResourceCachePurgeableBytes() const { 213 ASSERT_SINGLE_OWNER 214 return fResourceCache->getPurgeableBytes(); 215 } 216 217 //////////////////////////////////////////////////////////////////////////////// 218 219 int GrContext::maxTextureSize() const { return this->caps()->maxTextureSize(); } 220 221 int GrContext::maxRenderTargetSize() const { return this->caps()->maxRenderTargetSize(); } 222 223 bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const { 224 GrPixelConfig config = SkColorType2GrPixelConfig(colorType); 225 return this->caps()->isConfigTexturable(config); 226 } 227 228 int GrContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const { 229 GrPixelConfig config = SkColorType2GrPixelConfig(colorType); 230 return this->caps()->maxRenderTargetSampleCount(config); 231 } 232 233 //////////////////////////////////////////////////////////////////////////////// 234 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 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 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 275 void GrContext::storeVkPipelineCacheData() { 276 if (fGpu) { 277 fGpu->storeVkPipelineCacheData(); 278 } 279 } 280 281 //////////////////////////////////////////////////////////////////////////////// 282 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 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 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 316 bool GrContext::supportsDistanceFieldText() const { 317 return this->caps()->shaderCaps()->supportsDistanceFieldText(); 318 } 319 320 ////////////////////////////////////////////////////////////////////////////// 321 322 // DDL TODO: remove 'maxResources' 323 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 333 void GrContext::setResourceCacheLimits(int maxResources, size_t maxResourceBytes) { 334 ASSERT_SINGLE_OWNER 335 fResourceCache->setLimits(maxResources, maxResourceBytes); 336 } 337 338 ////////////////////////////////////////////////////////////////////////////// 339 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