GrContext.cpp revision b8fea97a7a493897fcff33aa2932d875c572f163
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 "GrContextOptions.h" 10#include "GrDrawingManager.h" 11#include "GrDrawContext.h" 12#include "GrLayerCache.h" 13#include "GrResourceCache.h" 14#include "GrResourceProvider.h" 15#include "GrSoftwarePathRenderer.h" 16#include "GrSurfacePriv.h" 17 18#include "SkConfig8888.h" 19#include "SkGrPriv.h" 20 21#include "batches/GrCopySurfaceBatch.h" 22#include "effects/GrConfigConversionEffect.h" 23#include "text/GrTextBlobCache.h" 24 25#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) 26#define ASSERT_SINGLE_OWNER \ 27 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);) 28#define RETURN_IF_ABANDONED if (fDrawingManager->abandoned()) { return; } 29#define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->abandoned()) { return false; } 30#define RETURN_NULL_IF_ABANDONED if (fDrawingManager->abandoned()) { return nullptr; } 31 32//////////////////////////////////////////////////////////////////////////////// 33 34GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) { 35 GrContextOptions defaultOptions; 36 return Create(backend, backendContext, defaultOptions); 37} 38 39GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, 40 const GrContextOptions& options) { 41 GrContext* context = new GrContext; 42 43 if (context->init(backend, backendContext, options)) { 44 return context; 45 } else { 46 context->unref(); 47 return nullptr; 48 } 49} 50 51static int32_t gNextID = 1; 52static int32_t next_id() { 53 int32_t id; 54 do { 55 id = sk_atomic_inc(&gNextID); 56 } while (id == SK_InvalidGenID); 57 return id; 58} 59 60GrContext::GrContext() : fUniqueID(next_id()) { 61 fGpu = nullptr; 62 fCaps = nullptr; 63 fResourceCache = nullptr; 64 fResourceProvider = nullptr; 65 fBatchFontCache = nullptr; 66 fFlushToReduceCacheSize = false; 67} 68 69bool GrContext::init(GrBackend backend, GrBackendContext backendContext, 70 const GrContextOptions& options) { 71 ASSERT_SINGLE_OWNER 72 SkASSERT(!fGpu); 73 74 fGpu = GrGpu::Create(backend, backendContext, options, this); 75 if (!fGpu) { 76 return false; 77 } 78 this->initCommon(options); 79 return true; 80} 81 82void GrContext::initCommon(const GrContextOptions& options) { 83 ASSERT_SINGLE_OWNER 84 85 fCaps = SkRef(fGpu->caps()); 86 fResourceCache = new GrResourceCache(fCaps); 87 fResourceCache->setOverBudgetCallback(OverBudgetCB, this); 88 fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner); 89 90 fLayerCache.reset(new GrLayerCache(this)); 91 92 fDidTestPMConversions = false; 93 94 GrDrawTarget::Options dtOptions; 95 dtOptions.fClipBatchToBounds = options.fClipBatchToBounds; 96 dtOptions.fDrawBatchBounds = options.fDrawBatchBounds; 97 dtOptions.fMaxBatchLookback = options.fMaxBatchLookback; 98 fDrawingManager.reset(new GrDrawingManager(this, dtOptions, &fSingleOwner)); 99 100 // GrBatchFontCache will eventually replace GrFontCache 101 fBatchFontCache = new GrBatchFontCache(this); 102 103 fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this)); 104} 105 106GrContext::~GrContext() { 107 ASSERT_SINGLE_OWNER 108 109 if (!fGpu) { 110 SkASSERT(!fCaps); 111 return; 112 } 113 114 this->flush(); 115 116 fDrawingManager->cleanup(); 117 118 for (int i = 0; i < fCleanUpData.count(); ++i) { 119 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); 120 } 121 122 delete fResourceProvider; 123 delete fResourceCache; 124 delete fBatchFontCache; 125 126 fGpu->unref(); 127 fCaps->unref(); 128} 129 130void GrContext::abandonContext() { 131 ASSERT_SINGLE_OWNER 132 133 fResourceProvider->abandon(); 134 135 // Need to abandon the drawing manager first so all the render targets 136 // will be released/forgotten before they too are abandoned. 137 fDrawingManager->abandon(); 138 139 // abandon first to so destructors 140 // don't try to free the resources in the API. 141 fResourceCache->abandonAll(); 142 143 fGpu->contextAbandoned(); 144 145 fBatchFontCache->freeAll(); 146 fLayerCache->freeAll(); 147 fTextBlobCache->freeAll(); 148} 149 150void GrContext::resetContext(uint32_t state) { 151 ASSERT_SINGLE_OWNER 152 fGpu->markContextDirty(state); 153} 154 155void GrContext::freeGpuResources() { 156 ASSERT_SINGLE_OWNER 157 158 this->flush(); 159 160 fBatchFontCache->freeAll(); 161 fLayerCache->freeAll(); 162 163 fDrawingManager->freeGpuResources(); 164 165 fResourceCache->purgeAllUnlocked(); 166} 167 168void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const { 169 ASSERT_SINGLE_OWNER 170 171 if (resourceCount) { 172 *resourceCount = fResourceCache->getBudgetedResourceCount(); 173 } 174 if (resourceBytes) { 175 *resourceBytes = fResourceCache->getBudgetedResourceBytes(); 176 } 177} 178 179//////////////////////////////////////////////////////////////////////////////// 180 181void GrContext::OverBudgetCB(void* data) { 182 SkASSERT(data); 183 184 GrContext* context = reinterpret_cast<GrContext*>(data); 185 186 // Flush the GrBufferedDrawTarget to possibly free up some textures 187 context->fFlushToReduceCacheSize = true; 188} 189 190void GrContext::TextBlobCacheOverBudgetCB(void* data) { 191 SkASSERT(data); 192 193 // Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level, therefore they 194 // cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush. The solution is to move 195 // drawText calls to below the GrContext level, but this is not trivial because they call 196 // drawPath on SkGpuDevice 197 GrContext* context = reinterpret_cast<GrContext*>(data); 198 context->flush(); 199} 200 201//////////////////////////////////////////////////////////////////////////////// 202 203void GrContext::flush(int flagsBitfield) { 204 ASSERT_SINGLE_OWNER 205 RETURN_IF_ABANDONED 206 207 if (kDiscard_FlushBit & flagsBitfield) { 208 fDrawingManager->reset(); 209 } else { 210 fDrawingManager->flush(); 211 } 212 fResourceCache->notifyFlushOccurred(); 213 fFlushToReduceCacheSize = false; 214} 215 216bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes, 217 const void* inPixels, size_t outRowBytes, void* outPixels) { 218 SkSrcPixelInfo srcPI; 219 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, nullptr)) { 220 return false; 221 } 222 srcPI.fAlphaType = kUnpremul_SkAlphaType; 223 srcPI.fPixels = inPixels; 224 srcPI.fRowBytes = inRowBytes; 225 226 SkDstPixelInfo dstPI; 227 dstPI.fColorType = srcPI.fColorType; 228 dstPI.fAlphaType = kPremul_SkAlphaType; 229 dstPI.fPixels = outPixels; 230 dstPI.fRowBytes = outRowBytes; 231 232 return srcPI.convertPixelsTo(&dstPI, width, height); 233} 234 235bool GrContext::writeSurfacePixels(GrSurface* surface, 236 int left, int top, int width, int height, 237 GrPixelConfig srcConfig, const void* buffer, size_t rowBytes, 238 uint32_t pixelOpsFlags) { 239 ASSERT_SINGLE_OWNER 240 RETURN_FALSE_IF_ABANDONED 241 ASSERT_OWNED_RESOURCE(surface); 242 SkASSERT(surface); 243 GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::writeSurfacePixels"); 244 245 this->testPMConversionsIfNecessary(pixelOpsFlags); 246 247 // Trim the params here so that if we wind up making a temporary surface it can be as small as 248 // necessary and because GrGpu::getWritePixelsInfo requires it. 249 if (!GrSurfacePriv::AdjustWritePixelParams(surface->width(), surface->height(), 250 GrBytesPerPixel(srcConfig), &left, &top, &width, 251 &height, &buffer, &rowBytes)) { 252 return false; 253 } 254 255 bool applyPremulToSrc = false; 256 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) { 257 if (!GrPixelConfigIs8888(srcConfig)) { 258 return false; 259 } 260 applyPremulToSrc = true; 261 } 262 263 GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference; 264 // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when 265 // we've already determined that there isn't a roundtrip preserving conversion processor pair. 266 if (applyPremulToSrc && !this->didFailPMUPMConversionTest()) { 267 drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference; 268 } 269 270 GrGpu::WritePixelTempDrawInfo tempDrawInfo; 271 if (!fGpu->getWritePixelsInfo(surface, width, height, rowBytes, srcConfig, &drawPreference, 272 &tempDrawInfo)) { 273 return false; 274 } 275 276 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && surface->surfacePriv().hasPendingIO()) { 277 this->flush(); 278 } 279 280 SkAutoTUnref<GrTexture> tempTexture; 281 if (GrGpu::kNoDraw_DrawPreference != drawPreference) { 282 tempTexture.reset( 283 this->textureProvider()->createApproxTexture(tempDrawInfo.fTempSurfaceDesc)); 284 if (!tempTexture && GrGpu::kRequireDraw_DrawPreference == drawPreference) { 285 return false; 286 } 287 } 288 289 // temp buffer for doing sw premul conversion, if needed. 290 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); 291 if (tempTexture) { 292 SkAutoTUnref<const GrFragmentProcessor> fp; 293 SkMatrix textureMatrix; 294 textureMatrix.setIDiv(tempTexture->width(), tempTexture->height()); 295 if (applyPremulToSrc) { 296 fp.reset(this->createUPMToPMEffect(tempTexture, tempDrawInfo.fSwizzle, 297 textureMatrix)); 298 // If premultiplying was the only reason for the draw, fall back to a straight write. 299 if (!fp) { 300 if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) { 301 tempTexture.reset(nullptr); 302 } 303 } else { 304 applyPremulToSrc = false; 305 } 306 } 307 if (tempTexture) { 308 if (!fp) { 309 fp.reset(GrConfigConversionEffect::Create(tempTexture, tempDrawInfo.fSwizzle, 310 GrConfigConversionEffect::kNone_PMConversion, textureMatrix)); 311 if (!fp) { 312 return false; 313 } 314 } 315 GrRenderTarget* renderTarget = surface->asRenderTarget(); 316 SkASSERT(renderTarget); 317 if (tempTexture->surfacePriv().hasPendingIO()) { 318 this->flush(); 319 } 320 if (applyPremulToSrc) { 321 size_t tmpRowBytes = 4 * width; 322 tmpPixels.reset(width * height); 323 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes, 324 tmpPixels.get())) { 325 return false; 326 } 327 rowBytes = tmpRowBytes; 328 buffer = tmpPixels.get(); 329 applyPremulToSrc = false; 330 } 331 if (!fGpu->writePixels(tempTexture, 0, 0, width, height, 332 tempDrawInfo.fWriteConfig, buffer, 333 rowBytes)) { 334 return false; 335 } 336 SkMatrix matrix; 337 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); 338 SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(renderTarget)); 339 if (!drawContext) { 340 return false; 341 } 342 GrPaint paint; 343 paint.addColorFragmentProcessor(fp); 344 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); 345 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); 346 drawContext->drawRect(GrClip::WideOpen(), paint, matrix, rect, nullptr); 347 348 if (kFlushWrites_PixelOp & pixelOpsFlags) { 349 this->flushSurfaceWrites(surface); 350 } 351 } 352 } 353 if (!tempTexture) { 354 if (applyPremulToSrc) { 355 size_t tmpRowBytes = 4 * width; 356 tmpPixels.reset(width * height); 357 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes, 358 tmpPixels.get())) { 359 return false; 360 } 361 rowBytes = tmpRowBytes; 362 buffer = tmpPixels.get(); 363 applyPremulToSrc = false; 364 } 365 return fGpu->writePixels(surface, left, top, width, height, srcConfig, buffer, rowBytes); 366 } 367 return true; 368} 369 370bool GrContext::readSurfacePixels(GrSurface* src, 371 int left, int top, int width, int height, 372 GrPixelConfig dstConfig, void* buffer, size_t rowBytes, 373 uint32_t flags) { 374 ASSERT_SINGLE_OWNER 375 RETURN_FALSE_IF_ABANDONED 376 ASSERT_OWNED_RESOURCE(src); 377 SkASSERT(src); 378 GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::readSurfacePixels"); 379 380 this->testPMConversionsIfNecessary(flags); 381 SkAutoMutexAcquire ama(fReadPixelsMutex); 382 383 // Adjust the params so that if we wind up using an intermediate surface we've already done 384 // all the trimming and the temporary can be the min size required. 385 if (!GrSurfacePriv::AdjustReadPixelParams(src->width(), src->height(), 386 GrBytesPerPixel(dstConfig), &left, 387 &top, &width, &height, &buffer, &rowBytes)) { 388 return false; 389 } 390 391 if (!(kDontFlush_PixelOpsFlag & flags) && src->surfacePriv().hasPendingWrite()) { 392 this->flush(); 393 } 394 395 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags); 396 if (unpremul && !GrPixelConfigIs8888(dstConfig)) { 397 // The unpremul flag is only allowed for 8888 configs. 398 return false; 399 } 400 401 GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference; 402 // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when 403 // we've already determined that there isn't a roundtrip preserving conversion processor pair. 404 if (unpremul && !this->didFailPMUPMConversionTest()) { 405 drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference; 406 } 407 408 GrGpu::ReadPixelTempDrawInfo tempDrawInfo; 409 if (!fGpu->getReadPixelsInfo(src, width, height, rowBytes, dstConfig, &drawPreference, 410 &tempDrawInfo)) { 411 return false; 412 } 413 414 SkAutoTUnref<GrSurface> surfaceToRead(SkRef(src)); 415 bool didTempDraw = false; 416 if (GrGpu::kNoDraw_DrawPreference != drawPreference) { 417 if (tempDrawInfo.fUseExactScratch) { 418 // We only respect this when the entire src is being read. Otherwise we can trigger too 419 // many odd ball texture sizes and trash the cache. 420 if (width != src->width() || height != src->height()) { 421 tempDrawInfo.fUseExactScratch = false; 422 } 423 } 424 SkAutoTUnref<GrTexture> temp; 425 if (tempDrawInfo.fUseExactScratch) { 426 temp.reset(this->textureProvider()->createTexture(tempDrawInfo.fTempSurfaceDesc, true)); 427 } else { 428 temp.reset(this->textureProvider()->createApproxTexture(tempDrawInfo.fTempSurfaceDesc)); 429 } 430 if (temp) { 431 SkMatrix textureMatrix; 432 textureMatrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); 433 textureMatrix.postIDiv(src->width(), src->height()); 434 SkAutoTUnref<const GrFragmentProcessor> fp; 435 if (unpremul) { 436 fp.reset(this->createPMToUPMEffect(src->asTexture(), tempDrawInfo.fSwizzle, 437 textureMatrix)); 438 if (fp) { 439 unpremul = false; // we no longer need to do this on CPU after the read back. 440 } else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) { 441 // We only wanted to do the draw in order to perform the unpremul so don't 442 // bother. 443 temp.reset(nullptr); 444 } 445 } 446 if (!fp && temp) { 447 fp.reset(GrConfigConversionEffect::Create(src->asTexture(), tempDrawInfo.fSwizzle, 448 GrConfigConversionEffect::kNone_PMConversion, textureMatrix)); 449 } 450 if (fp) { 451 GrPaint paint; 452 paint.addColorFragmentProcessor(fp); 453 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode); 454 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); 455 SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(temp->asRenderTarget())); 456 drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, nullptr); 457 surfaceToRead.reset(SkRef(temp.get())); 458 left = 0; 459 top = 0; 460 didTempDraw = true; 461 } 462 } 463 } 464 465 if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) { 466 return false; 467 } 468 GrPixelConfig configToRead = dstConfig; 469 if (didTempDraw) { 470 this->flushSurfaceWrites(surfaceToRead); 471 configToRead = tempDrawInfo.fReadConfig; 472 } 473 if (!fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead, buffer, 474 rowBytes)) { 475 return false; 476 } 477 478 // Perform umpremul conversion if we weren't able to perform it as a draw. 479 if (unpremul) { 480 SkDstPixelInfo dstPI; 481 if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, nullptr)) { 482 return false; 483 } 484 dstPI.fAlphaType = kUnpremul_SkAlphaType; 485 dstPI.fPixels = buffer; 486 dstPI.fRowBytes = rowBytes; 487 488 SkSrcPixelInfo srcPI; 489 srcPI.fColorType = dstPI.fColorType; 490 srcPI.fAlphaType = kPremul_SkAlphaType; 491 srcPI.fPixels = buffer; 492 srcPI.fRowBytes = rowBytes; 493 494 return srcPI.convertPixelsTo(&dstPI, width, height); 495 } 496 return true; 497} 498 499void GrContext::prepareSurfaceForExternalIO(GrSurface* surface) { 500 ASSERT_SINGLE_OWNER 501 RETURN_IF_ABANDONED 502 SkASSERT(surface); 503 ASSERT_OWNED_RESOURCE(surface); 504 if (surface->surfacePriv().hasPendingIO()) { 505 this->flush(); 506 } 507 GrRenderTarget* rt = surface->asRenderTarget(); 508 if (fGpu && rt) { 509 fGpu->resolveRenderTarget(rt); 510 } 511} 512 513bool GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect, 514 const SkIPoint& dstPoint) { 515 ASSERT_SINGLE_OWNER 516 RETURN_FALSE_IF_ABANDONED 517 GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::copySurface"); 518 519 if (!src || !dst) { 520 return false; 521 } 522 ASSERT_OWNED_RESOURCE(src); 523 ASSERT_OWNED_RESOURCE(dst); 524 525 if (!dst->asRenderTarget()) { 526 SkIRect clippedSrcRect; 527 SkIPoint clippedDstPoint; 528 if (!GrCopySurfaceBatch::ClipSrcRectAndDstPoint(dst, src, srcRect, dstPoint, 529 &clippedSrcRect, &clippedDstPoint)) { 530 return false; 531 } 532 // If we don't have an RT for the dst then we won't have a GrDrawContext to insert the 533 // the copy surface into. In the future we plan to have a more limited Context type 534 // (GrCopyContext?) that has the subset of GrDrawContext operations that should be 535 // allowed on textures that aren't render targets. 536 // For now we just flush any writes to the src and issue an immediate copy to the dst. 537 src->flushWrites(); 538 return fGpu->copySurface(dst, src, clippedSrcRect, clippedDstPoint); 539 } 540 SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(dst->asRenderTarget())); 541 if (!drawContext) { 542 return false; 543 } 544 545 if (!drawContext->copySurface(src, srcRect, dstPoint)) { 546 return false; 547 } 548 return true; 549} 550 551void GrContext::flushSurfaceWrites(GrSurface* surface) { 552 ASSERT_SINGLE_OWNER 553 RETURN_IF_ABANDONED 554 if (surface->surfacePriv().hasPendingWrite()) { 555 this->flush(); 556 } 557} 558 559//////////////////////////////////////////////////////////////////////////////// 560int GrContext::getRecommendedSampleCount(GrPixelConfig config, 561 SkScalar dpi) const { 562 ASSERT_SINGLE_OWNER 563 564 if (!this->caps()->isConfigRenderable(config, true)) { 565 return 0; 566 } 567 int chosenSampleCount = 0; 568 if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) { 569 if (dpi >= 250.0f) { 570 chosenSampleCount = 4; 571 } else { 572 chosenSampleCount = 16; 573 } 574 } 575 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? chosenSampleCount : 0; 576} 577 578 579GrDrawContext* GrContext::drawContext(GrRenderTarget* rt, const SkSurfaceProps* surfaceProps) { 580 ASSERT_SINGLE_OWNER 581 return fDrawingManager->drawContext(rt, surfaceProps); 582} 583 584bool GrContext::abandoned() const { 585 ASSERT_SINGLE_OWNER 586 return fDrawingManager->abandoned(); 587} 588 589namespace { 590void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) { 591 GrConfigConversionEffect::PMConversion pmToUPM; 592 GrConfigConversionEffect::PMConversion upmToPM; 593 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM); 594 *pmToUPMValue = pmToUPM; 595 *upmToPMValue = upmToPM; 596} 597} 598 599void GrContext::testPMConversionsIfNecessary(uint32_t flags) { 600 ASSERT_SINGLE_OWNER 601 if (SkToBool(kUnpremul_PixelOpsFlag & flags)) { 602 SkAutoMutexAcquire ama(fTestPMConversionsMutex); 603 if (!fDidTestPMConversions) { 604 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion); 605 fDidTestPMConversions = true; 606 } 607 } 608} 609 610const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture, 611 const GrSwizzle& swizzle, 612 const SkMatrix& matrix) const { 613 ASSERT_SINGLE_OWNER 614 // We should have already called this->testPMConversionsIfNecessary(). 615 SkASSERT(fDidTestPMConversions); 616 GrConfigConversionEffect::PMConversion pmToUPM = 617 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion); 618 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) { 619 return GrConfigConversionEffect::Create(texture, swizzle, pmToUPM, matrix); 620 } else { 621 return nullptr; 622 } 623} 624 625const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture, 626 const GrSwizzle& swizzle, 627 const SkMatrix& matrix) const { 628 ASSERT_SINGLE_OWNER 629 // We should have already called this->testPMConversionsIfNecessary(). 630 SkASSERT(fDidTestPMConversions); 631 GrConfigConversionEffect::PMConversion upmToPM = 632 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion); 633 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) { 634 return GrConfigConversionEffect::Create(texture, swizzle, upmToPM, matrix); 635 } else { 636 return nullptr; 637 } 638} 639 640bool GrContext::didFailPMUPMConversionTest() const { 641 ASSERT_SINGLE_OWNER 642 // We should have already called this->testPMConversionsIfNecessary(). 643 SkASSERT(fDidTestPMConversions); 644 // The PM<->UPM tests fail or succeed together so we only need to check one. 645 return GrConfigConversionEffect::kNone_PMConversion == fPMToUPMConversion; 646} 647 648////////////////////////////////////////////////////////////////////////////// 649 650void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const { 651 ASSERT_SINGLE_OWNER 652 if (maxTextures) { 653 *maxTextures = fResourceCache->getMaxResourceCount(); 654 } 655 if (maxTextureBytes) { 656 *maxTextureBytes = fResourceCache->getMaxResourceBytes(); 657 } 658} 659 660void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) { 661 ASSERT_SINGLE_OWNER 662 fResourceCache->setLimits(maxTextures, maxTextureBytes); 663} 664 665////////////////////////////////////////////////////////////////////////////// 666 667void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { 668 ASSERT_SINGLE_OWNER 669 fResourceCache->dumpMemoryStatistics(traceMemoryDump); 670} 671