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