GrContext.cpp revision 0551818a01f5cab18a9660b4bb21d9f5890e3130
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 "GrBackendSemaphore.h" 10#include "GrClip.h" 11#include "GrContextOptions.h" 12#include "GrContextPriv.h" 13#include "GrDrawingManager.h" 14#include "GrGpu.h" 15#include "GrProxyProvider.h" 16#include "GrRenderTargetContext.h" 17#include "GrRenderTargetProxy.h" 18#include "GrResourceCache.h" 19#include "GrResourceProvider.h" 20#include "GrSemaphore.h" 21#include "GrSoftwarePathRenderer.h" 22#include "GrSurfaceContext.h" 23#include "GrSurfacePriv.h" 24#include "GrSurfaceProxyPriv.h" 25#include "GrTexture.h" 26#include "GrTextureContext.h" 27#include "GrTracing.h" 28#include "SkConvertPixels.h" 29#include "SkDeferredDisplayList.h" 30#include "SkGr.h" 31#include "SkImageInfoPriv.h" 32#include "SkJSONWriter.h" 33#include "SkMakeUnique.h" 34#include "SkTaskGroup.h" 35#include "SkUnPreMultiplyPriv.h" 36#include "effects/GrConfigConversionEffect.h" 37#include "gl/GrGLGpu.h" 38#include "mock/GrMockGpu.h" 39#include "text/GrTextBlobCache.h" 40#ifdef SK_METAL 41#include "mtl/GrMtlTrampoline.h" 42#endif 43#ifdef SK_VULKAN 44#include "vk/GrVkGpu.h" 45#endif 46 47#define ASSERT_OWNED_PROXY(P) \ 48SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this) 49#define ASSERT_OWNED_PROXY_PRIV(P) \ 50SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == fContext) 51 52#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) 53#define ASSERT_SINGLE_OWNER \ 54 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);) 55#define ASSERT_SINGLE_OWNER_PRIV \ 56 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);) 57#define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; } 58#define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; } 59#define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; } 60#define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; } 61#define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; } 62 63//////////////////////////////////////////////////////////////////////////////// 64 65class SK_API GrDirectContext : public GrContext { 66public: 67 GrDirectContext(GrBackend backend) : INHERITED(backend) { } 68 69protected: 70 71private: 72 typedef GrContext INHERITED; 73}; 74 75class SK_API GrDDLContext : public GrContext { 76public: 77 GrDDLContext(GrContextThreadSafeProxy* proxy) : INHERITED(proxy) {} 78 79protected: 80 // DDL TODO: grab a GrRestrictedAtlasManager from the proxy 81 82private: 83 typedef GrContext INHERITED; 84}; 85 86GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) { 87 GrContextOptions defaultOptions; 88 return Create(backend, backendContext, defaultOptions); 89} 90 91GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext, 92 const GrContextOptions& options) { 93 94 sk_sp<GrContext> context(new GrDirectContext(backend)); 95 96 context->fGpu = GrGpu::Make(backend, backendContext, options, context.get()); 97 if (!context->fGpu) { 98 return nullptr; 99 } 100 101 if (!context->init(options)) { 102 return nullptr; 103 } 104 105 return context.release(); 106} 107 108sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface) { 109 GrContextOptions defaultOptions; 110 return MakeGL(std::move(interface), defaultOptions); 111} 112 113sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> interface, 114 const GrContextOptions& options) { 115 sk_sp<GrContext> context(new GrDirectContext(kOpenGL_GrBackend)); 116 117 context->fGpu = GrGLGpu::Make(std::move(interface), options, context.get()); 118 if (!context->fGpu) { 119 return nullptr; 120 } 121 if (!context->init(options)) { 122 return nullptr; 123 } 124 return context; 125} 126 127sk_sp<GrContext> GrContext::MakeGL(const GrGLInterface* interface) { 128 return MakeGL(sk_ref_sp(interface)); 129} 130 131sk_sp<GrContext> GrContext::MakeGL(const GrGLInterface* interface, 132 const GrContextOptions& options) { 133 return MakeGL(sk_ref_sp(interface), options); 134} 135 136sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions) { 137 GrContextOptions defaultOptions; 138 return MakeMock(mockOptions, defaultOptions); 139} 140 141sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions, 142 const GrContextOptions& options) { 143 sk_sp<GrContext> context(new GrDirectContext(kMock_GrBackend)); 144 145 context->fGpu = GrMockGpu::Make(mockOptions, options, context.get()); 146 if (!context->fGpu) { 147 return nullptr; 148 } 149 if (!context->init(options)) { 150 return nullptr; 151 } 152 return context; 153} 154 155#ifdef SK_VULKAN 156sk_sp<GrContext> GrContext::MakeVulkan(sk_sp<const GrVkBackendContext> backendContext) { 157 GrContextOptions defaultOptions; 158 return MakeVulkan(std::move(backendContext), defaultOptions); 159} 160 161sk_sp<GrContext> GrContext::MakeVulkan(sk_sp<const GrVkBackendContext> backendContext, 162 const GrContextOptions& options) { 163 sk_sp<GrContext> context(new GrDirectContext(kVulkan_GrBackend)); 164 165 context->fGpu = GrVkGpu::Make(std::move(backendContext), options, context.get()); 166 if (!context->fGpu) { 167 return nullptr; 168 } 169 if (!context->init(options)) { 170 return nullptr; 171 } 172 return context; 173} 174#endif 175 176#ifdef SK_METAL 177sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue) { 178 GrContextOptions defaultOptions; 179 return MakeMetal(device, queue, defaultOptions); 180} 181 182sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue, const GrContextOptions& options) { 183 sk_sp<GrContext> context(new GrContext(kMetal_GrBackend)); 184 185 context->fGpu = GrMtlTrampoline::MakeGpu(context.get(), options, device, queue); 186 if (!context->fGpu) { 187 return nullptr; 188 } 189 if (!context->init(options)) { 190 return nullptr; 191 } 192 return context; 193} 194#endif 195 196static int32_t gNextID = 1; 197static int32_t next_id() { 198 int32_t id; 199 do { 200 id = sk_atomic_inc(&gNextID); 201 } while (id == SK_InvalidGenID); 202 return id; 203} 204 205sk_sp<GrContext> GrContextPriv::MakeDDL(GrContextThreadSafeProxy* proxy) { 206 sk_sp<GrContext> context(new GrDDLContext(proxy)); 207 208 // Note: we aren't creating a Gpu here. This causes the resource provider & cache to 209 // also not be created 210 if (!context->init(proxy->fOptions)) { 211 return nullptr; 212 } 213 return context; 214} 215 216GrContext::GrContext(GrBackend backend) 217 : fUniqueID(next_id()) 218 , fBackend(backend) { 219 fResourceCache = nullptr; 220 fResourceProvider = nullptr; 221 fProxyProvider = nullptr; 222 fGlyphCache = nullptr; 223 fFullAtlasManager = nullptr; 224} 225 226GrContext::GrContext(GrContextThreadSafeProxy* proxy) 227 : fCaps(proxy->fCaps) 228 , fUniqueID(proxy->fContextUniqueID) 229 , fBackend(proxy->fBackend) { 230 fResourceCache = nullptr; 231 fResourceProvider = nullptr; 232 fProxyProvider = nullptr; 233 fGlyphCache = nullptr; 234 fFullAtlasManager = nullptr; 235} 236 237bool GrContext::init(const GrContextOptions& options) { 238 ASSERT_SINGLE_OWNER 239 240 if (fGpu) { 241 fCaps = fGpu->refCaps(); 242 fResourceCache = new GrResourceCache(fCaps.get(), fUniqueID); 243 fResourceProvider = new GrResourceProvider(fGpu.get(), fResourceCache, &fSingleOwner, 244 options.fExplicitlyAllocateGPUResources); 245 } 246 247 fProxyProvider = new GrProxyProvider(fResourceProvider, fResourceCache, fCaps, &fSingleOwner); 248 249 if (fResourceCache) { 250 fResourceCache->setProxyProvider(fProxyProvider); 251 } 252 253 // DDL TODO: we need to think through how the task group & persistent cache 254 // get passed on to/shared between all the DDLRecorders created with this context. 255 fThreadSafeProxy.reset(new GrContextThreadSafeProxy(fCaps, this->uniqueID(), fBackend, 256 options)); 257 258 fDisableGpuYUVConversion = options.fDisableGpuYUVConversion; 259 fSharpenMipmappedTextures = options.fSharpenMipmappedTextures; 260 fDidTestPMConversions = false; 261 262 GrPathRendererChain::Options prcOptions; 263 prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching; 264#if GR_TEST_UTILS 265 prcOptions.fGpuPathRenderers = options.fGpuPathRenderers; 266#endif 267 if (options.fDisableDistanceFieldPaths) { 268 prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall; 269 } 270 271 if (!fResourceCache) { 272 // DDL TODO: remove this crippling of the path renderer chain 273 // Disable the small path renderer bc of the proxies in the atlas. They need to be 274 // unified when the opLists are added back to the destination drawing manager. 275 prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall; 276 } 277 278 GrAtlasTextContext::Options atlasTextContextOptions; 279 atlasTextContextOptions.fMaxDistanceFieldFontSize = options.fGlyphsAsPathsFontSize; 280 atlasTextContextOptions.fMinDistanceFieldFontSize = options.fMinDistanceFieldFontSize; 281 atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = false; 282#if SK_SUPPORT_ATLAS_TEXT 283 if (GrContextOptions::Enable::kYes == options.fDistanceFieldGlyphVerticesAlwaysHaveW) { 284 atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = true; 285 } 286#endif 287 288 fDrawingManager.reset(new GrDrawingManager(this, prcOptions, atlasTextContextOptions, 289 &fSingleOwner, options.fSortRenderTargets)); 290 291 GrDrawOpAtlas::AllowMultitexturing allowMultitexturing; 292 if (GrContextOptions::Enable::kNo == options.fAllowMultipleGlyphCacheTextures || 293 // multitexturing supported only if range can represent the index + texcoords fully 294 !(fCaps->shaderCaps()->floatIs32Bits() || fCaps->shaderCaps()->integerSupport())) { 295 allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kNo; 296 } else { 297 allowMultitexturing = GrDrawOpAtlas::AllowMultitexturing::kYes; 298 } 299 300 fGlyphCache = new GrGlyphCache; 301 302 // DDL TODO: in DDL-mode grab a GrRestrictedAtlasManager from the thread-proxy and 303 // do not add an onFlushCB 304 fFullAtlasManager = new GrAtlasManager(fProxyProvider, fGlyphCache, 305 options.fGlyphCacheTextureMaximumBytes, 306 allowMultitexturing); 307 this->contextPriv().addOnFlushCallbackObject(fFullAtlasManager); 308 309 fGlyphCache->setGlyphSizeLimit(fFullAtlasManager->getGlyphSizeLimit()); 310 311 fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, 312 this, this->uniqueID(), SkToBool(fGpu))); 313 314 if (options.fExecutor) { 315 fTaskGroup = skstd::make_unique<SkTaskGroup>(*options.fExecutor); 316 } 317 318 fPersistentCache = options.fPersistentCache; 319 320 return true; 321} 322 323GrContext::~GrContext() { 324 ASSERT_SINGLE_OWNER 325 326 if (fGpu) { 327 this->flush(); 328 } 329 330 if (fDrawingManager) { 331 fDrawingManager->cleanup(); 332 } 333 334 for (int i = 0; i < fCleanUpData.count(); ++i) { 335 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo); 336 } 337 338 delete fResourceProvider; 339 delete fResourceCache; 340 delete fProxyProvider; 341 delete fGlyphCache; 342 delete fFullAtlasManager; 343} 344 345sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() { 346 return fThreadSafeProxy; 347} 348 349SkSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization( 350 size_t cacheMaxResourceBytes, 351 const SkImageInfo& ii, const GrBackendFormat& backendFormat, 352 int sampleCnt, GrSurfaceOrigin origin, 353 const SkSurfaceProps& surfaceProps, 354 bool isMipMapped) { 355 if (!backendFormat.isValid()) { 356 return SkSurfaceCharacterization(); // return an invalid characterization 357 } 358 359 // We're assuming GrFSAAType::kMixedSamples will never be specified via this code path 360 GrFSAAType FSAAType = sampleCnt > 1 ? GrFSAAType::kUnifiedMSAA : GrFSAAType::kNone; 361 362 if (!fCaps->mipMapSupport()) { 363 isMipMapped = false; 364 } 365 366 GrPixelConfig config = kUnknown_GrPixelConfig; 367 if (!fCaps->getConfigFromBackendFormat(backendFormat, ii.colorType(), &config)) { 368 return SkSurfaceCharacterization(); // return an invalid characterization 369 } 370 371 // This surface characterization factory assumes that the resulting characterization is 372 // textureable. 373 if (!fCaps->isConfigTexturable(config)) { 374 return SkSurfaceCharacterization(); // return an invalid characterization 375 } 376 377 return SkSurfaceCharacterization(sk_ref_sp<GrContextThreadSafeProxy>(this), 378 cacheMaxResourceBytes, 379 origin, ii.width(), ii.height(), config, FSAAType, sampleCnt, 380 SkSurfaceCharacterization::Textureable(true), 381 SkSurfaceCharacterization::MipMapped(isMipMapped), 382 ii.refColorSpace(), surfaceProps); 383} 384 385void GrContext::abandonContext() { 386 ASSERT_SINGLE_OWNER 387 388 fProxyProvider->abandon(); 389 fResourceProvider->abandon(); 390 391 // Need to abandon the drawing manager first so all the render targets 392 // will be released/forgotten before they too are abandoned. 393 fDrawingManager->abandon(); 394 395 // abandon first to so destructors 396 // don't try to free the resources in the API. 397 fResourceCache->abandonAll(); 398 399 fGpu->disconnect(GrGpu::DisconnectType::kAbandon); 400 401 fGlyphCache->freeAll(); 402 fFullAtlasManager->freeAll(); 403 fTextBlobCache->freeAll(); 404} 405 406void GrContext::releaseResourcesAndAbandonContext() { 407 ASSERT_SINGLE_OWNER 408 409 fProxyProvider->abandon(); 410 fResourceProvider->abandon(); 411 412 // Need to abandon the drawing manager first so all the render targets 413 // will be released/forgotten before they too are abandoned. 414 fDrawingManager->abandon(); 415 416 // Release all resources in the backend 3D API. 417 fResourceCache->releaseAll(); 418 419 fGpu->disconnect(GrGpu::DisconnectType::kCleanup); 420 421 fGlyphCache->freeAll(); 422 fFullAtlasManager->freeAll(); 423 fTextBlobCache->freeAll(); 424} 425 426void GrContext::resetContext(uint32_t state) { 427 ASSERT_SINGLE_OWNER 428 fGpu->markContextDirty(state); 429} 430 431void GrContext::freeGpuResources() { 432 ASSERT_SINGLE_OWNER 433 434 this->flush(); 435 436 fGlyphCache->freeAll(); 437 fFullAtlasManager->freeAll(); 438 439 fDrawingManager->freeGpuResources(); 440 441 fResourceCache->purgeAllUnlocked(); 442} 443 444void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) { 445 ASSERT_SINGLE_OWNER 446 fResourceCache->purgeAsNeeded(); 447 fResourceCache->purgeResourcesNotUsedSince(GrStdSteadyClock::now() - msNotUsed); 448 449 fTextBlobCache->purgeStaleBlobs(); 450} 451 452void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) { 453 ASSERT_SINGLE_OWNER 454 fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources); 455} 456 457void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const { 458 ASSERT_SINGLE_OWNER 459 460 if (resourceCount) { 461 *resourceCount = fResourceCache->getBudgetedResourceCount(); 462 } 463 if (resourceBytes) { 464 *resourceBytes = fResourceCache->getBudgetedResourceBytes(); 465 } 466} 467 468size_t GrContext::getResourceCachePurgeableBytes() const { 469 ASSERT_SINGLE_OWNER 470 return fResourceCache->getPurgeableBytes(); 471} 472 473//////////////////////////////////////////////////////////////////////////////// 474 475bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const { 476 GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps()); 477 return this->caps()->isConfigTexturable(config); 478} 479 480int GrContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const { 481 GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps()); 482 return this->caps()->maxRenderTargetSampleCount(config); 483} 484 485//////////////////////////////////////////////////////////////////////////////// 486 487void GrContext::TextBlobCacheOverBudgetCB(void* data) { 488 SkASSERT(data); 489 // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on 490 // GrRenderTargetContext to perform a necessary flush. The solution is to move drawText calls 491 // to below the GrContext level, but this is not trivial because they call drawPath on 492 // SkGpuDevice. 493 GrContext* context = reinterpret_cast<GrContext*>(data); 494 context->flush(); 495} 496 497//////////////////////////////////////////////////////////////////////////////// 498 499void GrContext::flush() { 500 ASSERT_SINGLE_OWNER 501 RETURN_IF_ABANDONED 502 503 fDrawingManager->flush(nullptr); 504} 505 506GrSemaphoresSubmitted GrContext::flushAndSignalSemaphores(int numSemaphores, 507 GrBackendSemaphore signalSemaphores[]) { 508 ASSERT_SINGLE_OWNER 509 if (fDrawingManager->wasAbandoned()) { return GrSemaphoresSubmitted::kNo; } 510 511 return fDrawingManager->flush(nullptr, numSemaphores, signalSemaphores); 512} 513 514void GrContextPriv::flush(GrSurfaceProxy* proxy) { 515 ASSERT_SINGLE_OWNER_PRIV 516 RETURN_IF_ABANDONED_PRIV 517 ASSERT_OWNED_PROXY_PRIV(proxy); 518 519 fContext->fDrawingManager->flush(proxy); 520} 521 522bool sw_convert_to_premul(GrColorType srcColorType, int width, int height, size_t inRowBytes, 523 const void* inPixels, size_t outRowBytes, void* outPixels) { 524 SkColorType colorType = GrColorTypeToSkColorType(srcColorType); 525 if (kUnknown_SkColorType == colorType || 4 != SkColorTypeBytesPerPixel(colorType)) { 526 return false; 527 } 528 529 for (int y = 0; y < height; y++) { 530 SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width); 531 outPixels = SkTAddOffset<void>(outPixels, outRowBytes); 532 inPixels = SkTAddOffset<const void>(inPixels, inRowBytes); 533 } 534 535 return true; 536} 537 538// TODO: This will be removed when GrSurfaceContexts are aware of their color types. 539// (skbug.com/6718) 540static bool valid_premul_config(GrPixelConfig config) { 541 switch (config) { 542 case kUnknown_GrPixelConfig: return false; 543 case kAlpha_8_GrPixelConfig: return false; 544 case kGray_8_GrPixelConfig: return false; 545 case kRGB_565_GrPixelConfig: return false; 546 case kRGBA_4444_GrPixelConfig: return true; 547 case kRGBA_8888_GrPixelConfig: return true; 548 case kBGRA_8888_GrPixelConfig: return true; 549 case kSRGBA_8888_GrPixelConfig: return true; 550 case kSBGRA_8888_GrPixelConfig: return true; 551 case kRGBA_float_GrPixelConfig: return true; 552 case kRG_float_GrPixelConfig: return false; 553 case kAlpha_half_GrPixelConfig: return false; 554 case kRGBA_half_GrPixelConfig: return true; 555 case kAlpha_8_as_Alpha_GrPixelConfig: return false; 556 case kAlpha_8_as_Red_GrPixelConfig: return false; 557 case kAlpha_half_as_Red_GrPixelConfig: return false; 558 case kGray_8_as_Lum_GrPixelConfig: return false; 559 case kGray_8_as_Red_GrPixelConfig: return false; 560 } 561 SK_ABORT("Invalid GrPixelConfig"); 562 return false; 563} 564 565static bool valid_premul_color_type(GrColorType ct) { 566 switch (ct) { 567 case GrColorType::kUnknown: return false; 568 case GrColorType::kAlpha_8: return false; 569 case GrColorType::kRGB_565: return false; 570 case GrColorType::kABGR_4444: return true; 571 case GrColorType::kRGBA_8888: return true; 572 case GrColorType::kBGRA_8888: return true; 573 case GrColorType::kGray_8: return false; 574 case GrColorType::kAlpha_F16: return false; 575 case GrColorType::kRGBA_F16: return true; 576 case GrColorType::kRG_F32: return false; 577 case GrColorType::kRGBA_F32: return true; 578 } 579 SK_ABORT("Invalid GrColorType"); 580 return false; 581} 582 583static bool valid_pixel_conversion(GrColorType cpuColorType, GrPixelConfig gpuConfig, 584 bool premulConversion) { 585 // We only allow premul <-> unpremul conversions for some formats 586 if (premulConversion && 587 (!valid_premul_color_type(cpuColorType) || !valid_premul_config(gpuConfig))) { 588 return false; 589 } 590 591 return true; 592} 593 594static bool pm_upm_must_round_trip(GrColorType cpuColorType, const SkColorSpace* cpuColorSpace) { 595 return !cpuColorSpace && 596 (GrColorType::kRGBA_8888 == cpuColorType || GrColorType::kBGRA_8888 == cpuColorType); 597} 598 599// TODO: This will be removed when GrSurfaceContexts are aware of their color types. 600// (skbug.com/6718) 601static bool pm_upm_must_round_trip(GrPixelConfig surfaceConfig, 602 const SkColorSpace* surfaceColorSpace) { 603 return !surfaceColorSpace && 604 (kRGBA_8888_GrPixelConfig == surfaceConfig || kBGRA_8888_GrPixelConfig == surfaceConfig); 605} 606 607static GrSRGBConversion determine_write_pixels_srgb_conversion(GrColorType srcColorType, 608 const SkColorSpace* srcColorSpace, 609 GrSRGBEncoded dstSRGBEncoded, 610 const SkColorSpace* dstColorSpace, 611 const GrCaps& caps) { 612 // No support for sRGB-encoded alpha. 613 if (GrColorTypeIsAlphaOnly(srcColorType)) { 614 return GrSRGBConversion::kNone; 615 } 616 // No conversions without GPU support for sRGB. (Legacy mode) 617 if (!caps.srgbSupport()) { 618 return GrSRGBConversion::kNone; 619 } 620 // If the GrSurfaceContext has no color space then it is in legacy mode. 621 if (!dstColorSpace) { 622 return GrSRGBConversion::kNone; 623 } 624 625 bool srcColorSpaceIsSRGB = srcColorSpace && srcColorSpace->gammaCloseToSRGB(); 626 bool dstColorSpaceIsSRGB = dstColorSpace->gammaCloseToSRGB(); 627 628 // For now we are assuming that if color space of the dst does not have sRGB gamma then the 629 // texture format is not sRGB encoded and vice versa. Note that we already checked for "legacy" 630 // mode being forced on by caps above. This may change in the future. We will then have to 631 // perform shader based conversions. 632 SkASSERT(dstColorSpaceIsSRGB == (GrSRGBEncoded::kYes == dstSRGBEncoded)); 633 634 if (srcColorSpaceIsSRGB == dstColorSpaceIsSRGB) { 635 return GrSRGBConversion::kNone; 636 } 637 return srcColorSpaceIsSRGB ? GrSRGBConversion::kSRGBToLinear : GrSRGBConversion::kLinearToSRGB; 638} 639 640static GrSRGBConversion determine_read_pixels_srgb_conversion(GrSRGBEncoded srcSRGBEncoded, 641 const SkColorSpace* srcColorSpace, 642 GrColorType dstColorType, 643 const SkColorSpace* dstColorSpace, 644 const GrCaps& caps) { 645 // This is symmetrical with the write version. 646 switch (determine_write_pixels_srgb_conversion(dstColorType, dstColorSpace, srcSRGBEncoded, 647 srcColorSpace, caps)) { 648 case GrSRGBConversion::kNone: return GrSRGBConversion::kNone; 649 case GrSRGBConversion::kLinearToSRGB: return GrSRGBConversion::kSRGBToLinear; 650 case GrSRGBConversion::kSRGBToLinear: return GrSRGBConversion::kLinearToSRGB; 651 } 652 return GrSRGBConversion::kNone; 653} 654 655bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst, int left, int top, int width, 656 int height, GrColorType srcColorType, 657 SkColorSpace* srcColorSpace, const void* buffer, 658 size_t rowBytes, uint32_t pixelOpsFlags) { 659#ifndef SK_LEGACY_GPU_PIXEL_OPS 660 return this->writeSurfacePixels2(dst, left, top, width, height, srcColorType, srcColorSpace, 661 buffer, rowBytes, pixelOpsFlags); 662#endif 663 664 // TODO: Color space conversion 665 666 ASSERT_SINGLE_OWNER_PRIV 667 RETURN_FALSE_IF_ABANDONED_PRIV 668 SkASSERT(dst); 669 ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy()); 670 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext); 671 672 if (!dst->asSurfaceProxy()->instantiate(this->resourceProvider())) { 673 return false; 674 } 675 676 GrSurfaceProxy* dstProxy = dst->asSurfaceProxy(); 677 GrSurface* dstSurface = dstProxy->priv().peekSurface(); 678 679 // The src is unpremul but the dst is premul -> premul the src before or as part of the write 680 const bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags); 681 682 if (!valid_pixel_conversion(srcColorType, dstProxy->config(), premul)) { 683 return false; 684 } 685 686 // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data, 687 // without any color spaces attached, and the caller wants us to premul. 688 bool useConfigConversionEffect = 689 premul && pm_upm_must_round_trip(srcColorType, srcColorSpace) && 690 pm_upm_must_round_trip(dstProxy->config(), dst->colorSpaceInfo().colorSpace()); 691 692 // Are we going to try to premul as part of a draw? For the non-legacy case, we always allow 693 // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly. 694 bool premulOnGpu = premul && 695 (!useConfigConversionEffect || fContext->validPMUPMConversionExists()); 696 697 // Trim the params here so that if we wind up making a temporary surface it can be as small as 698 // necessary and because GrGpu::getWritePixelsInfo requires it. 699 if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(), 700 GrColorTypeBytesPerPixel(srcColorType), &left, &top, 701 &width, &height, &buffer, &rowBytes)) { 702 return false; 703 } 704 705 GrGpu::DrawPreference drawPreference = premulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference 706 : GrGpu::kNoDraw_DrawPreference; 707 GrGpu::WritePixelTempDrawInfo tempDrawInfo; 708 GrSRGBConversion srgbConversion = determine_write_pixels_srgb_conversion( 709 srcColorType, srcColorSpace, GrPixelConfigIsSRGBEncoded(dstProxy->config()), 710 dst->colorSpaceInfo().colorSpace(), *fContext->caps()); 711 if (!fContext->fGpu->getWritePixelsInfo(dstSurface, dstProxy->origin(), width, height, 712 srcColorType, srgbConversion, &drawPreference, 713 &tempDrawInfo)) { 714 return false; 715 } 716 717 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) { 718 this->flush(nullptr); // MDB TODO: tighten this 719 } 720 721 sk_sp<GrTextureProxy> tempProxy; 722 if (GrGpu::kNoDraw_DrawPreference != drawPreference) { 723 tempProxy = this->proxyProvider()->createProxy(tempDrawInfo.fTempSurfaceDesc, 724 SkBackingFit::kApprox, 725 SkBudgeted::kYes); 726 if (!tempProxy && GrGpu::kRequireDraw_DrawPreference == drawPreference) { 727 return false; 728 } 729 } 730 731 // temp buffer for doing sw premul conversion, if needed. 732 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0); 733 // We need to do sw premul if we were unable to create a RT for drawing, or if we can't do the 734 // premul on the GPU 735 if (premul && (!tempProxy || !premulOnGpu)) { 736 size_t tmpRowBytes = 4 * width; 737 tmpPixels.reset(width * height); 738 if (!sw_convert_to_premul(srcColorType, width, height, rowBytes, buffer, tmpRowBytes, 739 tmpPixels.get())) { 740 return false; 741 } 742 rowBytes = tmpRowBytes; 743 buffer = tmpPixels.get(); 744 } 745 746 if (tempProxy) { 747 auto fp = GrSimpleTextureEffect::Make(tempProxy, SkMatrix::I()); 748 if (premulOnGpu) { 749 fp = fContext->createUPMToPMEffect(std::move(fp), useConfigConversionEffect); 750 } 751 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle); 752 if (!fp) { 753 return false; 754 } 755 756 if (!tempProxy->instantiate(this->resourceProvider())) { 757 return false; 758 } 759 GrTexture* texture = tempProxy->priv().peekTexture(); 760 761 if (tempProxy->priv().hasPendingIO()) { 762 this->flush(tempProxy.get()); 763 } 764 765 if (!fContext->fGpu->writePixels(texture, tempProxy->origin(), 0, 0, width, height, 766 tempDrawInfo.fWriteColorType, buffer, rowBytes)) { 767 return false; 768 } 769 tempProxy = nullptr; 770 771 SkMatrix matrix; 772 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top)); 773 GrRenderTargetContext* renderTargetContext = dst->asRenderTargetContext(); 774 if (!renderTargetContext) { 775 return false; 776 } 777 GrPaint paint; 778 paint.addColorFragmentProcessor(std::move(fp)); 779 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 780 paint.setAllowSRGBInputs(dst->colorSpaceInfo().isGammaCorrect() || 781 GrPixelConfigIsSRGB(dst->colorSpaceInfo().config())); 782 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); 783 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect, 784 nullptr); 785 786 if (kFlushWrites_PixelOp & pixelOpsFlags) { 787 this->flushSurfaceWrites(renderTargetContext->asRenderTargetProxy()); 788 } 789 } else { 790 return fContext->fGpu->writePixels(dstSurface, dstProxy->origin(), left, top, width, height, 791 srcColorType, buffer, rowBytes); 792 } 793 return true; 794} 795 796bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src, int left, int top, int width, 797 int height, GrColorType dstColorType, 798 SkColorSpace* dstColorSpace, void* buffer, size_t rowBytes, 799 uint32_t flags) { 800 // TODO: Color space conversion 801 802 ASSERT_SINGLE_OWNER_PRIV 803 RETURN_FALSE_IF_ABANDONED_PRIV 804 SkASSERT(src); 805 ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy()); 806 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext); 807 808 // MDB TODO: delay this instantiation until later in the method 809 if (!src->asSurfaceProxy()->instantiate(this->resourceProvider())) { 810 return false; 811 } 812 813 GrSurfaceProxy* srcProxy = src->asSurfaceProxy(); 814 GrSurface* srcSurface = srcProxy->priv().peekSurface(); 815 816 // The src is premul but the dst is unpremul -> unpremul the src after or as part of the read 817 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags); 818 819 if (!valid_pixel_conversion(dstColorType, srcProxy->config(), unpremul)) { 820 return false; 821 } 822 823 // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data, 824 // without any color spaces attached, and the caller wants us to unpremul. 825 bool useConfigConversionEffect = 826 unpremul && 827 pm_upm_must_round_trip(srcProxy->config(), src->colorSpaceInfo().colorSpace()) && 828 pm_upm_must_round_trip(dstColorType, dstColorSpace); 829 830 // Are we going to try to unpremul as part of a draw? For the non-legacy case, we always allow 831 // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly. 832 bool unpremulOnGpu = unpremul && 833 (!useConfigConversionEffect || fContext->validPMUPMConversionExists()); 834 835 // Adjust the params so that if we wind up using an intermediate surface we've already done 836 // all the trimming and the temporary can be the min size required. 837 if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(), 838 GrColorTypeBytesPerPixel(dstColorType), &left, &top, 839 &width, &height, &buffer, &rowBytes)) { 840 return false; 841 } 842 843 GrGpu::DrawPreference drawPreference = unpremulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference 844 : GrGpu::kNoDraw_DrawPreference; 845 GrGpu::ReadPixelTempDrawInfo tempDrawInfo; 846 GrSRGBConversion srgbConversion = determine_read_pixels_srgb_conversion( 847 GrPixelConfigIsSRGBEncoded(srcProxy->config()), src->colorSpaceInfo().colorSpace(), 848 dstColorType, dstColorSpace, *fContext->caps()); 849 850 if (!fContext->fGpu->getReadPixelsInfo(srcSurface, srcProxy->origin(), width, height, rowBytes, 851 dstColorType, srgbConversion, &drawPreference, 852 &tempDrawInfo)) { 853 return false; 854 } 855 856 if (!(kDontFlush_PixelOpsFlag & flags) && srcSurface->surfacePriv().hasPendingWrite()) { 857 this->flush(nullptr); // MDB TODO: tighten this 858 } 859 860 sk_sp<GrSurfaceProxy> proxyToRead = src->asSurfaceProxyRef(); 861 bool didTempDraw = false; 862 if (GrGpu::kNoDraw_DrawPreference != drawPreference) { 863 if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) { 864 // We only respect this when the entire src is being read. Otherwise we can trigger too 865 // many odd ball texture sizes and trash the cache. 866 if (width != srcSurface->width() || height != srcSurface->height()) { 867 tempDrawInfo.fTempSurfaceFit= SkBackingFit::kApprox; 868 } 869 } 870 // TODO: Need to decide the semantics of this function for color spaces. Do we support 871 // conversion to a passed-in color space? For now, specifying nullptr means that this 872 // path will do no conversion, so it will match the behavior of the non-draw path. For 873 // now we simply infer an sRGB color space if the config is sRGB in order to avoid an 874 // illegal combination. 875 sk_sp<SkColorSpace> colorSpace; 876 if (GrPixelConfigIsSRGB(tempDrawInfo.fTempSurfaceDesc.fConfig)) { 877 colorSpace = SkColorSpace::MakeSRGB(); 878 } 879 sk_sp<GrRenderTargetContext> tempRTC = 880 fContext->makeDeferredRenderTargetContext(tempDrawInfo.fTempSurfaceFit, 881 tempDrawInfo.fTempSurfaceDesc.fWidth, 882 tempDrawInfo.fTempSurfaceDesc.fHeight, 883 tempDrawInfo.fTempSurfaceDesc.fConfig, 884 std::move(colorSpace), 885 tempDrawInfo.fTempSurfaceDesc.fSampleCnt, 886 GrMipMapped::kNo, 887 tempDrawInfo.fTempSurfaceDesc.fOrigin); 888 if (tempRTC) { 889 // Adding discard to appease vulkan validation warning about loading uninitialized data 890 // on draw 891 tempRTC->discard(); 892 SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top)); 893 sk_sp<GrTextureProxy> proxy = src->asTextureProxyRef(); 894 auto fp = GrSimpleTextureEffect::Make(std::move(proxy), textureMatrix); 895 if (unpremulOnGpu) { 896 fp = fContext->createPMToUPMEffect(std::move(fp), useConfigConversionEffect); 897 // We no longer need to do this on CPU after the read back. 898 unpremul = false; 899 } 900 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle); 901 if (!fp) { 902 return false; 903 } 904 905 GrPaint paint; 906 paint.addColorFragmentProcessor(std::move(fp)); 907 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 908 paint.setAllowSRGBInputs(true); 909 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); 910 tempRTC->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect, 911 nullptr); 912 proxyToRead = tempRTC->asTextureProxyRef(); 913 left = 0; 914 top = 0; 915 didTempDraw = true; 916 } 917 } 918 919 if (!proxyToRead) { 920 return false; 921 } 922 923 if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) { 924 return false; 925 } 926 GrColorType colorTypeToRead = dstColorType; 927 if (didTempDraw) { 928 this->flushSurfaceWrites(proxyToRead.get()); 929 colorTypeToRead = tempDrawInfo.fReadColorType; 930 } 931 932 if (!proxyToRead->instantiate(this->resourceProvider())) { 933 return false; 934 } 935 936 GrSurface* surfaceToRead = proxyToRead->priv().peekSurface(); 937 938 if (!fContext->fGpu->readPixels(surfaceToRead, proxyToRead->origin(), left, top, width, height, 939 colorTypeToRead, buffer, rowBytes)) { 940 return false; 941 } 942 943 // Perform umpremul conversion if we weren't able to perform it as a draw. 944 if (unpremul) { 945 SkColorType colorType = GrColorTypeToSkColorType(dstColorType); 946 if (kUnknown_SkColorType == colorType || 4 != SkColorTypeBytesPerPixel(colorType)) { 947 return false; 948 } 949 950 for (int y = 0; y < height; y++) { 951 SkUnpremultiplyRow<false>((uint32_t*) buffer, (const uint32_t*) buffer, width); 952 buffer = SkTAddOffset<void>(buffer, rowBytes); 953 } 954 } 955 return true; 956} 957 958bool GrContextPriv::writeSurfacePixels2(GrSurfaceContext* dst, int left, int top, int width, 959 int height, GrColorType srcColorType, 960 SkColorSpace* srcColorSpace, const void* buffer, 961 size_t rowBytes, uint32_t pixelOpsFlags) { 962 ASSERT_SINGLE_OWNER_PRIV 963 RETURN_FALSE_IF_ABANDONED_PRIV 964 SkASSERT(dst); 965 SkASSERT(buffer); 966 ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy()); 967 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels2", fContext); 968 969 if (GrColorType::kUnknown == srcColorType) { 970 return false; 971 } 972 973 if (!dst->asSurfaceProxy()->instantiate(this->resourceProvider())) { 974 return false; 975 } 976 977 GrSurfaceProxy* dstProxy = dst->asSurfaceProxy(); 978 GrSurface* dstSurface = dstProxy->priv().peekSurface(); 979 980 if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(), 981 GrColorTypeBytesPerPixel(srcColorType), &left, &top, 982 &width, &height, &buffer, &rowBytes)) { 983 return false; 984 } 985 986 if (!fContext->caps()->surfaceSupportsWritePixels(dstSurface)) { 987 GrSurfaceDesc desc; 988 desc.fConfig = dstProxy->config(); 989 desc.fWidth = width; 990 desc.fHeight = height; 991 desc.fSampleCnt = 1; 992 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 993 auto tempProxy = 994 this->proxyProvider()->createProxy(desc, SkBackingFit::kApprox, SkBudgeted::kYes); 995 if (!tempProxy) { 996 return false; 997 } 998 auto tempCtx = this->drawingManager()->makeTextureContext( 999 tempProxy, dst->colorSpaceInfo().refColorSpace()); 1000 if (!tempCtx) { 1001 return false; 1002 } 1003 if (!this->writeSurfacePixels2(tempCtx.get(), 0, 0, width, height, srcColorType, 1004 srcColorSpace, buffer, rowBytes, pixelOpsFlags)) { 1005 return false; 1006 } 1007 return dst->copy(tempProxy.get(), SkIRect::MakeWH(width, height), {left, top}); 1008 } 1009 1010 // TODO: Make GrSurfaceContext know its alpha type and pass src buffer's alpha type. 1011 bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags); 1012 bool convert = premul; 1013 1014 if (!valid_pixel_conversion(srcColorType, dstProxy->config(), premul)) { 1015 return false; 1016 } 1017 1018 GrColorType allowedColorType = 1019 fContext->caps()->supportedWritePixelsColorType(dstProxy->config(), srcColorType); 1020 convert = convert || (srcColorType != allowedColorType); 1021 1022 if (!dst->colorSpaceInfo().colorSpace()) { 1023 // "Legacy" mode - no color space conversions. 1024 srcColorSpace = nullptr; 1025 } 1026 convert = convert || !SkColorSpace::Equals(srcColorSpace, dst->colorSpaceInfo().colorSpace()); 1027 1028 std::unique_ptr<char[]> tempBuffer; 1029 if (convert) { 1030 auto srcSkColorType = GrColorTypeToSkColorType(srcColorType); 1031 auto dstSkColorType = GrColorTypeToSkColorType(allowedColorType); 1032 if (kUnknown_SkColorType == srcSkColorType || kUnknown_SkColorType == dstSkColorType) { 1033 return false; 1034 } 1035 auto srcAlphaType = premul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType; 1036 SkPixmap src(SkImageInfo::Make(width, height, srcSkColorType, srcAlphaType, 1037 sk_ref_sp(srcColorSpace)), 1038 buffer, rowBytes); 1039 auto tempSrcII = SkImageInfo::Make(width, height, dstSkColorType, kPremul_SkAlphaType, 1040 dst->colorSpaceInfo().refColorSpace()); 1041 auto size = tempSrcII.computeMinByteSize(); 1042 if (!size) { 1043 return false; 1044 } 1045 tempBuffer.reset(new char[size]); 1046 SkPixmap tempSrc(tempSrcII, tempBuffer.get(), tempSrcII.minRowBytes()); 1047 if (!src.readPixels(tempSrc)) { 1048 return false; 1049 } 1050 srcColorType = allowedColorType; 1051 buffer = tempSrc.addr(); 1052 rowBytes = tempSrc.rowBytes(); 1053 if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) { 1054 std::unique_ptr<char[]> row(new char[rowBytes]); 1055 for (int y = 0; y < height / 2; ++y) { 1056 memcpy(row.get(), tempSrc.addr(0, y), rowBytes); 1057 memcpy(tempSrc.writable_addr(0, y), tempSrc.addr(0, height - 1 - y), rowBytes); 1058 memcpy(tempSrc.writable_addr(0, height - 1 - y), row.get(), rowBytes); 1059 } 1060 top = dstProxy->height() - top - height; 1061 } 1062 } else if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) { 1063 size_t trimRowBytes = GrColorTypeBytesPerPixel(srcColorType) * width; 1064 tempBuffer.reset(new char[trimRowBytes * height]); 1065 char* dst = reinterpret_cast<char*>(tempBuffer.get()) + trimRowBytes * (height - 1); 1066 const char* src = reinterpret_cast<const char*>(buffer); 1067 for (int i = 0; i < height; ++i, src += rowBytes, dst -= trimRowBytes) { 1068 memcpy(dst, src, trimRowBytes); 1069 } 1070 buffer = tempBuffer.get(); 1071 rowBytes = trimRowBytes; 1072 top = dstProxy->height() - top - height; 1073 } 1074 1075 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) { 1076 this->flush(nullptr); // MDB TODO: tighten this 1077 } 1078 1079 return this->getGpu()->writePixels(dstSurface, left, top, width, height, srcColorType, buffer, 1080 rowBytes); 1081} 1082 1083void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) { 1084 ASSERT_SINGLE_OWNER_PRIV 1085 RETURN_IF_ABANDONED_PRIV 1086 SkASSERT(proxy); 1087 ASSERT_OWNED_PROXY_PRIV(proxy); 1088 fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy, 0, nullptr); 1089} 1090 1091void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) { 1092 ASSERT_SINGLE_OWNER_PRIV 1093 RETURN_IF_ABANDONED_PRIV 1094 SkASSERT(proxy); 1095 ASSERT_OWNED_PROXY_PRIV(proxy); 1096 if (proxy->priv().hasPendingWrite()) { 1097 this->flush(proxy); 1098 } 1099} 1100 1101void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) { 1102 ASSERT_SINGLE_OWNER_PRIV 1103 RETURN_IF_ABANDONED_PRIV 1104 SkASSERT(proxy); 1105 ASSERT_OWNED_PROXY_PRIV(proxy); 1106 if (proxy->priv().hasPendingIO()) { 1107 this->flush(proxy); 1108 } 1109} 1110 1111//////////////////////////////////////////////////////////////////////////////// 1112 1113sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy, 1114 sk_sp<SkColorSpace> colorSpace, 1115 const SkSurfaceProps* props) { 1116 ASSERT_SINGLE_OWNER_PRIV 1117 1118 // sRGB pixel configs may only be used with near-sRGB gamma color spaces. 1119 if (GrPixelConfigIsSRGB(proxy->config())) { 1120 if (!colorSpace || !colorSpace->gammaCloseToSRGB()) { 1121 return nullptr; 1122 } 1123 } 1124 if (proxy->asRenderTargetProxy()) { 1125 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 1126 std::move(colorSpace), props); 1127 } else { 1128 SkASSERT(proxy->asTextureProxy()); 1129 SkASSERT(!props); 1130 return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace)); 1131 } 1132} 1133 1134sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc, 1135 GrMipMapped mipMapped, 1136 SkBackingFit fit, 1137 SkBudgeted isDstBudgeted, 1138 sk_sp<SkColorSpace> colorSpace, 1139 const SkSurfaceProps* props) { 1140 sk_sp<GrTextureProxy> proxy; 1141 if (GrMipMapped::kNo == mipMapped) { 1142 proxy = this->proxyProvider()->createProxy(dstDesc, fit, isDstBudgeted); 1143 } else { 1144 SkASSERT(SkBackingFit::kExact == fit); 1145 proxy = this->proxyProvider()->createMipMapProxy(dstDesc, isDstBudgeted); 1146 } 1147 if (!proxy) { 1148 return nullptr; 1149 } 1150 1151 return this->makeWrappedSurfaceContext(std::move(proxy), std::move(colorSpace), props); 1152} 1153 1154sk_sp<GrTextureContext> GrContextPriv::makeBackendTextureContext(const GrBackendTexture& tex, 1155 GrSurfaceOrigin origin, 1156 sk_sp<SkColorSpace> colorSpace) { 1157 ASSERT_SINGLE_OWNER_PRIV 1158 1159 sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->createWrappedTextureProxy(tex, origin); 1160 if (!proxy) { 1161 return nullptr; 1162 } 1163 1164 return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace)); 1165} 1166 1167sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext( 1168 const GrBackendTexture& tex, 1169 GrSurfaceOrigin origin, 1170 int sampleCnt, 1171 sk_sp<SkColorSpace> colorSpace, 1172 const SkSurfaceProps* props) { 1173 ASSERT_SINGLE_OWNER_PRIV 1174 SkASSERT(sampleCnt > 0); 1175 1176 sk_sp<GrTextureProxy> proxy(this->proxyProvider()->createWrappedTextureProxy(tex, origin, 1177 sampleCnt)); 1178 if (!proxy) { 1179 return nullptr; 1180 } 1181 1182 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 1183 std::move(colorSpace), props); 1184} 1185 1186sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext( 1187 const GrBackendRenderTarget& backendRT, 1188 GrSurfaceOrigin origin, 1189 sk_sp<SkColorSpace> colorSpace, 1190 const SkSurfaceProps* surfaceProps) { 1191 ASSERT_SINGLE_OWNER_PRIV 1192 1193 sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->createWrappedRenderTargetProxy(backendRT, 1194 origin); 1195 if (!proxy) { 1196 return nullptr; 1197 } 1198 1199 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 1200 std::move(colorSpace), 1201 surfaceProps); 1202} 1203 1204sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext( 1205 const GrBackendTexture& tex, 1206 GrSurfaceOrigin origin, 1207 int sampleCnt, 1208 sk_sp<SkColorSpace> colorSpace, 1209 const SkSurfaceProps* props) { 1210 ASSERT_SINGLE_OWNER_PRIV 1211 SkASSERT(sampleCnt > 0); 1212 sk_sp<GrSurfaceProxy> proxy(this->proxyProvider()->createWrappedRenderTargetProxy(tex, origin, 1213 sampleCnt)); 1214 if (!proxy) { 1215 return nullptr; 1216 } 1217 1218 return this->drawingManager()->makeRenderTargetContext(std::move(proxy), 1219 std::move(colorSpace), 1220 props); 1221} 1222 1223void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) { 1224 fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject); 1225} 1226 1227void GrContextPriv::moveOpListsToDDL(SkDeferredDisplayList* ddl) { 1228 fContext->fDrawingManager->moveOpListsToDDL(ddl); 1229} 1230 1231void GrContextPriv::copyOpListsFromDDL(const SkDeferredDisplayList* ddl, 1232 GrRenderTargetProxy* newDest) { 1233 fContext->fDrawingManager->copyOpListsFromDDL(ddl, newDest); 1234} 1235 1236static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) { 1237 switch (config) { 1238 case kAlpha_8_GrPixelConfig: 1239 case kRGB_565_GrPixelConfig: 1240 case kRGBA_4444_GrPixelConfig: 1241 case kBGRA_8888_GrPixelConfig: 1242 return kRGBA_8888_GrPixelConfig; 1243 case kSBGRA_8888_GrPixelConfig: 1244 return kSRGBA_8888_GrPixelConfig; 1245 case kAlpha_half_GrPixelConfig: 1246 return kRGBA_half_GrPixelConfig; 1247 default: 1248 return kUnknown_GrPixelConfig; 1249 } 1250} 1251 1252sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContextWithFallback( 1253 SkBackingFit fit, 1254 int width, int height, 1255 GrPixelConfig config, 1256 sk_sp<SkColorSpace> colorSpace, 1257 int sampleCnt, 1258 GrMipMapped mipMapped, 1259 GrSurfaceOrigin origin, 1260 const SkSurfaceProps* surfaceProps, 1261 SkBudgeted budgeted) { 1262 SkASSERT(sampleCnt > 0); 1263 if (0 == this->caps()->getRenderTargetSampleCount(sampleCnt, config)) { 1264 config = GrPixelConfigFallback(config); 1265 } 1266 1267 return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace), 1268 sampleCnt, mipMapped, origin, surfaceProps, 1269 budgeted); 1270} 1271 1272sk_sp<GrRenderTargetContext> GrContext::makeDeferredRenderTargetContext( 1273 SkBackingFit fit, 1274 int width, int height, 1275 GrPixelConfig config, 1276 sk_sp<SkColorSpace> colorSpace, 1277 int sampleCnt, 1278 GrMipMapped mipMapped, 1279 GrSurfaceOrigin origin, 1280 const SkSurfaceProps* surfaceProps, 1281 SkBudgeted budgeted) { 1282 SkASSERT(sampleCnt > 0); 1283 if (this->abandoned()) { 1284 return nullptr; 1285 } 1286 1287 GrSurfaceDesc desc; 1288 desc.fFlags = kRenderTarget_GrSurfaceFlag; 1289 desc.fOrigin = origin; 1290 desc.fWidth = width; 1291 desc.fHeight = height; 1292 desc.fConfig = config; 1293 desc.fSampleCnt = sampleCnt; 1294 1295 sk_sp<GrTextureProxy> rtp; 1296 if (GrMipMapped::kNo == mipMapped) { 1297 rtp = fProxyProvider->createProxy(desc, fit, budgeted); 1298 } else { 1299 rtp = fProxyProvider->createMipMapProxy(desc, budgeted); 1300 } 1301 if (!rtp) { 1302 return nullptr; 1303 } 1304 1305 sk_sp<GrRenderTargetContext> renderTargetContext( 1306 fDrawingManager->makeRenderTargetContext(std::move(rtp), 1307 std::move(colorSpace), 1308 surfaceProps)); 1309 if (!renderTargetContext) { 1310 return nullptr; 1311 } 1312 1313 renderTargetContext->discard(); 1314 1315 return renderTargetContext; 1316} 1317 1318bool GrContext::abandoned() const { 1319 ASSERT_SINGLE_OWNER 1320 return fDrawingManager->wasAbandoned(); 1321} 1322 1323std::unique_ptr<GrFragmentProcessor> GrContext::createPMToUPMEffect( 1324 std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) { 1325 ASSERT_SINGLE_OWNER 1326 // We have specialized effects that guarantee round-trip conversion for some formats 1327 if (useConfigConversionEffect) { 1328 // We should have already called this->validPMUPMConversionExists() in this case 1329 SkASSERT(fDidTestPMConversions); 1330 // ...and it should have succeeded 1331 SkASSERT(this->validPMUPMConversionExists()); 1332 1333 return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToUnpremul); 1334 } else { 1335 // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and 1336 // explicitly round the results. Just do the obvious, naive thing in the shader. 1337 return GrFragmentProcessor::UnpremulOutput(std::move(fp)); 1338 } 1339} 1340 1341std::unique_ptr<GrFragmentProcessor> GrContext::createUPMToPMEffect( 1342 std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) { 1343 ASSERT_SINGLE_OWNER 1344 // We have specialized effects that guarantee round-trip conversion for these formats 1345 if (useConfigConversionEffect) { 1346 // We should have already called this->validPMUPMConversionExists() in this case 1347 SkASSERT(fDidTestPMConversions); 1348 // ...and it should have succeeded 1349 SkASSERT(this->validPMUPMConversionExists()); 1350 1351 return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToPremul); 1352 } else { 1353 // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and 1354 // explicitly round the results. Just do the obvious, naive thing in the shader. 1355 return GrFragmentProcessor::PremulOutput(std::move(fp)); 1356 } 1357} 1358 1359bool GrContext::validPMUPMConversionExists() { 1360 ASSERT_SINGLE_OWNER 1361 if (!fDidTestPMConversions) { 1362 fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this); 1363 fDidTestPMConversions = true; 1364 } 1365 1366 // The PM<->UPM tests fail or succeed together so we only need to check one. 1367 return fPMUPMConversionsRoundTrip; 1368} 1369 1370////////////////////////////////////////////////////////////////////////////// 1371 1372// DDL TODO: remove 'maxResources' 1373void GrContext::getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const { 1374 ASSERT_SINGLE_OWNER 1375 if (maxResources) { 1376 *maxResources = fResourceCache->getMaxResourceCount(); 1377 } 1378 if (maxResourceBytes) { 1379 *maxResourceBytes = fResourceCache->getMaxResourceBytes(); 1380 } 1381} 1382 1383void GrContext::setResourceCacheLimits(int maxResources, size_t maxResourceBytes) { 1384 ASSERT_SINGLE_OWNER 1385 fResourceCache->setLimits(maxResources, maxResourceBytes); 1386} 1387 1388////////////////////////////////////////////////////////////////////////////// 1389 1390void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const { 1391 ASSERT_SINGLE_OWNER 1392 fResourceCache->dumpMemoryStatistics(traceMemoryDump); 1393} 1394 1395////////////////////////////////////////////////////////////////////////////// 1396 1397SkString GrContext::dump() const { 1398 SkDynamicMemoryWStream stream; 1399 SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty); 1400 writer.beginObject(); 1401 1402 static const char* kBackendStr[] = { 1403 "Metal", 1404 "OpenGL", 1405 "Vulkan", 1406 "Mock", 1407 }; 1408 GR_STATIC_ASSERT(0 == kMetal_GrBackend); 1409 GR_STATIC_ASSERT(1 == kOpenGL_GrBackend); 1410 GR_STATIC_ASSERT(2 == kVulkan_GrBackend); 1411 GR_STATIC_ASSERT(3 == kMock_GrBackend); 1412 writer.appendString("backend", kBackendStr[fBackend]); 1413 1414 writer.appendName("caps"); 1415 fCaps->dumpJSON(&writer); 1416 1417 writer.appendName("gpu"); 1418 fGpu->dumpJSON(&writer); 1419 1420 // Flush JSON to the memory stream 1421 writer.endObject(); 1422 writer.flush(); 1423 1424 // Null terminate the JSON data in the memory stream 1425 stream.write8(0); 1426 1427 // Allocate a string big enough to hold all the data, then copy out of the stream 1428 SkString result(stream.bytesWritten()); 1429 stream.copyToAndReset(result.writable_str()); 1430 return result; 1431} 1432