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 "GrClip.h" 11 #include "GrContextOptions.h" 12 #include "GrContextPriv.h" 13 #include "GrDrawingManager.h" 14 #include "GrGpu.h" 15 #include "GrMemoryPool.h" 16 #include "GrProxyProvider.h" 17 #include "GrRenderTargetContext.h" 18 #include "GrRenderTargetProxy.h" 19 #include "GrResourceCache.h" 20 #include "GrResourceProvider.h" 21 #include "GrSemaphore.h" 22 #include "GrSoftwarePathRenderer.h" 23 #include "GrSurfaceContext.h" 24 #include "GrSurfacePriv.h" 25 #include "GrSurfaceProxyPriv.h" 26 #include "GrTexture.h" 27 #include "GrTextureContext.h" 28 #include "GrTracing.h" 29 #include "SkAutoPixmapStorage.h" 30 #include "SkDeferredDisplayList.h" 31 #include "SkGr.h" 32 #include "SkImageInfoPriv.h" 33 #include "SkMakeUnique.h" 34 #include "SkSurface_Gpu.h" 35 #include "SkTaskGroup.h" 36 #include "SkTraceMemoryDump.h" 37 #include "effects/GrConfigConversionEffect.h" 38 #include "effects/GrSkSLFP.h" 39 #include "ccpr/GrCoverageCountingPathRenderer.h" 40 #include "text/GrTextBlobCache.h" 41 #include <atomic> 42 #include <unordered_map> 43 44 #define ASSERT_OWNED_PROXY(P) \ 45 SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == this) 46 #define ASSERT_OWNED_PROXY_PRIV(P) \ 47 SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == fContext) 48 49 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) 50 #define ASSERT_SINGLE_OWNER \ 51 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);) 52 #define ASSERT_SINGLE_OWNER_PRIV \ 53 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);) 54 #define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; } 55 #define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; } 56 #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; } 57 #define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; } 58 #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; } 59 60 //////////////////////////////////////////////////////////////////////////////// 61 62 GrContext::GrContext(GrBackendApi backend, int32_t id) 63 : INHERITED(backend, id) { 64 fResourceCache = nullptr; 65 fResourceProvider = nullptr; 66 fProxyProvider = nullptr; 67 fGlyphCache = nullptr; 68 } 69 70 bool GrContext::initCommon(const GrContextOptions& options) { 71 ASSERT_SINGLE_OWNER 72 SkASSERT(fCaps); // needs to have been initialized by derived classes 73 SkASSERT(fThreadSafeProxy); // needs to have been initialized by derived classes 74 75 if (fGpu) { 76 fCaps = fGpu->refCaps(); 77 fResourceCache = new GrResourceCache(fCaps.get(), &fSingleOwner, this->contextID()); 78 fResourceProvider = new GrResourceProvider(fGpu.get(), fResourceCache, &fSingleOwner, 79 options.fExplicitlyAllocateGPUResources); 80 fProxyProvider = 81 new GrProxyProvider(fResourceProvider, fResourceCache, fCaps, &fSingleOwner); 82 } else { 83 fProxyProvider = new GrProxyProvider(this->contextID(), fCaps, &fSingleOwner); 84 } 85 86 if (fResourceCache) { 87 fResourceCache->setProxyProvider(fProxyProvider); 88 } 89 90 fDisableGpuYUVConversion = options.fDisableGpuYUVConversion; 91 fSharpenMipmappedTextures = options.fSharpenMipmappedTextures; 92 fDidTestPMConversions = false; 93 94 GrPathRendererChain::Options prcOptions; 95 prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching; 96 #if GR_TEST_UTILS 97 prcOptions.fGpuPathRenderers = options.fGpuPathRenderers; 98 #endif 99 if (options.fDisableCoverageCountingPaths) { 100 prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting; 101 } 102 if (options.fDisableDistanceFieldPaths) { 103 prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall; 104 } 105 106 if (!fResourceCache) { 107 // DDL TODO: remove this crippling of the path renderer chain 108 // Disable the small path renderer bc of the proxies in the atlas. They need to be 109 // unified when the opLists are added back to the destination drawing manager. 110 prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall; 111 prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kStencilAndCover; 112 } 113 114 GrTextContext::Options textContextOptions; 115 textContextOptions.fMaxDistanceFieldFontSize = options.fGlyphsAsPathsFontSize; 116 textContextOptions.fMinDistanceFieldFontSize = options.fMinDistanceFieldFontSize; 117 textContextOptions.fDistanceFieldVerticesAlwaysHaveW = false; 118 #if SK_SUPPORT_ATLAS_TEXT 119 if (GrContextOptions::Enable::kYes == options.fDistanceFieldGlyphVerticesAlwaysHaveW) { 120 textContextOptions.fDistanceFieldVerticesAlwaysHaveW = true; 121 } 122 #endif 123 124 bool explicitlyAllocatingResources = fResourceProvider 125 ? fResourceProvider->explicitlyAllocateGPUResources() 126 : false; 127 fDrawingManager.reset(new GrDrawingManager(this, prcOptions, textContextOptions, 128 &fSingleOwner, explicitlyAllocatingResources, 129 options.fSortRenderTargets, 130 options.fReduceOpListSplitting)); 131 132 fGlyphCache = new GrStrikeCache(fCaps.get(), options.fGlyphCacheTextureMaximumBytes); 133 134 fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this, this->contextID())); 135 136 // DDL TODO: we need to think through how the task group & persistent cache 137 // get passed on to/shared between all the DDLRecorders created with this context. 138 if (options.fExecutor) { 139 fTaskGroup = skstd::make_unique<SkTaskGroup>(*options.fExecutor); 140 } 141 142 fPersistentCache = options.fPersistentCache; 143 144 return true; 145 } 146 147 GrContext::~GrContext() { 148 ASSERT_SINGLE_OWNER 149 150 if (fDrawingManager) { 151 fDrawingManager->cleanup(); 152 } 153 delete fResourceProvider; 154 delete fResourceCache; 155 delete fProxyProvider; 156 delete fGlyphCache; 157 } 158 159 sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() { 160 return fThreadSafeProxy; 161 } 162 163 ////////////////////////////////////////////////////////////////////////////// 164 165 void GrContext::abandonContext() { 166 ASSERT_SINGLE_OWNER 167 168 fProxyProvider->abandon(); 169 fResourceProvider->abandon(); 170 171 // Need to abandon the drawing manager first so all the render targets 172 // will be released/forgotten before they too are abandoned. 173 fDrawingManager->abandon(); 174 175 // abandon first to so destructors 176 // don't try to free the resources in the API. 177 fResourceCache->abandonAll(); 178 179 fGpu->disconnect(GrGpu::DisconnectType::kAbandon); 180 181 fGlyphCache->freeAll(); 182 fTextBlobCache->freeAll(); 183 } 184 185 bool GrContext::abandoned() const { 186 ASSERT_SINGLE_OWNER 187 // If called from ~GrContext(), the drawing manager may already be gone. 188 return !fDrawingManager || fDrawingManager->wasAbandoned(); 189 } 190 191 void GrContext::releaseResourcesAndAbandonContext() { 192 ASSERT_SINGLE_OWNER 193 194 if (this->abandoned()) { 195 return; 196 } 197 fProxyProvider->abandon(); 198 fResourceProvider->abandon(); 199 200 // Need to abandon the drawing manager first so all the render targets 201 // will be released/forgotten before they too are abandoned. 202 fDrawingManager->abandon(); 203 204 // Release all resources in the backend 3D API. 205 fResourceCache->releaseAll(); 206 207 fGpu->disconnect(GrGpu::DisconnectType::kCleanup); 208 209 fGlyphCache->freeAll(); 210 fTextBlobCache->freeAll(); 211 } 212 213 void GrContext::resetContext(uint32_t state) { 214 ASSERT_SINGLE_OWNER 215 fGpu->markContextDirty(state); 216 } 217 218 void GrContext::freeGpuResources() { 219 ASSERT_SINGLE_OWNER 220 221 fGlyphCache->freeAll(); 222 223 fDrawingManager->freeGpuResources(); 224 225 fResourceCache->purgeAllUnlocked(); 226 } 227 228 void GrContext::purgeUnlockedResources(bool scratchResourcesOnly) { 229 ASSERT_SINGLE_OWNER 230 fResourceCache->purgeUnlockedResources(scratchResourcesOnly); 231 fResourceCache->purgeAsNeeded(); 232 fTextBlobCache->purgeStaleBlobs(); 233 } 234 235 void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) { 236 ASSERT_SINGLE_OWNER 237 238 auto purgeTime = GrStdSteadyClock::now() - msNotUsed; 239 240 fResourceCache->purgeAsNeeded(); 241 fResourceCache->purgeResourcesNotUsedSince(purgeTime); 242 243 if (auto ccpr = fDrawingManager->getCoverageCountingPathRenderer()) { 244 ccpr->purgeCacheEntriesOlderThan(fProxyProvider, purgeTime); 245 } 246 247 fTextBlobCache->purgeStaleBlobs(); 248 } 249 250 void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) { 251 ASSERT_SINGLE_OWNER 252 fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources); 253 } 254 255 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const { 256 ASSERT_SINGLE_OWNER 257 258 if (resourceCount) { 259 *resourceCount = fResourceCache->getBudgetedResourceCount(); 260 } 261 if (resourceBytes) { 262 *resourceBytes = fResourceCache->getBudgetedResourceBytes(); 263 } 264 } 265 266 size_t GrContext::getResourceCachePurgeableBytes() const { 267 ASSERT_SINGLE_OWNER 268 return fResourceCache->getPurgeableBytes(); 269 } 270 271 //////////////////////////////////////////////////////////////////////////////// 272 273 int GrContext::maxTextureSize() const { return fCaps->maxTextureSize(); } 274 275 int GrContext::maxRenderTargetSize() const { return fCaps->maxRenderTargetSize(); } 276 277 bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const { 278 GrPixelConfig config = SkColorType2GrPixelConfig(colorType); 279 return fCaps->isConfigTexturable(config); 280 } 281 282 int GrContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const { 283 GrPixelConfig config = SkColorType2GrPixelConfig(colorType); 284 return fCaps->maxRenderTargetSampleCount(config); 285 } 286 287 //////////////////////////////////////////////////////////////////////////////// 288 289 void GrContext::TextBlobCacheOverBudgetCB(void* data) { 290 SkASSERT(data); 291 // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on 292 // GrRenderTargetContext to perform a necessary flush. The solution is to move drawText calls 293 // to below the GrContext level, but this is not trivial because they call drawPath on 294 // SkGpuDevice. 295 GrContext* context = reinterpret_cast<GrContext*>(data); 296 context->flush(); 297 } 298 299 //////////////////////////////////////////////////////////////////////////////// 300 301 void GrContext::flush() { 302 ASSERT_SINGLE_OWNER 303 RETURN_IF_ABANDONED 304 305 fDrawingManager->flush(nullptr); 306 } 307 308 GrSemaphoresSubmitted GrContext::flushAndSignalSemaphores(int numSemaphores, 309 GrBackendSemaphore signalSemaphores[]) { 310 ASSERT_SINGLE_OWNER 311 if (fDrawingManager->wasAbandoned()) { return GrSemaphoresSubmitted::kNo; } 312 313 return fDrawingManager->flush(nullptr, numSemaphores, signalSemaphores); 314 } 315 316 void GrContextPriv::flush(GrSurfaceProxy* proxy) { 317 ASSERT_SINGLE_OWNER_PRIV 318 RETURN_IF_ABANDONED_PRIV 319 ASSERT_OWNED_PROXY_PRIV(proxy); 320 321 fContext->fDrawingManager->flush(proxy); 322 } 323 324 //////////////////////////////////////////////////////////////////////////////// 325 326 void GrContext::storeVkPipelineCacheData() { 327 if (fGpu) { 328 fGpu->storeVkPipelineCacheData(); 329 } 330 } 331 332 //////////////////////////////////////////////////////////////////////////////// 333 334 // TODO: This will be removed when GrSurfaceContexts are aware of their color types. 335 // (skbug.com/6718) 336 static bool valid_premul_config(GrPixelConfig config) { 337 switch (config) { 338 case kUnknown_GrPixelConfig: return false; 339 case kAlpha_8_GrPixelConfig: return false; 340 case kGray_8_GrPixelConfig: return false; 341 case kRGB_565_GrPixelConfig: return false; 342 case kRGBA_4444_GrPixelConfig: return true; 343 case kRGBA_8888_GrPixelConfig: return true; 344 case kRGB_888_GrPixelConfig: return false; 345 case kRG_88_GrPixelConfig: return false; 346 case kBGRA_8888_GrPixelConfig: return true; 347 case kSRGBA_8888_GrPixelConfig: return true; 348 case kSBGRA_8888_GrPixelConfig: return true; 349 case kRGBA_1010102_GrPixelConfig: return true; 350 case kRGBA_float_GrPixelConfig: return true; 351 case kRG_float_GrPixelConfig: return false; 352 case kAlpha_half_GrPixelConfig: return false; 353 case kRGBA_half_GrPixelConfig: return true; 354 case kRGB_ETC1_GrPixelConfig: return false; 355 case kAlpha_8_as_Alpha_GrPixelConfig: return false; 356 case kAlpha_8_as_Red_GrPixelConfig: return false; 357 case kAlpha_half_as_Red_GrPixelConfig: return false; 358 case kGray_8_as_Lum_GrPixelConfig: return false; 359 case kGray_8_as_Red_GrPixelConfig: return false; 360 } 361 SK_ABORT("Invalid GrPixelConfig"); 362 return false; 363 } 364 365 static bool valid_premul_color_type(GrColorType ct) { 366 switch (ct) { 367 case GrColorType::kUnknown: return false; 368 case GrColorType::kAlpha_8: return false; 369 case GrColorType::kRGB_565: return false; 370 case GrColorType::kABGR_4444: return true; 371 case GrColorType::kRGBA_8888: return true; 372 case GrColorType::kRGB_888x: return false; 373 case GrColorType::kRG_88: return false; 374 case GrColorType::kBGRA_8888: return true; 375 case GrColorType::kRGBA_1010102: return true; 376 case GrColorType::kGray_8: return false; 377 case GrColorType::kAlpha_F16: return false; 378 case GrColorType::kRGBA_F16: return true; 379 case GrColorType::kRG_F32: return false; 380 case GrColorType::kRGBA_F32: return true; 381 case GrColorType::kRGB_ETC1: return false; 382 } 383 SK_ABORT("Invalid GrColorType"); 384 return false; 385 } 386 387 static bool valid_pixel_conversion(GrColorType cpuColorType, GrPixelConfig gpuConfig, 388 bool premulConversion) { 389 // We only allow premul <-> unpremul conversions for some formats 390 if (premulConversion && 391 (!valid_premul_color_type(cpuColorType) || !valid_premul_config(gpuConfig))) { 392 return false; 393 } 394 return true; 395 } 396 397 bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst, int left, int top, int width, 398 int height, GrColorType srcColorType, 399 SkColorSpace* srcColorSpace, const void* buffer, 400 size_t rowBytes, uint32_t pixelOpsFlags) { 401 ASSERT_SINGLE_OWNER_PRIV 402 RETURN_FALSE_IF_ABANDONED_PRIV 403 SkASSERT(dst); 404 SkASSERT(buffer); 405 ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy()); 406 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext); 407 408 if (GrColorType::kUnknown == srcColorType) { 409 return false; 410 } 411 412 if (!dst->asSurfaceProxy()->instantiate(this->resourceProvider())) { 413 return false; 414 } 415 416 GrSurfaceProxy* dstProxy = dst->asSurfaceProxy(); 417 GrSurface* dstSurface = dstProxy->peekSurface(); 418 419 if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(), 420 GrColorTypeBytesPerPixel(srcColorType), &left, &top, 421 &width, &height, &buffer, &rowBytes)) { 422 return false; 423 } 424 425 // TODO: Make GrSurfaceContext know its alpha type and pass src buffer's alpha type. 426 bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags); 427 428 // For canvas2D putImageData performance we have a special code path for unpremul RGBA_8888 srcs 429 // that are premultiplied on the GPU. This is kept as narrow as possible for now. 430 bool canvas2DFastPath = 431 !fContext->contextPriv().caps()->avoidWritePixelsFastPath() && 432 premul && 433 !dst->colorSpaceInfo().colorSpace() && 434 (srcColorType == GrColorType::kRGBA_8888 || srcColorType == GrColorType::kBGRA_8888) && 435 SkToBool(dst->asRenderTargetContext()) && 436 (dstProxy->config() == kRGBA_8888_GrPixelConfig || 437 dstProxy->config() == kBGRA_8888_GrPixelConfig) && 438 !(pixelOpsFlags & kDontFlush_PixelOpsFlag) && 439 fContext->contextPriv().caps()->isConfigTexturable(kRGBA_8888_GrPixelConfig) && 440 fContext->validPMUPMConversionExists(); 441 442 const GrCaps* caps = this->caps(); 443 if (!caps->surfaceSupportsWritePixels(dstSurface) || 444 canvas2DFastPath) { 445 // We don't expect callers that are skipping flushes to require an intermediate draw. 446 SkASSERT(!(pixelOpsFlags & kDontFlush_PixelOpsFlag)); 447 if (pixelOpsFlags & kDontFlush_PixelOpsFlag) { 448 return false; 449 } 450 451 GrSurfaceDesc desc; 452 desc.fWidth = width; 453 desc.fHeight = height; 454 desc.fSampleCnt = 1; 455 456 GrBackendFormat format; 457 if (canvas2DFastPath) { 458 desc.fConfig = kRGBA_8888_GrPixelConfig; 459 format = 460 fContext->contextPriv().caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType); 461 } else { 462 desc.fConfig = dstProxy->config(); 463 format = dstProxy->backendFormat().makeTexture2D(); 464 if (!format.isValid()) { 465 return false; 466 } 467 } 468 469 auto tempProxy = this->proxyProvider()->createProxy( 470 format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox, SkBudgeted::kYes); 471 if (!tempProxy) { 472 return false; 473 } 474 auto tempCtx = this->drawingManager()->makeTextureContext( 475 tempProxy, dst->colorSpaceInfo().refColorSpace()); 476 if (!tempCtx) { 477 return false; 478 } 479 uint32_t flags = canvas2DFastPath ? 0 : pixelOpsFlags; 480 // In the fast path we always write the srcData to the temp context as though it were RGBA. 481 // When the data is really BGRA the write will cause the R and B channels to be swapped in 482 // the intermediate surface which gets corrected by a swizzle effect when drawing to the 483 // dst. 484 auto tmpColorType = canvas2DFastPath ? GrColorType::kRGBA_8888 : srcColorType; 485 if (!this->writeSurfacePixels(tempCtx.get(), 0, 0, width, height, tmpColorType, 486 srcColorSpace, buffer, rowBytes, flags)) { 487 return false; 488 } 489 if (canvas2DFastPath) { 490 GrPaint paint; 491 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 492 auto fp = fContext->createUPMToPMEffect( 493 GrSimpleTextureEffect::Make(std::move(tempProxy), SkMatrix::I())); 494 if (srcColorType == GrColorType::kBGRA_8888) { 495 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA()); 496 } 497 if (!fp) { 498 return false; 499 } 500 paint.addColorFragmentProcessor(std::move(fp)); 501 dst->asRenderTargetContext()->fillRectToRect( 502 GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), 503 SkRect::MakeXYWH(left, top, width, height), SkRect::MakeWH(width, height)); 504 return true; 505 } else { 506 return dst->copy(tempProxy.get(), SkIRect::MakeWH(width, height), {left, top}); 507 } 508 } 509 510 bool convert = premul; 511 512 if (!valid_pixel_conversion(srcColorType, dstProxy->config(), premul)) { 513 return false; 514 } 515 516 GrColorType allowedColorType = fContext->contextPriv().caps()->supportedWritePixelsColorType( 517 dstProxy->config(), srcColorType); 518 convert = convert || (srcColorType != allowedColorType); 519 520 if (!dst->colorSpaceInfo().colorSpace()) { 521 // "Legacy" mode - no color space conversions. 522 srcColorSpace = nullptr; 523 } 524 convert = convert || !SkColorSpace::Equals(srcColorSpace, dst->colorSpaceInfo().colorSpace()); 525 526 std::unique_ptr<char[]> tempBuffer; 527 if (convert) { 528 auto srcSkColorType = GrColorTypeToSkColorType(srcColorType); 529 auto dstSkColorType = GrColorTypeToSkColorType(allowedColorType); 530 if (kUnknown_SkColorType == srcSkColorType || kUnknown_SkColorType == dstSkColorType) { 531 return false; 532 } 533 auto srcAlphaType = SkColorTypeIsAlwaysOpaque(srcSkColorType) 534 ? kOpaque_SkAlphaType 535 : (premul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType); 536 SkPixmap src(SkImageInfo::Make(width, height, srcSkColorType, srcAlphaType, 537 sk_ref_sp(srcColorSpace)), 538 buffer, rowBytes); 539 auto tempSrcII = SkImageInfo::Make(width, height, dstSkColorType, kPremul_SkAlphaType, 540 dst->colorSpaceInfo().refColorSpace()); 541 auto size = tempSrcII.computeMinByteSize(); 542 if (!size) { 543 return false; 544 } 545 tempBuffer.reset(new char[size]); 546 SkPixmap tempSrc(tempSrcII, tempBuffer.get(), tempSrcII.minRowBytes()); 547 if (!src.readPixels(tempSrc)) { 548 return false; 549 } 550 srcColorType = allowedColorType; 551 buffer = tempSrc.addr(); 552 rowBytes = tempSrc.rowBytes(); 553 if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) { 554 std::unique_ptr<char[]> row(new char[rowBytes]); 555 for (int y = 0; y < height / 2; ++y) { 556 memcpy(row.get(), tempSrc.addr(0, y), rowBytes); 557 memcpy(tempSrc.writable_addr(0, y), tempSrc.addr(0, height - 1 - y), rowBytes); 558 memcpy(tempSrc.writable_addr(0, height - 1 - y), row.get(), rowBytes); 559 } 560 top = dstSurface->height() - top - height; 561 } 562 } else if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) { 563 size_t trimRowBytes = GrColorTypeBytesPerPixel(srcColorType) * width; 564 tempBuffer.reset(new char[trimRowBytes * height]); 565 char* dst = reinterpret_cast<char*>(tempBuffer.get()) + trimRowBytes * (height - 1); 566 const char* src = reinterpret_cast<const char*>(buffer); 567 for (int i = 0; i < height; ++i, src += rowBytes, dst -= trimRowBytes) { 568 memcpy(dst, src, trimRowBytes); 569 } 570 buffer = tempBuffer.get(); 571 rowBytes = trimRowBytes; 572 top = dstSurface->height() - top - height; 573 } 574 575 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) { 576 this->flush(nullptr); // MDB TODO: tighten this 577 } 578 579 return this->getGpu()->writePixels(dstSurface, left, top, width, height, srcColorType, buffer, 580 rowBytes); 581 } 582 583 bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src, int left, int top, int width, 584 int height, GrColorType dstColorType, 585 SkColorSpace* dstColorSpace, void* buffer, size_t rowBytes, 586 uint32_t pixelOpsFlags) { 587 ASSERT_SINGLE_OWNER_PRIV 588 RETURN_FALSE_IF_ABANDONED_PRIV 589 SkASSERT(src); 590 SkASSERT(buffer); 591 ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy()); 592 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext); 593 594 SkASSERT(!(pixelOpsFlags & kDontFlush_PixelOpsFlag)); 595 if (pixelOpsFlags & kDontFlush_PixelOpsFlag) { 596 return false; 597 } 598 599 // MDB TODO: delay this instantiation until later in the method 600 if (!src->asSurfaceProxy()->instantiate(this->resourceProvider())) { 601 return false; 602 } 603 604 GrSurfaceProxy* srcProxy = src->asSurfaceProxy(); 605 GrSurface* srcSurface = srcProxy->peekSurface(); 606 607 if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(), 608 GrColorTypeBytesPerPixel(dstColorType), &left, &top, 609 &width, &height, &buffer, &rowBytes)) { 610 return false; 611 } 612 613 // TODO: Make GrSurfaceContext know its alpha type and pass dst buffer's alpha type. 614 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags); 615 616 if (!valid_pixel_conversion(dstColorType, srcProxy->config(), unpremul)) { 617 return false; 618 } 619 620 // This is the getImageData equivalent to the canvas2D putImageData fast path. We probably don't 621 // care so much about getImageData performance. However, in order to ensure putImageData/ 622 // getImageData in "legacy" mode are round-trippable we use the GPU to do the complementary 623 // unpremul step to writeSurfacePixels's premul step (which is determined empirically in 624 // fContext->vaildaPMUPMConversionExists()). 625 bool canvas2DFastPath = 626 unpremul && 627 !src->colorSpaceInfo().colorSpace() && 628 (GrColorType::kRGBA_8888 == dstColorType || GrColorType::kBGRA_8888 == dstColorType) && 629 SkToBool(srcProxy->asTextureProxy()) && 630 (srcProxy->config() == kRGBA_8888_GrPixelConfig || 631 srcProxy->config() == kBGRA_8888_GrPixelConfig) && 632 fContext->contextPriv().caps()->isConfigRenderable(kRGBA_8888_GrPixelConfig) && 633 fContext->validPMUPMConversionExists(); 634 635 if (!fContext->contextPriv().caps()->surfaceSupportsReadPixels(srcSurface) || 636 canvas2DFastPath) { 637 GrSurfaceDesc desc; 638 desc.fFlags = canvas2DFastPath ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags; 639 desc.fConfig = canvas2DFastPath ? kRGBA_8888_GrPixelConfig : srcProxy->config(); 640 desc.fWidth = width; 641 desc.fHeight = height; 642 desc.fSampleCnt = 1; 643 644 GrBackendFormat format; 645 if (canvas2DFastPath) { 646 desc.fFlags = kRenderTarget_GrSurfaceFlag; 647 desc.fConfig = kRGBA_8888_GrPixelConfig; 648 format = this->caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType); 649 } else { 650 desc.fFlags = kNone_GrSurfaceFlags; 651 desc.fConfig = srcProxy->config(); 652 format = srcProxy->backendFormat().makeTexture2D(); 653 if (!format.isValid()) { 654 return false; 655 } 656 } 657 658 auto tempProxy = this->proxyProvider()->createProxy( 659 format, desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox, SkBudgeted::kYes); 660 if (!tempProxy) { 661 return false; 662 } 663 sk_sp<GrSurfaceContext> tempCtx; 664 if (canvas2DFastPath) { 665 tempCtx = this->drawingManager()->makeRenderTargetContext(std::move(tempProxy), nullptr, 666 nullptr); 667 SkASSERT(tempCtx->asRenderTargetContext()); 668 tempCtx->asRenderTargetContext()->discard(); 669 } else { 670 tempCtx = this->drawingManager()->makeTextureContext( 671 std::move(tempProxy), src->colorSpaceInfo().refColorSpace()); 672 } 673 if (!tempCtx) { 674 return false; 675 } 676 if (canvas2DFastPath) { 677 GrPaint paint; 678 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 679 auto fp = fContext->createPMToUPMEffect( 680 GrSimpleTextureEffect::Make(sk_ref_sp(srcProxy->asTextureProxy()), 681 SkMatrix::I())); 682 if (dstColorType == GrColorType::kBGRA_8888) { 683 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), GrSwizzle::BGRA()); 684 dstColorType = GrColorType::kRGBA_8888; 685 } 686 if (!fp) { 687 return false; 688 } 689 paint.addColorFragmentProcessor(std::move(fp)); 690 tempCtx->asRenderTargetContext()->fillRectToRect( 691 GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), 692 SkRect::MakeWH(width, height), SkRect::MakeXYWH(left, top, width, height)); 693 } else if (!tempCtx->copy(srcProxy, SkIRect::MakeXYWH(left, top, width, height), {0, 0})) { 694 return false; 695 } 696 uint32_t flags = canvas2DFastPath ? 0 : pixelOpsFlags; 697 return this->readSurfacePixels(tempCtx.get(), 0, 0, width, height, dstColorType, 698 dstColorSpace, buffer, rowBytes, flags); 699 } 700 701 bool convert = unpremul; 702 703 bool flip = srcProxy->origin() == kBottomLeft_GrSurfaceOrigin; 704 if (flip) { 705 top = srcSurface->height() - top - height; 706 } 707 708 GrColorType allowedColorType = fContext->contextPriv().caps()->supportedReadPixelsColorType( 709 srcProxy->config(), dstColorType); 710 convert = convert || (dstColorType != allowedColorType); 711 712 if (!src->colorSpaceInfo().colorSpace()) { 713 // "Legacy" mode - no color space conversions. 714 dstColorSpace = nullptr; 715 } 716 convert = convert || !SkColorSpace::Equals(dstColorSpace, src->colorSpaceInfo().colorSpace()); 717 718 SkAutoPixmapStorage tempPixmap; 719 SkPixmap finalPixmap; 720 if (convert) { 721 SkColorType srcSkColorType = GrColorTypeToSkColorType(allowedColorType); 722 SkColorType dstSkColorType = GrColorTypeToSkColorType(dstColorType); 723 bool srcAlwaysOpaque = SkColorTypeIsAlwaysOpaque(srcSkColorType); 724 bool dstAlwaysOpaque = SkColorTypeIsAlwaysOpaque(dstSkColorType); 725 if (kUnknown_SkColorType == srcSkColorType || kUnknown_SkColorType == dstSkColorType) { 726 return false; 727 } 728 auto tempAT = srcAlwaysOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType; 729 auto tempII = SkImageInfo::Make(width, height, srcSkColorType, tempAT, 730 src->colorSpaceInfo().refColorSpace()); 731 SkASSERT(!unpremul || !dstAlwaysOpaque); 732 auto finalAT = (srcAlwaysOpaque || dstAlwaysOpaque) 733 ? kOpaque_SkAlphaType 734 : unpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType; 735 auto finalII = 736 SkImageInfo::Make(width, height, dstSkColorType, finalAT, sk_ref_sp(dstColorSpace)); 737 if (!SkImageInfoValidConversion(finalII, tempII)) { 738 return false; 739 } 740 if (!tempPixmap.tryAlloc(tempII)) { 741 return false; 742 } 743 finalPixmap.reset(finalII, buffer, rowBytes); 744 buffer = tempPixmap.writable_addr(); 745 rowBytes = tempPixmap.rowBytes(); 746 // Chrome msan bots require this. 747 sk_bzero(buffer, tempPixmap.computeByteSize()); 748 } 749 750 if (srcSurface->surfacePriv().hasPendingWrite()) { 751 this->flush(nullptr); // MDB TODO: tighten this 752 } 753 754 if (!fContext->fGpu->readPixels(srcSurface, left, top, width, height, allowedColorType, buffer, 755 rowBytes)) { 756 return false; 757 } 758 759 if (flip) { 760 size_t trimRowBytes = GrColorTypeBytesPerPixel(allowedColorType) * width; 761 std::unique_ptr<char[]> row(new char[trimRowBytes]); 762 char* upper = reinterpret_cast<char*>(buffer); 763 char* lower = reinterpret_cast<char*>(buffer) + (height - 1) * rowBytes; 764 for (int y = 0; y < height / 2; ++y, upper += rowBytes, lower -= rowBytes) { 765 memcpy(row.get(), upper, trimRowBytes); 766 memcpy(upper, lower, trimRowBytes); 767 memcpy(lower, row.get(), trimRowBytes); 768 } 769 } 770 if (convert) { 771 if (!tempPixmap.readPixels(finalPixmap)) { 772 return false; 773 } 774 } 775 return true; 776 } 777 778 void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) { 779 ASSERT_SINGLE_OWNER_PRIV 780 RETURN_IF_ABANDONED_PRIV 781 SkASSERT(proxy); 782 ASSERT_OWNED_PROXY_PRIV(proxy); 783 fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy, 0, nullptr); 784 } 785 786 void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) { 787 ASSERT_SINGLE_OWNER_PRIV 788 RETURN_IF_ABANDONED_PRIV 789 SkASSERT(proxy); 790 ASSERT_OWNED_PROXY_PRIV(proxy); 791 if (proxy->priv().hasPendingWrite()) { 792 this->flush(proxy); 793 } 794 } 795 796 void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) { 797 ASSERT_SINGLE_OWNER_PRIV 798 RETURN_IF_ABANDONED_PRIV 799 SkASSERT(proxy); 800 ASSERT_OWNED_PROXY_PRIV(proxy); 801 if (proxy->priv().hasPendingIO()) { 802 this->flush(proxy); 803 } 804 } 805 806 //////////////////////////////////////////////////////////////////////////////// 807 808 sk_sp<GrOpMemoryPool> GrContextPriv::refOpMemoryPool() { 809 if (!fContext->fOpMemoryPool) { 810 // DDL TODO: should the size of the memory pool be decreased in DDL mode? CPU-side memory 811 // consumed in DDL mode vs. normal mode for a single skp might be a good metric of wasted 812 // memory. 813 fContext->fOpMemoryPool = sk_sp<GrOpMemoryPool>(new GrOpMemoryPool(16384, 16384)); 814 } 815 816 SkASSERT(fContext->fOpMemoryPool); 817 return fContext->fOpMemoryPool; 818 } 819 820 GrOpMemoryPool* GrContextPriv::opMemoryPool() { 821 return this->refOpMemoryPool().get(); 822 } 823 824 sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy, 825 sk_sp<SkColorSpace> colorSpace, 826 const SkSurfaceProps* props) { 827 ASSERT_SINGLE_OWNER_PRIV 828 829 if (proxy->asRenderTargetProxy()) { 830 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 831 std::move(colorSpace), props); 832 } else { 833 SkASSERT(proxy->asTextureProxy()); 834 SkASSERT(!props); 835 return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace)); 836 } 837 } 838 839 sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrBackendFormat& format, 840 const GrSurfaceDesc& dstDesc, 841 GrSurfaceOrigin origin, 842 GrMipMapped mipMapped, 843 SkBackingFit fit, 844 SkBudgeted isDstBudgeted, 845 sk_sp<SkColorSpace> colorSpace, 846 const SkSurfaceProps* props) { 847 sk_sp<GrTextureProxy> proxy; 848 if (GrMipMapped::kNo == mipMapped) { 849 proxy = this->proxyProvider()->createProxy(format, dstDesc, origin, fit, isDstBudgeted); 850 } else { 851 SkASSERT(SkBackingFit::kExact == fit); 852 proxy = this->proxyProvider()->createMipMapProxy(format, dstDesc, origin, isDstBudgeted); 853 } 854 if (!proxy) { 855 return nullptr; 856 } 857 858 sk_sp<GrSurfaceContext> sContext = this->makeWrappedSurfaceContext(std::move(proxy), 859 std::move(colorSpace), 860 props); 861 if (sContext && sContext->asRenderTargetContext()) { 862 sContext->asRenderTargetContext()->discard(); 863 } 864 865 return sContext; 866 } 867 868 sk_sp<GrTextureContext> GrContextPriv::makeBackendTextureContext(const GrBackendTexture& tex, 869 GrSurfaceOrigin origin, 870 sk_sp<SkColorSpace> colorSpace) { 871 ASSERT_SINGLE_OWNER_PRIV 872 873 sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->wrapBackendTexture( 874 tex, origin, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType); 875 if (!proxy) { 876 return nullptr; 877 } 878 879 return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace)); 880 } 881 882 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext( 883 const GrBackendTexture& tex, 884 GrSurfaceOrigin origin, 885 int sampleCnt, 886 sk_sp<SkColorSpace> colorSpace, 887 const SkSurfaceProps* props) { 888 ASSERT_SINGLE_OWNER_PRIV 889 SkASSERT(sampleCnt > 0); 890 891 sk_sp<GrTextureProxy> proxy(this->proxyProvider()->wrapRenderableBackendTexture( 892 tex, origin, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo)); 893 if (!proxy) { 894 return nullptr; 895 } 896 897 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 898 std::move(colorSpace), props); 899 } 900 901 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext( 902 const GrBackendRenderTarget& backendRT, 903 GrSurfaceOrigin origin, 904 sk_sp<SkColorSpace> colorSpace, 905 const SkSurfaceProps* surfaceProps) { 906 ASSERT_SINGLE_OWNER_PRIV 907 908 sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->wrapBackendRenderTarget(backendRT, origin); 909 if (!proxy) { 910 return nullptr; 911 } 912 913 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 914 std::move(colorSpace), 915 surfaceProps); 916 } 917 918 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext( 919 const GrBackendTexture& tex, 920 GrSurfaceOrigin origin, 921 int sampleCnt, 922 sk_sp<SkColorSpace> colorSpace, 923 const SkSurfaceProps* props) { 924 ASSERT_SINGLE_OWNER_PRIV 925 SkASSERT(sampleCnt > 0); 926 sk_sp<GrSurfaceProxy> proxy( 927 this->proxyProvider()->wrapBackendTextureAsRenderTarget(tex, origin, sampleCnt)); 928 if (!proxy) { 929 return nullptr; 930 } 931 932 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 933 std::move(colorSpace), 934 props); 935 } 936 937 sk_sp<GrRenderTargetContext> GrContextPriv::makeVulkanSecondaryCBRenderTargetContext( 938 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo, const SkSurfaceProps* props) { 939 ASSERT_SINGLE_OWNER_PRIV 940 sk_sp<GrSurfaceProxy> proxy( 941 this->proxyProvider()->wrapVulkanSecondaryCBAsRenderTarget(imageInfo, vkInfo)); 942 if (!proxy) { 943 return nullptr; 944 } 945 946 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 947 imageInfo.refColorSpace(), 948 props); 949 } 950 951 void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) { 952 fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject); 953 } 954 955 void GrContextPriv::moveOpListsToDDL(SkDeferredDisplayList* ddl) { 956 fContext->fDrawingManager->moveOpListsToDDL(ddl); 957 } 958 959 void GrContextPriv::copyOpListsFromDDL(const SkDeferredDisplayList* ddl, 960 GrRenderTargetProxy* newDest) { 961 fContext->fDrawingManager->copyOpListsFromDDL(ddl, newDest); 962 } 963 964 static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) { 965 switch (config) { 966 case kAlpha_8_GrPixelConfig: 967 case kAlpha_8_as_Alpha_GrPixelConfig: 968 case kAlpha_8_as_Red_GrPixelConfig: 969 case kRGB_565_GrPixelConfig: 970 case kRGBA_4444_GrPixelConfig: 971 case kBGRA_8888_GrPixelConfig: 972 case kRGBA_1010102_GrPixelConfig: 973 case kRGBA_half_GrPixelConfig: 974 return kRGBA_8888_GrPixelConfig; 975 case kSBGRA_8888_GrPixelConfig: 976 return kSRGBA_8888_GrPixelConfig; 977 case kAlpha_half_GrPixelConfig: 978 case kAlpha_half_as_Red_GrPixelConfig: 979 return kRGBA_half_GrPixelConfig; 980 case kGray_8_GrPixelConfig: 981 case kGray_8_as_Lum_GrPixelConfig: 982 case kGray_8_as_Red_GrPixelConfig: 983 return kRGB_888_GrPixelConfig; 984 default: 985 return kUnknown_GrPixelConfig; 986 } 987 } 988 989 sk_sp<GrRenderTargetContext> GrContextPriv::makeDeferredRenderTargetContextWithFallback( 990 const GrBackendFormat& format, 991 SkBackingFit fit, 992 int width, int height, 993 GrPixelConfig config, 994 sk_sp<SkColorSpace> colorSpace, 995 int sampleCnt, 996 GrMipMapped mipMapped, 997 GrSurfaceOrigin origin, 998 const SkSurfaceProps* surfaceProps, 999 SkBudgeted budgeted) { 1000 GrBackendFormat localFormat = format; 1001 SkASSERT(sampleCnt > 0); 1002 if (0 == fContext->contextPriv().caps()->getRenderTargetSampleCount(sampleCnt, config)) { 1003 config = GrPixelConfigFallback(config); 1004 // TODO: First we should be checking the getRenderTargetSampleCount from the GrBackendFormat 1005 // and not GrPixelConfig. Besides that, we should implement the fallback in the caps, but 1006 // for now we just convert the fallback pixel config to an SkColorType and then get the 1007 // GrBackendFormat from that. 1008 SkColorType colorType; 1009 if (!GrPixelConfigToColorType(config, &colorType)) { 1010 return nullptr; 1011 } 1012 localFormat = fContext->fCaps->getBackendFormatFromColorType(colorType); 1013 } 1014 1015 return this->makeDeferredRenderTargetContext(localFormat, fit, width, height, config, 1016 std::move(colorSpace), sampleCnt, mipMapped, 1017 origin, surfaceProps, budgeted); 1018 } 1019 1020 sk_sp<GrRenderTargetContext> GrContextPriv::makeDeferredRenderTargetContext( 1021 const GrBackendFormat& format, 1022 SkBackingFit fit, 1023 int width, int height, 1024 GrPixelConfig config, 1025 sk_sp<SkColorSpace> colorSpace, 1026 int sampleCnt, 1027 GrMipMapped mipMapped, 1028 GrSurfaceOrigin origin, 1029 const SkSurfaceProps* surfaceProps, 1030 SkBudgeted budgeted) { 1031 SkASSERT(sampleCnt > 0); 1032 if (fContext->abandoned()) { 1033 return nullptr; 1034 } 1035 1036 GrSurfaceDesc desc; 1037 desc.fFlags = kRenderTarget_GrSurfaceFlag; 1038 desc.fWidth = width; 1039 desc.fHeight = height; 1040 desc.fConfig = config; 1041 desc.fSampleCnt = sampleCnt; 1042 1043 sk_sp<GrTextureProxy> rtp; 1044 if (GrMipMapped::kNo == mipMapped) { 1045 rtp = fContext->fProxyProvider->createProxy(format, desc, origin, fit, budgeted); 1046 } else { 1047 rtp = fContext->fProxyProvider->createMipMapProxy(format, desc, origin, budgeted); 1048 } 1049 if (!rtp) { 1050 return nullptr; 1051 } 1052 1053 sk_sp<GrRenderTargetContext> renderTargetContext( 1054 fContext->fDrawingManager->makeRenderTargetContext(std::move(rtp), 1055 std::move(colorSpace), 1056 surfaceProps)); 1057 if (!renderTargetContext) { 1058 return nullptr; 1059 } 1060 1061 renderTargetContext->discard(); 1062 1063 return renderTargetContext; 1064 } 1065 1066 sk_sp<GrSkSLFPFactoryCache> GrContextPriv::getFPFactoryCache() { return fContext->fFPFactoryCache; } 1067 1068 std::unique_ptr<GrFragmentProcessor> GrContext::createPMToUPMEffect( 1069 std::unique_ptr<GrFragmentProcessor> fp) { 1070 ASSERT_SINGLE_OWNER 1071 // We should have already called this->validPMUPMConversionExists() in this case 1072 SkASSERT(fDidTestPMConversions); 1073 // ...and it should have succeeded 1074 SkASSERT(this->validPMUPMConversionExists()); 1075 1076 return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToUnpremul); 1077 } 1078 1079 std::unique_ptr<GrFragmentProcessor> GrContext::createUPMToPMEffect( 1080 std::unique_ptr<GrFragmentProcessor> fp) { 1081 ASSERT_SINGLE_OWNER 1082 // We should have already called this->validPMUPMConversionExists() in this case 1083 SkASSERT(fDidTestPMConversions); 1084 // ...and it should have succeeded 1085 SkASSERT(this->validPMUPMConversionExists()); 1086 1087 return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToPremul); 1088 } 1089 1090 bool GrContext::validPMUPMConversionExists() { 1091 ASSERT_SINGLE_OWNER 1092 if (!fDidTestPMConversions) { 1093 fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this); 1094 fDidTestPMConversions = true; 1095 } 1096 1097 // The PM<->UPM tests fail or succeed together so we only need to check one. 1098 return fPMUPMConversionsRoundTrip; 1099 } 1100 1101 bool GrContext::supportsDistanceFieldText() const { 1102 return fCaps->shaderCaps()->supportsDistanceFieldText(); 1103 } 1104 1105 ////////////////////////////////////////////////////////////////////////////// 1106 1107 // DDL TODO: remove 'maxResources' 1108 void GrContext::getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const { 1109 ASSERT_SINGLE_OWNER 1110 if (maxResources) { 1111 *maxResources = fResourceCache->getMaxResourceCount(); 1112 } 1113 if (maxResourceBytes) { 1114 *maxResourceBytes = fResourceCache->getMaxResourceBytes(); 1115 } 1116 } 1117 1118 void GrContext::setResourceCacheLimits(int maxResources, size_t maxResourceBytes) { 1119 ASSERT_SINGLE_OWNER 1120 fResourceCache->setLimits(maxResources, maxResourceBytes); 1121 } 1122 1123 ////////////////////////////////////////////////////////////////////////////// 1124 void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { 1125 ASSERT_SINGLE_OWNER 1126 fResourceCache->dumpMemoryStatistics(traceMemoryDump); 1127 traceMemoryDump->dumpNumericValue("skia/gr_text_blob_cache", "size", "bytes", 1128 fTextBlobCache->usedBytes()); 1129 } 1130 1131 ////////////////////////////////////////////////////////////////////////////// 1132 #ifdef SK_ENABLE_DUMP_GPU 1133 #include "SkJSONWriter.h" 1134 SkString GrContextPriv::dump() const { 1135 SkDynamicMemoryWStream stream; 1136 SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty); 1137 writer.beginObject(); 1138 1139 static const char* kBackendStr[] = { 1140 "Metal", 1141 "OpenGL", 1142 "Vulkan", 1143 "Mock", 1144 }; 1145 GR_STATIC_ASSERT(0 == (unsigned)GrBackendApi::kMetal); 1146 GR_STATIC_ASSERT(1 == (unsigned)GrBackendApi::kOpenGL); 1147 GR_STATIC_ASSERT(2 == (unsigned)GrBackendApi::kVulkan); 1148 GR_STATIC_ASSERT(3 == (unsigned)GrBackendApi::kMock); 1149 writer.appendString("backend", kBackendStr[(unsigned)fContext->backend()]); 1150 1151 writer.appendName("caps"); 1152 fContext->fCaps->dumpJSON(&writer); 1153 1154 writer.appendName("gpu"); 1155 fContext->fGpu->dumpJSON(&writer); 1156 1157 // Flush JSON to the memory stream 1158 writer.endObject(); 1159 writer.flush(); 1160 1161 // Null terminate the JSON data in the memory stream 1162 stream.write8(0); 1163 1164 // Allocate a string big enough to hold all the data, then copy out of the stream 1165 SkString result(stream.bytesWritten()); 1166 stream.copyToAndReset(result.writable_str()); 1167 return result; 1168 } 1169 #endif 1170