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