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