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 "GrBackendSemaphore.h" 9 #include "GrContext.h" 10 #include "GrClip.h" 11 #include "GrContextOptions.h" 12 #include "GrContextPriv.h" 13 #include "GrDrawingManager.h" 14 #include "GrGpu.h" 15 #include "GrProxyProvider.h" 16 #include "GrRenderTargetContext.h" 17 #include "GrRenderTargetProxy.h" 18 #include "GrResourceCache.h" 19 #include "GrResourceProvider.h" 20 #include "GrSemaphore.h" 21 #include "GrSoftwarePathRenderer.h" 22 #include "GrSurfaceContext.h" 23 #include "GrSurfacePriv.h" 24 #include "GrSurfaceProxyPriv.h" 25 #include "GrTexture.h" 26 #include "GrTextureContext.h" 27 #include "GrTracing.h" 28 29 #include "SkConvertPixels.h" 30 #include "SkDeferredDisplayList.h" 31 #include "SkGr.h" 32 #include "SkJSONWriter.h" 33 #include "SkMakeUnique.h" 34 #include "SkTaskGroup.h" 35 #include "SkUnPreMultiplyPriv.h" 36 #include "effects/GrConfigConversionEffect.h" 37 #include "text/GrTextBlobCache.h" 38 39 #include "gl/GrGLGpu.h" 40 #include "mock/GrMockGpu.h" 41 #ifdef SK_METAL 42 #include "mtl/GrMtlTrampoline.h" 43 #endif 44 #include "ddl/GrDDLGpu.h" 45 #ifdef SK_VULKAN 46 #include "vk/GrVkGpu.h" 47 #endif 48 49 #define ASSERT_OWNED_PROXY(P) \ 50 SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this) 51 #define ASSERT_OWNED_PROXY_PRIV(P) \ 52 SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == fContext) 53 54 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) 55 #define ASSERT_SINGLE_OWNER \ 56 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);) 57 #define ASSERT_SINGLE_OWNER_PRIV \ 58 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);) 59 #define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; } 60 #define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; } 61 #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; } 62 #define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; } 63 #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; } 64 65 //////////////////////////////////////////////////////////////////////////////// 66 67 class SK_API GrDirectContext : public GrContext { 68 public: 69 GrDirectContext(GrBackend backend) : INHERITED(backend) { } 70 71 protected: 72 73 private: 74 typedef GrContext INHERITED; 75 }; 76 77 class SK_API GrDDLContext : public GrContext { 78 public: 79 GrDDLContext(GrContextThreadSafeProxy* proxy) : INHERITED(proxy) {} 80 81 protected: 82 83 private: 84 typedef GrContext INHERITED; 85 }; 86 87 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) { 88 GrContextOptions defaultOptions; 89 return Create(backend, backendContext, defaultOptions); 90 } 91 92 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, 93 const GrContextOptions& options) { 94 95 sk_sp<GrContext> context(new GrDirectContext(backend)); 96 97 context->fGpu = GrGpu::Make(backend, backendContext, options, context.get()); 98 if (!context->fGpu) { 99 return nullptr; 100 } 101 102 if (!context->init(options)) { 103 return nullptr; 104 } 105 106 return context.release(); 107 } 108 109 sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface) { 110 GrContextOptions defaultOptions; 111 return MakeGL(std::move(interface), defaultOptions); 112 } 113 114 sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface, 115 const GrContextOptions& options) { 116 sk_sp<GrContext> context(new GrDirectContext(kOpenGL_GrBackend)); 117 118 context->fGpu = GrGLGpu::Make(std::move(interface), options, context.get()); 119 if (!context->fGpu) { 120 return nullptr; 121 } 122 if (!context->init(options)) { 123 return nullptr; 124 } 125 return context; 126 } 127 128 sk_sp<GrContext> GrContext::MakeGL(const GrGLInterface* interface) { 129 return MakeGL(sk_ref_sp(interface)); 130 } 131 132 sk_sp<GrContext> GrContext::MakeGL(const GrGLInterface* interface, 133 const GrContextOptions& options) { 134 return MakeGL(sk_ref_sp(interface), options); 135 } 136 137 sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions) { 138 GrContextOptions defaultOptions; 139 return MakeMock(mockOptions, defaultOptions); 140 } 141 142 sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions, 143 const GrContextOptions& options) { 144 sk_sp<GrContext> context(new GrDirectContext(kMock_GrBackend)); 145 146 context->fGpu = GrMockGpu::Make(mockOptions, options, context.get()); 147 if (!context->fGpu) { 148 return nullptr; 149 } 150 if (!context->init(options)) { 151 return nullptr; 152 } 153 return context; 154 } 155 156 #ifdef SK_VULKAN 157 sk_sp<GrContext> GrContext::MakeVulkan(sk_sp<const GrVkBackendContext> backendContext) { 158 GrContextOptions defaultOptions; 159 return MakeVulkan(std::move(backendContext), defaultOptions); 160 } 161 162 sk_sp<GrContext> GrContext::MakeVulkan(sk_sp<const GrVkBackendContext> backendContext, 163 const GrContextOptions& options) { 164 sk_sp<GrContext> context(new GrDirectContext(kVulkan_GrBackend)); 165 166 context->fGpu = GrVkGpu::Make(std::move(backendContext), options, context.get()); 167 if (!context->fGpu) { 168 return nullptr; 169 } 170 if (!context->init(options)) { 171 return nullptr; 172 } 173 return context; 174 } 175 #endif 176 177 #ifdef SK_METAL 178 sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue) { 179 GrContextOptions defaultOptions; 180 return MakeMetal(device, queue, defaultOptions); 181 } 182 183 sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue, const GrContextOptions& options) { 184 sk_sp<GrContext> context(new GrContext(kMetal_GrBackend)); 185 186 context->fGpu = GrMtlTrampoline::MakeGpu(context.get(), options, device, queue); 187 if (!context->fGpu) { 188 return nullptr; 189 } 190 if (!context->init(options)) { 191 return nullptr; 192 } 193 return context; 194 } 195 #endif 196 197 static int32_t gNextID = 1; 198 static int32_t next_id() { 199 int32_t id; 200 do { 201 id = sk_atomic_inc(&gNextID); 202 } while (id == SK_InvalidGenID); 203 return id; 204 } 205 206 sk_sp<GrContext> GrContextPriv::MakeDDL(GrContextThreadSafeProxy* proxy) { 207 sk_sp<GrContext> context(new GrDDLContext(proxy)); 208 209 // Note: we aren't creating a Gpu here. This causes the resource provider & cache to 210 // also not be created 211 if (!context->init(proxy->fOptions)) { 212 return nullptr; 213 } 214 return context; 215 } 216 217 GrContext::GrContext(GrBackend backend) 218 : fUniqueID(next_id()) 219 , fBackend(backend) { 220 fResourceCache = nullptr; 221 fResourceProvider = nullptr; 222 fProxyProvider = nullptr; 223 fAtlasGlyphCache = nullptr; 224 } 225 226 GrContext::GrContext(GrContextThreadSafeProxy* proxy) 227 : fCaps(proxy->fCaps) 228 , fUniqueID(proxy->fContextUniqueID) 229 , fBackend(proxy->fBackend) { 230 fResourceCache = nullptr; 231 fResourceProvider = nullptr; 232 fProxyProvider = nullptr; 233 fAtlasGlyphCache = nullptr; 234 } 235 236 bool GrContext::init(const GrContextOptions& options) { 237 ASSERT_SINGLE_OWNER 238 239 if (fGpu) { 240 fCaps = fGpu->refCaps(); 241 fResourceCache = new GrResourceCache(fCaps.get(), fUniqueID); 242 fResourceProvider = new GrResourceProvider(fGpu.get(), fResourceCache, &fSingleOwner); 243 } 244 245 fProxyProvider = new GrProxyProvider(fResourceProvider, fResourceCache, fCaps, &fSingleOwner); 246 247 if (fResourceCache) { 248 fResourceCache->setProxyProvider(fProxyProvider); 249 } 250 251 // DDL TODO: we need to think through how the task group & persistent cache 252 // get passed on to/shared between all the DDLRecorders created with this context. 253 fThreadSafeProxy.reset(new GrContextThreadSafeProxy(fCaps, this->uniqueID(), fBackend, 254 options)); 255 256 fDisableGpuYUVConversion = options.fDisableGpuYUVConversion; 257 fDidTestPMConversions = false; 258 259 GrPathRendererChain::Options prcOptions; 260 prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching; 261 #if GR_TEST_UTILS 262 prcOptions.fGpuPathRenderers = options.fGpuPathRenderers; 263 #endif 264 if (options.fDisableDistanceFieldPaths) { 265 prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall; 266 } 267 268 if (!fResourceCache) { 269 // DDL TODO: remove this crippling of the path renderer chain 270 // Disable the small path renderer bc of the proxies in the atlas. They need to be 271 // unified when the opLists are added back to the destination drawing manager. 272 prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall; 273 } 274 275 GrAtlasTextContext::Options atlasTextContextOptions; 276 atlasTextContextOptions.fMaxDistanceFieldFontSize = options.fGlyphsAsPathsFontSize; 277 atlasTextContextOptions.fMinDistanceFieldFontSize = options.fMinDistanceFieldFontSize; 278 atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = false; 279 #if SK_SUPPORT_ATLAS_TEXT 280 if (GrContextOptions::Enable::kYes == options.fDistanceFieldGlyphVerticesAlwaysHaveW) { 281 atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = true; 282 } 283 #endif 284 285 fDrawingManager.reset( 286 new GrDrawingManager(this, prcOptions, atlasTextContextOptions, &fSingleOwner)); 287 288 GrDrawOpAtlas::AllowMultitexturing allowMultitexturing; 289 if (GrContextOptions::Enable::kNo == options.fAllowMultipleGlyphCacheTextures || 290 // multitexturing supported only if range can represent the index + texcoords fully 291 !(fCaps->shaderCaps()->floatIs32Bits() || fCaps->shaderCaps()->integerSupport())) { 292 allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kNo; 293 } else { 294 allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes; 295 } 296 fAtlasGlyphCache = new GrAtlasGlyphCache(this, options.fGlyphCacheTextureMaximumBytes, 297 allowMultitexturing); 298 this->contextPriv().addOnFlushCallbackObject(fAtlasGlyphCache); 299 300 fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this, this->uniqueID())); 301 302 if (options.fExecutor) { 303 fTaskGroup = skstd::make_unique<SkTaskGroup>(*options.fExecutor); 304 } 305 306 fPersistentCache = options.fPersistentCache; 307 308 return true; 309 } 310 311 GrContext::~GrContext() { 312 ASSERT_SINGLE_OWNER 313 314 if (fGpu) { 315 this->flush(); 316 } 317 318 if (fDrawingManager) { 319 fDrawingManager->cleanup(); 320 } 321 322 for (int i = 0; i < fCleanUpData.count(); ++i) { 323 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); 324 } 325 326 delete fResourceProvider; 327 delete fResourceCache; 328 delete fProxyProvider; 329 delete fAtlasGlyphCache; 330 } 331 332 sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() { 333 return fThreadSafeProxy; 334 } 335 336 void GrContext::abandonContext() { 337 ASSERT_SINGLE_OWNER 338 339 fProxyProvider->abandon(); 340 fResourceProvider->abandon(); 341 342 // Need to abandon the drawing manager first so all the render targets 343 // will be released/forgotten before they too are abandoned. 344 fDrawingManager->abandon(); 345 346 // abandon first to so destructors 347 // don't try to free the resources in the API. 348 fResourceCache->abandonAll(); 349 350 fGpu->disconnect(GrGpu::DisconnectType::kAbandon); 351 352 fAtlasGlyphCache->freeAll(); 353 fTextBlobCache->freeAll(); 354 } 355 356 void GrContext::releaseResourcesAndAbandonContext() { 357 ASSERT_SINGLE_OWNER 358 359 fProxyProvider->abandon(); 360 fResourceProvider->abandon(); 361 362 // Need to abandon the drawing manager first so all the render targets 363 // will be released/forgotten before they too are abandoned. 364 fDrawingManager->abandon(); 365 366 // Release all resources in the backend 3D API. 367 fResourceCache->releaseAll(); 368 369 fGpu->disconnect(GrGpu::DisconnectType::kCleanup); 370 371 fAtlasGlyphCache->freeAll(); 372 fTextBlobCache->freeAll(); 373 } 374 375 void GrContext::resetContext(uint32_t state) { 376 ASSERT_SINGLE_OWNER 377 fGpu->markContextDirty(state); 378 } 379 380 void GrContext::freeGpuResources() { 381 ASSERT_SINGLE_OWNER 382 383 this->flush(); 384 385 fAtlasGlyphCache->freeAll(); 386 387 fDrawingManager->freeGpuResources(); 388 389 fResourceCache->purgeAllUnlocked(); 390 } 391 392 void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) { 393 ASSERT_SINGLE_OWNER 394 fResourceCache->purgeAsNeeded(); 395 fResourceCache->purgeResourcesNotUsedSince(GrStdSteadyClock::now() - msNotUsed); 396 397 fTextBlobCache->purgeStaleBlobs(); 398 } 399 400 void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) { 401 ASSERT_SINGLE_OWNER 402 fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources); 403 } 404 405 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const { 406 ASSERT_SINGLE_OWNER 407 408 if (resourceCount) { 409 *resourceCount = fResourceCache->getBudgetedResourceCount(); 410 } 411 if (resourceBytes) { 412 *resourceBytes = fResourceCache->getBudgetedResourceBytes(); 413 } 414 } 415 416 size_t GrContext::getResourceCachePurgeableBytes() const { 417 ASSERT_SINGLE_OWNER 418 return fResourceCache->getPurgeableBytes(); 419 } 420 421 //////////////////////////////////////////////////////////////////////////////// 422 423 void GrContext::TextBlobCacheOverBudgetCB(void* data) { 424 SkASSERT(data); 425 // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on 426 // GrRenderTargetContext to perform a necessary flush. The solution is to move drawText calls 427 // to below the GrContext level, but this is not trivial because they call drawPath on 428 // SkGpuDevice. 429 GrContext* context = reinterpret_cast<GrContext*>(data); 430 context->flush(); 431 } 432 433 //////////////////////////////////////////////////////////////////////////////// 434 435 void GrContext::flush() { 436 ASSERT_SINGLE_OWNER 437 RETURN_IF_ABANDONED 438 439 fDrawingManager->flush(nullptr); 440 } 441 442 GrSemaphoresSubmitted GrContext::flushAndSignalSemaphores(int numSemaphores, 443 GrBackendSemaphore signalSemaphores[]) { 444 ASSERT_SINGLE_OWNER 445 if (fDrawingManager->wasAbandoned()) { return GrSemaphoresSubmitted::kNo; } 446 447 return fDrawingManager->flush(nullptr, numSemaphores, signalSemaphores); 448 } 449 450 void GrContextPriv::flush(GrSurfaceProxy* proxy) { 451 ASSERT_SINGLE_OWNER_PRIV 452 RETURN_IF_ABANDONED_PRIV 453 ASSERT_OWNED_PROXY_PRIV(proxy); 454 455 fContext->fDrawingManager->flush(proxy); 456 } 457 458 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes, 459 const void* inPixels, size_t outRowBytes, void* outPixels) { 460 SkColorType colorType; 461 if (!GrPixelConfigToColorType(srcConfig, &colorType) || 462 4 != SkColorTypeBytesPerPixel(colorType)) 463 { 464 return false; 465 } 466 467 for (int y = 0; y < height; y++) { 468 SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width); 469 outPixels = SkTAddOffset<void>(outPixels, outRowBytes); 470 inPixels = SkTAddOffset<const void>(inPixels, inRowBytes); 471 } 472 473 return true; 474 } 475 476 static bool valid_premul_config(GrPixelConfig config) { 477 return GrPixelConfigIs8888Unorm(config) || kRGBA_half_GrPixelConfig == config; 478 } 479 480 static bool valid_pixel_conversion(GrPixelConfig srcConfig, GrPixelConfig dstConfig, 481 bool premulConversion) { 482 // We don't allow conversion between integer configs and float/fixed configs. 483 if (GrPixelConfigIsSint(srcConfig) != GrPixelConfigIsSint(dstConfig)) { 484 return false; 485 } 486 487 // We only allow premul <-> unpremul conversions for some formats 488 if (premulConversion && (!valid_premul_config(srcConfig) || !valid_premul_config(dstConfig))) { 489 return false; 490 } 491 492 return true; 493 } 494 495 static bool pm_upm_must_round_trip(GrPixelConfig config, SkColorSpace* colorSpace) { 496 return !colorSpace && 497 (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config); 498 } 499 500 bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst, 501 int left, int top, int width, int height, 502 GrPixelConfig srcConfig, SkColorSpace* srcColorSpace, 503 const void* buffer, size_t rowBytes, 504 uint32_t pixelOpsFlags) { 505 // TODO: Color space conversion 506 507 ASSERT_SINGLE_OWNER_PRIV 508 RETURN_FALSE_IF_ABANDONED_PRIV 509 SkASSERT(dst); 510 ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy()); 511 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext); 512 513 if (!dst->asSurfaceProxy()->instantiate(this->resourceProvider())) { 514 return false; 515 } 516 517 GrSurfaceProxy* dstProxy = dst->asSurfaceProxy(); 518 GrSurface* dstSurface = dstProxy->priv().peekSurface(); 519 520 // The src is unpremul but the dst is premul -> premul the src before or as part of the write 521 const bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags); 522 if (!valid_pixel_conversion(srcConfig, dstProxy->config(), premul)) { 523 return false; 524 } 525 526 // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data, 527 // without any color spaces attached, and the caller wants us to premul. 528 bool useConfigConversionEffect = 529 premul && pm_upm_must_round_trip(srcConfig, srcColorSpace) && 530 pm_upm_must_round_trip(dstProxy->config(), dst->colorSpaceInfo().colorSpace()); 531 532 // Are we going to try to premul as part of a draw? For the non-legacy case, we always allow 533 // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly. 534 bool premulOnGpu = premul && 535 (!useConfigConversionEffect || fContext->validPMUPMConversionExists()); 536 537 // Trim the params here so that if we wind up making a temporary surface it can be as small as 538 // necessary and because GrGpu::getWritePixelsInfo requires it. 539 if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(), 540 GrBytesPerPixel(srcConfig), &left, &top, &width, 541 &height, &buffer, &rowBytes)) { 542 return false; 543 } 544 545 GrGpu::DrawPreference drawPreference = premulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference 546 : GrGpu::kNoDraw_DrawPreference; 547 GrGpu::WritePixelTempDrawInfo tempDrawInfo; 548 if (!fContext->fGpu->getWritePixelsInfo(dstSurface, dstProxy->origin(), width, height, 549 srcConfig, &drawPreference, &tempDrawInfo)) { 550 return false; 551 } 552 553 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) { 554 this->flush(nullptr); // MDB TODO: tighten this 555 } 556 557 sk_sp<GrTextureProxy> tempProxy; 558 if (GrGpu::kNoDraw_DrawPreference != drawPreference) { 559 tempProxy = this->proxyProvider()->createProxy(tempDrawInfo.fTempSurfaceDesc, 560 SkBackingFit::kApprox, 561 SkBudgeted::kYes); 562 if (!tempProxy && GrGpu::kRequireDraw_DrawPreference == drawPreference) { 563 return false; 564 } 565 } 566 567 // temp buffer for doing sw premul conversion, if needed. 568 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); 569 // We need to do sw premul if we were unable to create a RT for drawing, or if we can't do the 570 // premul on the GPU 571 if (premul && (!tempProxy || !premulOnGpu)) { 572 size_t tmpRowBytes = 4 * width; 573 tmpPixels.reset(width * height); 574 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes, 575 tmpPixels.get())) { 576 return false; 577 } 578 rowBytes = tmpRowBytes; 579 buffer = tmpPixels.get(); 580 } 581 582 if (tempProxy) { 583 auto fp = GrSimpleTextureEffect::Make(tempProxy, SkMatrix::I()); 584 if (premulOnGpu) { 585 fp = fContext->createUPMToPMEffect(std::move(fp), useConfigConversionEffect); 586 } 587 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle); 588 if (!fp) { 589 return false; 590 } 591 592 if (!tempProxy->instantiate(this->resourceProvider())) { 593 return false; 594 } 595 GrTexture* texture = tempProxy->priv().peekTexture(); 596 597 if (tempProxy->priv().hasPendingIO()) { 598 this->flush(tempProxy.get()); 599 } 600 601 if (!fContext->fGpu->writePixels(texture, tempProxy->origin(), 0, 0, width, height, 602 tempDrawInfo.fWriteConfig, buffer, rowBytes)) { 603 return false; 604 } 605 tempProxy = nullptr; 606 607 SkMatrix matrix; 608 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); 609 GrRenderTargetContext* renderTargetContext = dst->asRenderTargetContext(); 610 if (!renderTargetContext) { 611 return false; 612 } 613 GrPaint paint; 614 paint.addColorFragmentProcessor(std::move(fp)); 615 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 616 paint.setAllowSRGBInputs(dst->colorSpaceInfo().isGammaCorrect() || 617 GrPixelConfigIsSRGB(dst->colorSpaceInfo().config())); 618 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); 619 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect, 620 nullptr); 621 622 if (kFlushWrites_PixelOp & pixelOpsFlags) { 623 this->flushSurfaceWrites(renderTargetContext->asRenderTargetProxy()); 624 } 625 } else { 626 return fContext->fGpu->writePixels(dstSurface, dstProxy->origin(), left, top, width, 627 height, srcConfig, buffer, rowBytes); 628 } 629 return true; 630 } 631 632 bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src, 633 int left, int top, int width, int height, 634 GrPixelConfig dstConfig, SkColorSpace* dstColorSpace, 635 void* buffer, size_t rowBytes, uint32_t flags) { 636 // TODO: Color space conversion 637 638 ASSERT_SINGLE_OWNER_PRIV 639 RETURN_FALSE_IF_ABANDONED_PRIV 640 SkASSERT(src); 641 ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy()); 642 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext); 643 644 // MDB TODO: delay this instantiation until later in the method 645 if (!src->asSurfaceProxy()->instantiate(this->resourceProvider())) { 646 return false; 647 } 648 649 GrSurfaceProxy* srcProxy = src->asSurfaceProxy(); 650 GrSurface* srcSurface = srcProxy->priv().peekSurface(); 651 652 // The src is premul but the dst is unpremul -> unpremul the src after or as part of the read 653 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags); 654 if (!valid_pixel_conversion(srcProxy->config(), dstConfig, unpremul)) { 655 return false; 656 } 657 658 // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data, 659 // without any color spaces attached, and the caller wants us to unpremul. 660 bool useConfigConversionEffect = 661 unpremul && 662 pm_upm_must_round_trip(srcProxy->config(), src->colorSpaceInfo().colorSpace()) && 663 pm_upm_must_round_trip(dstConfig, dstColorSpace); 664 665 // Are we going to try to unpremul as part of a draw? For the non-legacy case, we always allow 666 // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly. 667 bool unpremulOnGpu = unpremul && 668 (!useConfigConversionEffect || fContext->validPMUPMConversionExists()); 669 670 // Adjust the params so that if we wind up using an intermediate surface we've already done 671 // all the trimming and the temporary can be the min size required. 672 if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(), 673 GrBytesPerPixel(dstConfig), &left, 674 &top, &width, &height, &buffer, &rowBytes)) { 675 return false; 676 } 677 678 GrGpu::DrawPreference drawPreference = unpremulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference 679 : GrGpu::kNoDraw_DrawPreference; 680 GrGpu::ReadPixelTempDrawInfo tempDrawInfo; 681 if (!fContext->fGpu->getReadPixelsInfo(srcSurface, srcProxy->origin(), width, height, rowBytes, 682 dstConfig, &drawPreference, &tempDrawInfo)) { 683 return false; 684 } 685 686 if (!(kDontFlush_PixelOpsFlag & flags) && srcSurface->surfacePriv().hasPendingWrite()) { 687 this->flush(nullptr); // MDB TODO: tighten this 688 } 689 690 sk_sp<GrSurfaceProxy> proxyToRead = src->asSurfaceProxyRef(); 691 bool didTempDraw = false; 692 if (GrGpu::kNoDraw_DrawPreference != drawPreference) { 693 if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) { 694 // We only respect this when the entire src is being read. Otherwise we can trigger too 695 // many odd ball texture sizes and trash the cache. 696 if (width != srcSurface->width() || height != srcSurface->height()) { 697 tempDrawInfo.fTempSurfaceFit= SkBackingFit::kApprox; 698 } 699 } 700 // TODO: Need to decide the semantics of this function for color spaces. Do we support 701 // conversion to a passed-in color space? For now, specifying nullptr means that this 702 // path will do no conversion, so it will match the behavior of the non-draw path. 703 sk_sp<GrRenderTargetContext> tempRTC = fContext->makeDeferredRenderTargetContext( 704 tempDrawInfo.fTempSurfaceFit, 705 tempDrawInfo.fTempSurfaceDesc.fWidth, 706 tempDrawInfo.fTempSurfaceDesc.fHeight, 707 tempDrawInfo.fTempSurfaceDesc.fConfig, 708 nullptr, 709 tempDrawInfo.fTempSurfaceDesc.fSampleCnt, 710 GrMipMapped::kNo, 711 tempDrawInfo.fTempSurfaceDesc.fOrigin); 712 if (tempRTC) { 713 // Adding discard to appease vulkan validation warning about loading uninitialized data 714 // on draw 715 tempRTC->discard(); 716 SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top)); 717 sk_sp<GrTextureProxy> proxy = src->asTextureProxyRef(); 718 auto fp = GrSimpleTextureEffect::Make(std::move(proxy), textureMatrix); 719 if (unpremulOnGpu) { 720 fp = fContext->createPMToUPMEffect(std::move(fp), useConfigConversionEffect); 721 // We no longer need to do this on CPU after the read back. 722 unpremul = false; 723 } 724 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle); 725 if (!fp) { 726 return false; 727 } 728 729 GrPaint paint; 730 paint.addColorFragmentProcessor(std::move(fp)); 731 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 732 paint.setAllowSRGBInputs(true); 733 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); 734 tempRTC->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect, 735 nullptr); 736 proxyToRead = tempRTC->asTextureProxyRef(); 737 left = 0; 738 top = 0; 739 didTempDraw = true; 740 } 741 } 742 743 if (!proxyToRead) { 744 return false; 745 } 746 747 if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) { 748 return false; 749 } 750 GrPixelConfig configToRead = dstConfig; 751 if (didTempDraw) { 752 this->flushSurfaceWrites(proxyToRead.get()); 753 configToRead = tempDrawInfo.fReadConfig; 754 } 755 756 if (!proxyToRead->instantiate(this->resourceProvider())) { 757 return false; 758 } 759 760 GrSurface* surfaceToRead = proxyToRead->priv().peekSurface(); 761 762 if (!fContext->fGpu->readPixels(surfaceToRead, proxyToRead->origin(), 763 left, top, width, height, configToRead, buffer, rowBytes)) { 764 return false; 765 } 766 767 // Perform umpremul conversion if we weren't able to perform it as a draw. 768 if (unpremul) { 769 SkColorType colorType; 770 if (!GrPixelConfigToColorType(dstConfig, &colorType) || 771 4 != SkColorTypeBytesPerPixel(colorType)) 772 { 773 return false; 774 } 775 776 for (int y = 0; y < height; y++) { 777 SkUnpremultiplyRow<false>((uint32_t*) buffer, (const uint32_t*) buffer, width); 778 buffer = SkTAddOffset<void>(buffer, rowBytes); 779 } 780 } 781 return true; 782 } 783 784 void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) { 785 ASSERT_SINGLE_OWNER_PRIV 786 RETURN_IF_ABANDONED_PRIV 787 SkASSERT(proxy); 788 ASSERT_OWNED_PROXY_PRIV(proxy); 789 fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy, 0, nullptr); 790 } 791 792 void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) { 793 ASSERT_SINGLE_OWNER_PRIV 794 RETURN_IF_ABANDONED_PRIV 795 SkASSERT(proxy); 796 ASSERT_OWNED_PROXY_PRIV(proxy); 797 if (proxy->priv().hasPendingWrite()) { 798 this->flush(proxy); 799 } 800 } 801 802 void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) { 803 ASSERT_SINGLE_OWNER_PRIV 804 RETURN_IF_ABANDONED_PRIV 805 SkASSERT(proxy); 806 ASSERT_OWNED_PROXY_PRIV(proxy); 807 if (proxy->priv().hasPendingIO()) { 808 this->flush(proxy); 809 } 810 } 811 812 //////////////////////////////////////////////////////////////////////////////// 813 814 sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy, 815 sk_sp<SkColorSpace> colorSpace, 816 const SkSurfaceProps* props) { 817 ASSERT_SINGLE_OWNER_PRIV 818 819 if (proxy->asRenderTargetProxy()) { 820 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 821 std::move(colorSpace), props); 822 } else { 823 SkASSERT(proxy->asTextureProxy()); 824 SkASSERT(!props); 825 return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace)); 826 } 827 } 828 829 sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc, 830 GrMipMapped mipMapped, 831 SkBackingFit fit, 832 SkBudgeted isDstBudgeted) { 833 834 sk_sp<GrTextureProxy> proxy; 835 if (GrMipMapped::kNo == mipMapped) { 836 proxy = this->proxyProvider()->createProxy(dstDesc, fit, isDstBudgeted); 837 } else { 838 SkASSERT(SkBackingFit::kExact == fit); 839 proxy = this->proxyProvider()->createMipMapProxy(dstDesc, isDstBudgeted); 840 } 841 if (!proxy) { 842 return nullptr; 843 } 844 845 sk_sp<GrSurfaceContext> sContext = this->makeWrappedSurfaceContext(std::move(proxy)); 846 if (sContext && sContext->asRenderTargetContext()) { 847 sContext->asRenderTargetContext()->discard(); 848 } 849 850 return sContext; 851 } 852 853 sk_sp<GrTextureContext> GrContextPriv::makeBackendTextureContext(const GrBackendTexture& tex, 854 GrSurfaceOrigin origin, 855 sk_sp<SkColorSpace> colorSpace) { 856 ASSERT_SINGLE_OWNER_PRIV 857 858 sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->createWrappedTextureProxy(tex, origin); 859 if (!proxy) { 860 return nullptr; 861 } 862 863 return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace)); 864 } 865 866 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext( 867 const GrBackendTexture& tex, 868 GrSurfaceOrigin origin, 869 int sampleCnt, 870 sk_sp<SkColorSpace> colorSpace, 871 const SkSurfaceProps* props) { 872 ASSERT_SINGLE_OWNER_PRIV 873 SkASSERT(sampleCnt > 0); 874 875 sk_sp<GrTextureProxy> proxy(this->proxyProvider()->createWrappedTextureProxy(tex, origin, 876 sampleCnt)); 877 if (!proxy) { 878 return nullptr; 879 } 880 881 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 882 std::move(colorSpace), props); 883 } 884 885 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext( 886 const GrBackendRenderTarget& backendRT, 887 GrSurfaceOrigin origin, 888 sk_sp<SkColorSpace> colorSpace, 889 const SkSurfaceProps* surfaceProps) { 890 ASSERT_SINGLE_OWNER_PRIV 891 892 sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->createWrappedRenderTargetProxy(backendRT, 893 origin); 894 if (!proxy) { 895 return nullptr; 896 } 897 898 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 899 std::move(colorSpace), 900 surfaceProps); 901 } 902 903 sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext( 904 const GrBackendTexture& tex, 905 GrSurfaceOrigin origin, 906 int sampleCnt, 907 sk_sp<SkColorSpace> colorSpace, 908 const SkSurfaceProps* props) { 909 ASSERT_SINGLE_OWNER_PRIV 910 SkASSERT(sampleCnt > 0); 911 sk_sp<GrSurfaceProxy> proxy(this->proxyProvider()->createWrappedRenderTargetProxy(tex, origin, 912 sampleCnt)); 913 if (!proxy) { 914 return nullptr; 915 } 916 917 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 918 std::move(colorSpace), 919 props); 920 } 921 922 void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) { 923 fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject); 924 } 925 926 void GrContextPriv::moveOpListsToDDL(SkDeferredDisplayList* ddl) { 927 fContext->fDrawingManager->moveOpListsToDDL(ddl); 928 } 929 930 void GrContextPriv::copyOpListsFromDDL(const SkDeferredDisplayList* ddl, 931 GrRenderTargetProxy* newDest) { 932 fContext->fDrawingManager->copyOpListsFromDDL(ddl, newDest); 933 } 934 935 static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) { 936 switch (config) { 937 case kAlpha_8_GrPixelConfig: 938 case kRGB_565_GrPixelConfig: 939 case kRGBA_4444_GrPixelConfig: 940 case kBGRA_8888_GrPixelConfig: 941 return kRGBA_8888_GrPixelConfig; 942 case kSBGRA_8888_GrPixelConfig: 943 return kSRGBA_8888_GrPixelConfig; 944 case kAlpha_half_GrPixelConfig: 945 return kRGBA_half_GrPixelConfig; 946 default: 947 return kUnknown_GrPixelConfig; 948 } 949 } 950 951 sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContextWithFallback( 952 SkBackingFit fit, 953 int width, int height, 954 GrPixelConfig config, 955 sk_sp<SkColorSpace> colorSpace, 956 int sampleCnt, 957 GrMipMapped mipMapped, 958 GrSurfaceOrigin origin, 959 const SkSurfaceProps* surfaceProps, 960 SkBudgeted budgeted) { 961 SkASSERT(sampleCnt > 0); 962 if (!this->caps()->isConfigRenderable(config, sampleCnt > 1)) { 963 config = GrPixelConfigFallback(config); 964 } 965 966 return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace), 967 sampleCnt, mipMapped, origin, surfaceProps, 968 budgeted); 969 } 970 971 sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext( 972 SkBackingFit fit, 973 int width, int height, 974 GrPixelConfig config, 975 sk_sp<SkColorSpace> colorSpace, 976 int sampleCnt, 977 GrMipMapped mipMapped, 978 GrSurfaceOrigin origin, 979 const SkSurfaceProps* surfaceProps, 980 SkBudgeted budgeted) { 981 SkASSERT(sampleCnt > 0); 982 if (this->abandoned()) { 983 return nullptr; 984 } 985 986 GrSurfaceDesc desc; 987 desc.fFlags = kRenderTarget_GrSurfaceFlag; 988 desc.fOrigin = origin; 989 desc.fWidth = width; 990 desc.fHeight = height; 991 desc.fConfig = config; 992 desc.fSampleCnt = sampleCnt; 993 994 sk_sp<GrTextureProxy> rtp; 995 if (GrMipMapped::kNo == mipMapped) { 996 rtp = fProxyProvider->createProxy(desc, fit, budgeted); 997 } else { 998 rtp = fProxyProvider->createMipMapProxy(desc, budgeted); 999 } 1000 if (!rtp) { 1001 return nullptr; 1002 } 1003 1004 sk_sp<GrRenderTargetContext> renderTargetContext( 1005 fDrawingManager->makeRenderTargetContext(std::move(rtp), 1006 std::move(colorSpace), 1007 surfaceProps)); 1008 if (!renderTargetContext) { 1009 return nullptr; 1010 } 1011 1012 renderTargetContext->discard(); 1013 1014 return renderTargetContext; 1015 } 1016 1017 bool GrContext::abandoned() const { 1018 ASSERT_SINGLE_OWNER 1019 return fDrawingManager->wasAbandoned(); 1020 } 1021 1022 std::unique_ptr<GrFragmentProcessor> GrContext::createPMToUPMEffect( 1023 std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) { 1024 ASSERT_SINGLE_OWNER 1025 // We have specialized effects that guarantee round-trip conversion for some formats 1026 if (useConfigConversionEffect) { 1027 // We should have already called this->validPMUPMConversionExists() in this case 1028 SkASSERT(fDidTestPMConversions); 1029 // ...and it should have succeeded 1030 SkASSERT(this->validPMUPMConversionExists()); 1031 1032 return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToUnpremul); 1033 } else { 1034 // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and 1035 // explicitly round the results. Just do the obvious, naive thing in the shader. 1036 return GrFragmentProcessor::UnpremulOutput(std::move(fp)); 1037 } 1038 } 1039 1040 std::unique_ptr<GrFragmentProcessor> GrContext::createUPMToPMEffect( 1041 std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) { 1042 ASSERT_SINGLE_OWNER 1043 // We have specialized effects that guarantee round-trip conversion for these formats 1044 if (useConfigConversionEffect) { 1045 // We should have already called this->validPMUPMConversionExists() in this case 1046 SkASSERT(fDidTestPMConversions); 1047 // ...and it should have succeeded 1048 SkASSERT(this->validPMUPMConversionExists()); 1049 1050 return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToPremul); 1051 } else { 1052 // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and 1053 // explicitly round the results. Just do the obvious, naive thing in the shader. 1054 return GrFragmentProcessor::PremulOutput(std::move(fp)); 1055 } 1056 } 1057 1058 bool GrContext::validPMUPMConversionExists() { 1059 ASSERT_SINGLE_OWNER 1060 if (!fDidTestPMConversions) { 1061 fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this); 1062 fDidTestPMConversions = true; 1063 } 1064 1065 // The PM<->UPM tests fail or succeed together so we only need to check one. 1066 return fPMUPMConversionsRoundTrip; 1067 } 1068 1069 ////////////////////////////////////////////////////////////////////////////// 1070 1071 void GrContext::getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const { 1072 ASSERT_SINGLE_OWNER 1073 if (maxResources) { 1074 *maxResources = fResourceCache->getMaxResourceCount(); 1075 } 1076 if (maxResourceBytes) { 1077 *maxResourceBytes = fResourceCache->getMaxResourceBytes(); 1078 } 1079 } 1080 1081 void GrContext::setResourceCacheLimits(int maxResources, size_t maxResourceBytes) { 1082 ASSERT_SINGLE_OWNER 1083 fResourceCache->setLimits(maxResources, maxResourceBytes); 1084 } 1085 1086 ////////////////////////////////////////////////////////////////////////////// 1087 1088 void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { 1089 ASSERT_SINGLE_OWNER 1090 fResourceCache->dumpMemoryStatistics(traceMemoryDump); 1091 } 1092 1093 ////////////////////////////////////////////////////////////////////////////// 1094 1095 SkString GrContext::dump() const { 1096 SkDynamicMemoryWStream stream; 1097 SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty); 1098 writer.beginObject(); 1099 1100 static const char* kBackendStr[] = { 1101 "Metal", 1102 "OpenGL", 1103 "Vulkan", 1104 "Mock", 1105 }; 1106 GR_STATIC_ASSERT(0 == kMetal_GrBackend); 1107 GR_STATIC_ASSERT(1 == kOpenGL_GrBackend); 1108 GR_STATIC_ASSERT(2 == kVulkan_GrBackend); 1109 GR_STATIC_ASSERT(3 == kMock_GrBackend); 1110 writer.appendString("backend", kBackendStr[fBackend]); 1111 1112 writer.appendName("caps"); 1113 fCaps->dumpJSON(&writer); 1114 1115 writer.appendName("gpu"); 1116 fGpu->dumpJSON(&writer); 1117 1118 // Flush JSON to the memory stream 1119 writer.endObject(); 1120 writer.flush(); 1121 1122 // Null terminate the JSON data in the memory stream 1123 stream.write8(0); 1124 1125 // Allocate a string big enough to hold all the data, then copy out of the stream 1126 SkString result(stream.bytesWritten()); 1127 stream.copyToAndReset(result.writable_str()); 1128 return result; 1129 } 1130