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