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