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