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