GrContext.cpp revision fb0bd98a43fa11e09705837418167dd72bb4a361
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> fp; 339 if (applyPremulToSrc) { 340 fp = fContext->createUPMToPMEffect(tempProxy, SkMatrix::I()); 341 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle); 342 // If premultiplying was the only reason for the draw, fall back to a straight write. 343 if (!fp) { 344 if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) { 345 tempProxy.reset(nullptr); 346 } 347 } else { 348 applyPremulToSrc = false; 349 } 350 } 351 if (tempProxy) { 352 if (!fp) { 353 fp = GrSimpleTextureEffect::Make(fContext->resourceProvider(), tempProxy, nullptr, 354 SkMatrix::I()); 355 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle); 356 357 if (!fp) { 358 return false; 359 } 360 } 361 if (tempProxy->priv().hasPendingIO()) { 362 this->flush(tempProxy.get()); 363 } 364 GrTexture* texture = tempProxy->instantiate(fContext->resourceProvider()); 365 if (!texture) { 366 return false; 367 } 368 if (applyPremulToSrc) { 369 size_t tmpRowBytes = 4 * width; 370 tmpPixels.reset(width * height); 371 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes, 372 tmpPixels.get())) { 373 return false; 374 } 375 rowBytes = tmpRowBytes; 376 buffer = tmpPixels.get(); 377 applyPremulToSrc = false; 378 } 379 if (!fContext->fGpu->writePixels(texture, 0, 0, width, height, 380 tempDrawInfo.fWriteConfig, buffer, 381 rowBytes)) { 382 return false; 383 } 384 SkMatrix matrix; 385 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); 386 // TODO: Need to decide the semantics of this function for color spaces. Do we support 387 // conversion from a passed-in color space? For now, specifying nullptr means that this 388 // path will do no conversion, so it will match the behavior of the non-draw path. 389 GrRenderTarget* renderTarget = surface->asRenderTarget(); 390 SkASSERT(renderTarget); 391 sk_sp<GrRenderTargetContext> renderTargetContext( 392 this->makeWrappedRenderTargetContext(sk_ref_sp(renderTarget), nullptr)); 393 if (!renderTargetContext) { 394 return false; 395 } 396 GrPaint paint; 397 paint.addColorFragmentProcessor(std::move(fp)); 398 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 399 paint.setAllowSRGBInputs(true); 400 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); 401 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect, 402 nullptr); 403 404 if (kFlushWrites_PixelOp & pixelOpsFlags) { 405 this->flushSurfaceWrites(renderTargetContext->asRenderTargetProxy()); 406 } 407 } 408 } 409 if (!tempProxy) { 410 if (applyPremulToSrc) { 411 size_t tmpRowBytes = 4 * width; 412 tmpPixels.reset(width * height); 413 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes, 414 tmpPixels.get())) { 415 return false; 416 } 417 rowBytes = tmpRowBytes; 418 buffer = tmpPixels.get(); 419 applyPremulToSrc = false; 420 } 421 return fContext->fGpu->writePixels(surface, left, top, width, height, srcConfig, 422 buffer, rowBytes); 423 } 424 return true; 425} 426 427bool GrContextPriv::readSurfacePixels(GrSurfaceProxy* srcProxy, SkColorSpace* srcColorSpace, 428 int left, int top, int width, int height, 429 GrPixelConfig dstConfig, SkColorSpace* dstColorSpace, 430 void* buffer, size_t rowBytes, uint32_t flags) { 431 // TODO: Color space conversion 432 433 ASSERT_SINGLE_OWNER_PRIV 434 RETURN_FALSE_IF_ABANDONED_PRIV 435 ASSERT_OWNED_PROXY_PRIV(srcProxy); 436 SkASSERT(srcProxy); 437 GR_AUDIT_TRAIL_AUTO_FRAME(&fContext->fAuditTrail, "GrContextPriv::readSurfacePixels"); 438 439 // MDB TODO: delay this instantiation until later in the method 440 GrSurface* src = srcProxy->instantiate(fContext->resourceProvider()); 441 if (!src) { 442 return false; 443 } 444 445 fContext->testPMConversionsIfNecessary(flags); 446 447 // Adjust the params so that if we wind up using an intermediate surface we've already done 448 // all the trimming and the temporary can be the min size required. 449 if (!GrSurfacePriv::AdjustReadPixelParams(src->width(), src->height(), 450 GrBytesPerPixel(dstConfig), &left, 451 &top, &width, &height, &buffer, &rowBytes)) { 452 return false; 453 } 454 455 if (!(kDontFlush_PixelOpsFlag & flags) && src->surfacePriv().hasPendingWrite()) { 456 this->flush(nullptr); // MDB TODO: tighten this 457 } 458 459 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags); 460 if (unpremul && !valid_unpremul_config(dstConfig)) { 461 // The unpremul flag is only allowed for 8888 and F16 configs. 462 return false; 463 } 464 // We don't allow conversion between integer configs and float/fixed configs. 465 if (GrPixelConfigIsSint(src->config()) != GrPixelConfigIsSint(dstConfig)) { 466 return false; 467 } 468 469 GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference; 470 // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when 471 // we've already determined that there isn't a roundtrip preserving conversion processor pair. 472 if (unpremul && fContext->validPMUPMConversionExists(src->config())) { 473 drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference; 474 } 475 476 GrGpu::ReadPixelTempDrawInfo tempDrawInfo; 477 if (!fContext->fGpu->getReadPixelsInfo(src, width, height, rowBytes, dstConfig, 478 &drawPreference, &tempDrawInfo)) { 479 return false; 480 } 481 482 sk_sp<GrSurfaceProxy> proxyToRead = sk_ref_sp(srcProxy); 483 bool didTempDraw = false; 484 if (GrGpu::kNoDraw_DrawPreference != drawPreference) { 485 if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) { 486 // We only respect this when the entire src is being read. Otherwise we can trigger too 487 // many odd ball texture sizes and trash the cache. 488 if (width != src->width() || height != src->height()) { 489 tempDrawInfo.fTempSurfaceFit= SkBackingFit::kApprox; 490 } 491 } 492 // TODO: Need to decide the semantics of this function for color spaces. Do we support 493 // conversion to a passed-in color space? For now, specifying nullptr means that this 494 // path will do no conversion, so it will match the behavior of the non-draw path. 495 sk_sp<GrRenderTargetContext> tempRTC = fContext->makeRenderTargetContext( 496 tempDrawInfo.fTempSurfaceFit, 497 tempDrawInfo.fTempSurfaceDesc.fWidth, 498 tempDrawInfo.fTempSurfaceDesc.fHeight, 499 tempDrawInfo.fTempSurfaceDesc.fConfig, 500 nullptr, 501 tempDrawInfo.fTempSurfaceDesc.fSampleCnt, 502 tempDrawInfo.fTempSurfaceDesc.fOrigin); 503 if (tempRTC) { 504 SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top)); 505 sk_sp<GrTextureProxy> proxy = sk_ref_sp(srcProxy->asTextureProxy()); 506 sk_sp<GrFragmentProcessor> fp; 507 if (unpremul) { 508 fp = fContext->createPMToUPMEffect(proxy, textureMatrix); 509 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle); 510 if (fp) { 511 unpremul = false; // we no longer need to do this on CPU after the read back. 512 } else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) { 513 // We only wanted to do the draw in order to perform the unpremul so don't 514 // bother. 515 tempRTC.reset(nullptr); 516 } 517 } 518 if (!fp && tempRTC) { 519 fp = GrSimpleTextureEffect::Make(fContext->resourceProvider(), std::move(proxy), 520 nullptr, textureMatrix); 521 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle); 522 } 523 if (fp) { 524 GrPaint paint; 525 paint.addColorFragmentProcessor(std::move(fp)); 526 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 527 paint.setAllowSRGBInputs(true); 528 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); 529 tempRTC->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect, 530 nullptr); 531 proxyToRead = tempRTC->asTextureProxyRef(); 532 left = 0; 533 top = 0; 534 didTempDraw = true; 535 } 536 } 537 } 538 539 if (!proxyToRead) { 540 return false; 541 } 542 543 GrSurface* surfaceToRead = proxyToRead->instantiate(fContext->resourceProvider()); 544 if (!surfaceToRead) { 545 return false; 546 } 547 548 if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) { 549 return false; 550 } 551 GrPixelConfig configToRead = dstConfig; 552 if (didTempDraw) { 553 this->flushSurfaceWrites(proxyToRead.get()); 554 configToRead = tempDrawInfo.fReadConfig; 555 } 556 if (!fContext->fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead, 557 buffer, rowBytes)) { 558 return false; 559 } 560 561 // Perform umpremul conversion if we weren't able to perform it as a draw. 562 if (unpremul) { 563 SkColorType colorType; 564 if (!GrPixelConfigToColorType(dstConfig, &colorType) || 565 4 != SkColorTypeBytesPerPixel(colorType)) 566 { 567 return false; 568 } 569 570 for (int y = 0; y < height; y++) { 571 SkUnpremultiplyRow<false>((uint32_t*) buffer, (const uint32_t*) buffer, width); 572 buffer = SkTAddOffset<void>(buffer, rowBytes); 573 } 574 } 575 return true; 576} 577 578void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) { 579 ASSERT_SINGLE_OWNER_PRIV 580 RETURN_IF_ABANDONED_PRIV 581 SkASSERT(proxy); 582 ASSERT_OWNED_PROXY_PRIV(proxy); 583 fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy); 584} 585 586void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) { 587 ASSERT_SINGLE_OWNER_PRIV 588 RETURN_IF_ABANDONED_PRIV 589 SkASSERT(proxy); 590 ASSERT_OWNED_PROXY_PRIV(proxy); 591 if (proxy->priv().hasPendingWrite()) { 592 this->flush(proxy); 593 } 594} 595 596void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) { 597 ASSERT_SINGLE_OWNER_PRIV 598 RETURN_IF_ABANDONED_PRIV 599 SkASSERT(proxy); 600 ASSERT_OWNED_PROXY_PRIV(proxy); 601 if (proxy->priv().hasPendingIO()) { 602 this->flush(proxy); 603 } 604} 605 606//////////////////////////////////////////////////////////////////////////////// 607int GrContext::getRecommendedSampleCount(GrPixelConfig config, 608 SkScalar dpi) const { 609 ASSERT_SINGLE_OWNER 610 611 if (!this->caps()->isConfigRenderable(config, true)) { 612 return 0; 613 } 614 int chosenSampleCount = 0; 615 if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) { 616 if (dpi >= 250.0f) { 617 chosenSampleCount = 4; 618 } else { 619 chosenSampleCount = 16; 620 } 621 } 622 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? chosenSampleCount : 0; 623} 624 625sk_sp<GrRenderTargetContext> GrContextPriv::makeWrappedRenderTargetContext( 626 sk_sp<GrRenderTarget> rt, 627 sk_sp<SkColorSpace> colorSpace, 628 const SkSurfaceProps* surfaceProps) { 629 ASSERT_SINGLE_OWNER_PRIV 630 631 sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(rt))); 632 if (!proxy) { 633 return nullptr; 634 } 635 636 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 637 std::move(colorSpace), 638 surfaceProps); 639} 640 641sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy, 642 sk_sp<SkColorSpace> colorSpace) { 643 ASSERT_SINGLE_OWNER_PRIV 644 645 if (proxy->asRenderTargetProxy()) { 646 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 647 std::move(colorSpace), nullptr); 648 } else { 649 SkASSERT(proxy->asTextureProxy()); 650 return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace)); 651 } 652} 653 654sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurface> surface) { 655 ASSERT_SINGLE_OWNER_PRIV 656 657 sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface))); 658 if (!proxy) { 659 return nullptr; 660 } 661 662 return this->makeWrappedSurfaceContext(std::move(proxy), nullptr); 663} 664 665sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc, 666 SkBackingFit fit, 667 SkBudgeted isDstBudgeted) { 668 669 sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeDeferred(fContext->resourceProvider(), 670 dstDesc, fit, isDstBudgeted); 671 if (!proxy) { 672 return nullptr; 673 } 674 675 return this->makeWrappedSurfaceContext(std::move(proxy), nullptr); 676} 677 678sk_sp<GrSurfaceContext> GrContextPriv::makeBackendSurfaceContext(const GrBackendTextureDesc& desc, 679 sk_sp<SkColorSpace> colorSpace) { 680 ASSERT_SINGLE_OWNER_PRIV 681 682 sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTexture(desc)); 683 if (!surface) { 684 return nullptr; 685 } 686 687 sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface))); 688 if (!proxy) { 689 return nullptr; 690 } 691 692 return this->makeWrappedSurfaceContext(std::move(proxy), std::move(colorSpace)); 693} 694 695sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext( 696 const GrBackendTextureDesc& desc, 697 sk_sp<SkColorSpace> colorSpace, 698 const SkSurfaceProps* props) { 699 ASSERT_SINGLE_OWNER_PRIV 700 SkASSERT(desc.fFlags & kRenderTarget_GrBackendTextureFlag); 701 702 sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTexture(desc)); 703 if (!surface) { 704 return nullptr; 705 } 706 707 sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface))); 708 if (!proxy) { 709 return nullptr; 710 } 711 712 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 713 std::move(colorSpace), props); 714} 715 716sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext( 717 const GrBackendRenderTargetDesc& desc, 718 sk_sp<SkColorSpace> colorSpace, 719 const SkSurfaceProps* surfaceProps) { 720 ASSERT_SINGLE_OWNER_PRIV 721 722 sk_sp<GrRenderTarget> rt(fContext->resourceProvider()->wrapBackendRenderTarget(desc)); 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 737sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext( 738 const GrBackendTextureDesc& desc, 739 sk_sp<SkColorSpace> colorSpace, 740 const SkSurfaceProps* surfaceProps) { 741 ASSERT_SINGLE_OWNER_PRIV 742 SkASSERT(desc.fFlags & kRenderTarget_GrBackendTextureFlag); 743 744 sk_sp<GrSurface> surface(fContext->resourceProvider()->wrapBackendTextureAsRenderTarget(desc)); 745 if (!surface) { 746 return nullptr; 747 } 748 749 sk_sp<GrSurfaceProxy> proxy(GrSurfaceProxy::MakeWrapped(std::move(surface))); 750 if (!proxy) { 751 return nullptr; 752 } 753 754 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 755 std::move(colorSpace), 756 surfaceProps); 757} 758 759void GrContextPriv::addPreFlushCallbackObject(sk_sp<GrPreFlushCallbackObject> preFlushCBObject) { 760 fContext->fDrawingManager->addPreFlushCallbackObject(std::move(preFlushCBObject)); 761} 762 763 764static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) { 765 switch (config) { 766 case kAlpha_8_GrPixelConfig: 767 case kRGB_565_GrPixelConfig: 768 case kRGBA_4444_GrPixelConfig: 769 case kBGRA_8888_GrPixelConfig: 770 return kRGBA_8888_GrPixelConfig; 771 case kSBGRA_8888_GrPixelConfig: 772 return kSRGBA_8888_GrPixelConfig; 773 case kAlpha_half_GrPixelConfig: 774 return kRGBA_half_GrPixelConfig; 775 default: 776 return kUnknown_GrPixelConfig; 777 } 778} 779 780sk_sp<GrRenderTargetContext> GrContext::makeRenderTargetContextWithFallback( 781 SkBackingFit fit, 782 int width, int height, 783 GrPixelConfig config, 784 sk_sp<SkColorSpace> colorSpace, 785 int sampleCnt, 786 GrSurfaceOrigin origin, 787 const SkSurfaceProps* surfaceProps, 788 SkBudgeted budgeted) { 789 if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) { 790 config = GrPixelConfigFallback(config); 791 } 792 793 return this->makeRenderTargetContext(fit, width, height, config, std::move(colorSpace), 794 sampleCnt, origin, surfaceProps, budgeted); 795} 796 797sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContextWithFallback( 798 SkBackingFit fit, 799 int width, int height, 800 GrPixelConfig config, 801 sk_sp<SkColorSpace> colorSpace, 802 int sampleCnt, 803 GrSurfaceOrigin origin, 804 const SkSurfaceProps* surfaceProps, 805 SkBudgeted budgeted) { 806 if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) { 807 config = GrPixelConfigFallback(config); 808 } 809 810 return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace), 811 sampleCnt, origin, surfaceProps, budgeted); 812} 813 814sk_sp<GrRenderTargetContext> GrContext::makeRenderTargetContext(SkBackingFit fit, 815 int width, int height, 816 GrPixelConfig config, 817 sk_sp<SkColorSpace> colorSpace, 818 int sampleCnt, 819 GrSurfaceOrigin origin, 820 const SkSurfaceProps* surfaceProps, 821 SkBudgeted budgeted) { 822 if (!this->caps()->isConfigRenderable(config, sampleCnt > 0)) { 823 return nullptr; 824 } 825 826 GrSurfaceDesc desc; 827 desc.fFlags = kRenderTarget_GrSurfaceFlag; 828 desc.fOrigin = origin; 829 desc.fWidth = width; 830 desc.fHeight = height; 831 desc.fConfig = config; 832 desc.fSampleCnt = sampleCnt; 833 834 sk_sp<GrTexture> tex; 835 if (SkBackingFit::kExact == fit) { 836 tex = this->resourceProvider()->createTexture(desc, budgeted); 837 } else { 838 tex.reset(this->resourceProvider()->createApproxTexture(desc, 0)); 839 } 840 if (!tex) { 841 return nullptr; 842 } 843 844 sk_sp<GrRenderTargetContext> renderTargetContext( 845 this->contextPriv().makeWrappedRenderTargetContext(sk_ref_sp(tex->asRenderTarget()), 846 std::move(colorSpace), surfaceProps)); 847 if (!renderTargetContext) { 848 return nullptr; 849 } 850 851 return renderTargetContext; 852} 853 854sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext( 855 SkBackingFit fit, 856 int width, int height, 857 GrPixelConfig config, 858 sk_sp<SkColorSpace> colorSpace, 859 int sampleCnt, 860 GrSurfaceOrigin origin, 861 const SkSurfaceProps* surfaceProps, 862 SkBudgeted budgeted) { 863 GrSurfaceDesc desc; 864 desc.fFlags = kRenderTarget_GrSurfaceFlag; 865 desc.fOrigin = origin; 866 desc.fWidth = width; 867 desc.fHeight = height; 868 desc.fConfig = config; 869 desc.fSampleCnt = sampleCnt; 870 871 sk_sp<GrTextureProxy> rtp = GrSurfaceProxy::MakeDeferred(this->resourceProvider(), 872 desc, fit, budgeted); 873 if (!rtp) { 874 return nullptr; 875 } 876 877 return fDrawingManager->makeRenderTargetContext(std::move(rtp), 878 std::move(colorSpace), 879 surfaceProps); 880} 881 882bool GrContext::abandoned() const { 883 ASSERT_SINGLE_OWNER 884 return fDrawingManager->wasAbandoned(); 885} 886 887namespace { 888void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { 889 GrConfigConversionEffect::PMConversion pmToUPM; 890 GrConfigConversionEffect::PMConversion upmToPM; 891 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM); 892 *pmToUPMValue = pmToUPM; 893 *upmToPMValue = upmToPM; 894} 895} 896 897void GrContext::testPMConversionsIfNecessary(uint32_t flags) { 898 ASSERT_SINGLE_OWNER 899 if (SkToBool(GrContextPriv::kUnpremul_PixelOpsFlag & flags)) { 900 if (!fDidTestPMConversions) { 901 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion); 902 fDidTestPMConversions = true; 903 } 904 } 905} 906 907sk_sp<GrFragmentProcessor> GrContext::createPMToUPMEffect(sk_sp<GrTextureProxy> proxy, 908 const SkMatrix& matrix) { 909 ASSERT_SINGLE_OWNER 910 // We should have already called this->testPMConversionsIfNecessary(). 911 SkASSERT(fDidTestPMConversions); 912 if (kRGBA_half_GrPixelConfig == proxy->config()) { 913 return GrFragmentProcessor::UnpremulOutput( 914 GrSimpleTextureEffect::Make(this->resourceProvider(), std::move(proxy), 915 nullptr, matrix)); 916 } else { 917 GrConfigConversionEffect::PMConversion pmToUPM = 918 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion); 919 if (GrConfigConversionEffect::kPMConversionCnt != pmToUPM) { 920 return GrConfigConversionEffect::Make(this->resourceProvider(), std::move(proxy), 921 pmToUPM, matrix); 922 } else { 923 return nullptr; 924 } 925 } 926} 927 928sk_sp<GrFragmentProcessor> GrContext::createUPMToPMEffect(sk_sp<GrTextureProxy> proxy, 929 const SkMatrix& matrix) { 930 ASSERT_SINGLE_OWNER 931 // We should have already called this->testPMConversionsIfNecessary(). 932 SkASSERT(fDidTestPMConversions); 933 if (kRGBA_half_GrPixelConfig == proxy->config()) { 934 return GrFragmentProcessor::PremulOutput( 935 GrSimpleTextureEffect::Make(this->resourceProvider(), std::move(proxy), 936 nullptr, matrix)); 937 } else { 938 GrConfigConversionEffect::PMConversion upmToPM = 939 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion); 940 if (GrConfigConversionEffect::kPMConversionCnt != upmToPM) { 941 return GrConfigConversionEffect::Make(this->resourceProvider(), std::move(proxy), 942 upmToPM, matrix); 943 } else { 944 return nullptr; 945 } 946 } 947} 948 949bool GrContext::validPMUPMConversionExists(GrPixelConfig config) const { 950 ASSERT_SINGLE_OWNER 951 // We should have already called this->testPMConversionsIfNecessary(). 952 SkASSERT(fDidTestPMConversions); 953 // The PM<->UPM tests fail or succeed together so we only need to check one. 954 // For F16, we always allow PM/UPM conversion on the GPU, even if it doesn't round-trip. 955 return GrConfigConversionEffect::kPMConversionCnt != fPMToUPMConversion || 956 kRGBA_half_GrPixelConfig == config; 957} 958 959////////////////////////////////////////////////////////////////////////////// 960 961void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const { 962 ASSERT_SINGLE_OWNER 963 if (maxTextures) { 964 *maxTextures = fResourceCache->getMaxResourceCount(); 965 } 966 if (maxTextureBytes) { 967 *maxTextureBytes = fResourceCache->getMaxResourceBytes(); 968 } 969} 970 971void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) { 972 ASSERT_SINGLE_OWNER 973 fResourceCache->setLimits(maxTextures, maxTextureBytes); 974} 975 976////////////////////////////////////////////////////////////////////////////// 977 978void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { 979 ASSERT_SINGLE_OWNER 980 fResourceCache->dumpMemoryStatistics(traceMemoryDump); 981} 982