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