blob: 4b624ee820c211379b98981ed015b3ad48a22f70 [file] [log] [blame]
bsalomon@google.com27847de2011-02-22 20:59:41 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * 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.
bsalomon@google.com27847de2011-02-22 20:59:41 +00006 */
7
bsalomon@google.com1fadb202011-12-12 16:10:08 +00008#include "GrContext.h"
Brian Salomon5f33a8c2018-02-26 14:32:39 -05009#include "GrBackendSemaphore.h"
Brian Salomonc65aec92017-03-09 09:03:58 -050010#include "GrClip.h"
bsalomon682c2692015-05-22 14:01:46 -070011#include "GrContextOptions.h"
Brian Salomonc65aec92017-03-09 09:03:58 -050012#include "GrContextPriv.h"
robertphillips77a2e522015-10-17 07:43:27 -070013#include "GrDrawingManager.h"
Robert Phillips646e4292017-06-13 12:44:56 -040014#include "GrGpu.h"
Robert Phillips1afd4cd2018-01-08 13:40:32 -050015#include "GrProxyProvider.h"
Brian Osman11052242016-10-27 14:47:55 -040016#include "GrRenderTargetContext.h"
Brian Salomonc65aec92017-03-09 09:03:58 -050017#include "GrRenderTargetProxy.h"
bsalomon0ea80f42015-02-11 10:49:59 -080018#include "GrResourceCache.h"
bsalomond309e7a2015-04-30 14:18:54 -070019#include "GrResourceProvider.h"
Greg Danield85f97d2017-03-07 13:37:21 -050020#include "GrSemaphore.h"
robertphillips@google.com72176b22012-05-23 13:19:12 +000021#include "GrSoftwarePathRenderer.h"
Brian Osman45580d32016-11-23 09:37:01 -050022#include "GrSurfaceContext.h"
bsalomonafbf2d62014-09-30 12:18:44 -070023#include "GrSurfacePriv.h"
Robert Phillips757914d2017-01-25 15:48:30 -050024#include "GrSurfaceProxyPriv.h"
Robert Phillips646e4292017-06-13 12:44:56 -040025#include "GrTexture.h"
Brian Osman45580d32016-11-23 09:37:01 -050026#include "GrTextureContext.h"
Robert Phillips41a3b872018-03-09 12:00:34 -050027#include "GrTextureStripAtlas.h"
Brian Salomondcbb9d92017-07-19 10:53:20 -040028#include "GrTracing.h"
Matt Sarett485c4992017-02-14 14:18:27 -050029#include "SkConvertPixels.h"
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -050030#include "SkDeferredDisplayList.h"
Brian Osman3b655982017-03-07 16:58:08 -050031#include "SkGr.h"
Mike Reed7fcfb622018-02-09 13:26:46 -050032#include "SkImageInfoPriv.h"
Brian Osman71a18892017-08-10 10:23:25 -040033#include "SkJSONWriter.h"
Brian Osman51279982017-08-23 10:12:00 -040034#include "SkMakeUnique.h"
35#include "SkTaskGroup.h"
Matt Sarettc7b29082017-02-09 16:22:39 -050036#include "SkUnPreMultiplyPriv.h"
joshualitt5478d422014-11-14 16:00:38 -080037#include "effects/GrConfigConversionEffect.h"
Brian Salomon5f33a8c2018-02-26 14:32:39 -050038#include "text/GrTextBlobCache.h"
Greg Danielb76a72a2017-07-13 15:07:54 -040039
Robert Phillipse78b7252017-04-06 07:59:41 -040040#define ASSERT_OWNED_PROXY(P) \
41SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == this)
Robert Phillips7ee385e2017-03-30 08:02:11 -040042#define ASSERT_OWNED_PROXY_PRIV(P) \
43SkASSERT(!(P) || !((P)->priv().peekTexture()) || (P)->priv().peekTexture()->getContext() == fContext)
44
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000045#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
joshualitt1de610a2016-01-06 08:26:09 -080046#define ASSERT_SINGLE_OWNER \
47 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);)
robertphillips4fd74ae2016-08-03 14:26:53 -070048#define ASSERT_SINGLE_OWNER_PRIV \
49 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fContext->fSingleOwner);)
robertphillips7761d612016-05-16 09:14:53 -070050#define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; }
Robert Phillips7ee385e2017-03-30 08:02:11 -040051#define RETURN_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return; }
robertphillips7761d612016-05-16 09:14:53 -070052#define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; }
Robert Phillipse78b7252017-04-06 07:59:41 -040053#define RETURN_FALSE_IF_ABANDONED_PRIV if (fContext->fDrawingManager->wasAbandoned()) { return false; }
robertphillips7761d612016-05-16 09:14:53 -070054#define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; }
bsalomon@google.combc4b6542011-11-19 13:56:11 +000055
robertphillipsea461502015-05-26 11:38:03 -070056////////////////////////////////////////////////////////////////////////////////
57
joshualitt0acd0d32015-05-07 08:23:19 -070058static int32_t gNextID = 1;
59static int32_t next_id() {
60 int32_t id;
61 do {
62 id = sk_atomic_inc(&gNextID);
63 } while (id == SK_InvalidGenID);
64 return id;
65}
66
Robert Phillipsfde6fa02018-03-02 08:53:14 -050067GrContext::GrContext(GrBackend backend, int32_t id)
68 : fBackend(backend)
69 , fUniqueID(SK_InvalidGenID == id ? next_id() : id) {
halcanary96fcdcc2015-08-27 07:41:13 -070070 fResourceCache = nullptr;
71 fResourceProvider = nullptr;
Robert Phillips1afd4cd2018-01-08 13:40:32 -050072 fProxyProvider = nullptr;
Robert Phillipsc4039ea2018-03-01 11:36:45 -050073 fGlyphCache = nullptr;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000074}
75
Robert Phillipsfde6fa02018-03-02 08:53:14 -050076bool GrContext::initCommon(const GrContextOptions& options) {
Greg Danielb76a72a2017-07-13 15:07:54 -040077 ASSERT_SINGLE_OWNER
Robert Phillipsfde6fa02018-03-02 08:53:14 -050078 SkASSERT(fCaps); // needs to have been initialized by derived classes
79 SkASSERT(fThreadSafeProxy); // needs to have been initialized by derived classes
Robert Phillips88260b52018-01-19 12:56:09 -050080
81 if (fGpu) {
82 fCaps = fGpu->refCaps();
83 fResourceCache = new GrResourceCache(fCaps.get(), fUniqueID);
Robert Phillips4150eea2018-02-07 17:08:21 -050084 fResourceProvider = new GrResourceProvider(fGpu.get(), fResourceCache, &fSingleOwner,
85 options.fExplicitlyAllocateGPUResources);
Robert Phillips88260b52018-01-19 12:56:09 -050086 }
87
Robert Phillips1afd4cd2018-01-08 13:40:32 -050088 fProxyProvider = new GrProxyProvider(fResourceProvider, fResourceCache, fCaps, &fSingleOwner);
Robert Phillips88260b52018-01-19 12:56:09 -050089
90 if (fResourceCache) {
91 fResourceCache->setProxyProvider(fProxyProvider);
92 }
Robert Phillips1afd4cd2018-01-08 13:40:32 -050093
Robert Phillips41a3b872018-03-09 12:00:34 -050094 fTextureStripAtlasManager.reset(new GrTextureStripAtlasManager);
95
Brian Osman46da1cc2017-02-14 14:15:48 -050096 fDisableGpuYUVConversion = options.fDisableGpuYUVConversion;
Brian Osman8a83ca42018-02-12 14:32:17 -050097 fSharpenMipmappedTextures = options.fSharpenMipmappedTextures;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000098 fDidTestPMConversions = false;
99
bsalomon6b2552f2016-09-15 13:50:26 -0700100 GrPathRendererChain::Options prcOptions;
bsalomon39ef7fb2016-09-21 11:16:05 -0700101 prcOptions.fAllowPathMaskCaching = options.fAllowPathMaskCaching;
Brian Osman195c05b2017-08-30 15:14:04 -0400102#if GR_TEST_UTILS
csmartdalton008b9d82017-02-22 12:00:42 -0700103 prcOptions.fGpuPathRenderers = options.fGpuPathRenderers;
Brian Osman195c05b2017-08-30 15:14:04 -0400104#endif
Brian Osmanb350ae22017-08-29 16:15:39 -0400105 if (options.fDisableDistanceFieldPaths) {
Brian Osman195c05b2017-08-30 15:14:04 -0400106 prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall;
Brian Osmanb350ae22017-08-29 16:15:39 -0400107 }
Brian Salomonaf597482017-11-07 16:23:34 -0500108
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500109 if (!fResourceCache) {
110 // DDL TODO: remove this crippling of the path renderer chain
111 // Disable the small path renderer bc of the proxies in the atlas. They need to be
112 // unified when the opLists are added back to the destination drawing manager.
113 prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall;
114 }
115
Brian Salomonaf597482017-11-07 16:23:34 -0500116 GrAtlasTextContext::Options atlasTextContextOptions;
117 atlasTextContextOptions.fMaxDistanceFieldFontSize = options.fGlyphsAsPathsFontSize;
118 atlasTextContextOptions.fMinDistanceFieldFontSize = options.fMinDistanceFieldFontSize;
Brian Salomonb5086962017-12-13 10:59:33 -0500119 atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = false;
120#if SK_SUPPORT_ATLAS_TEXT
121 if (GrContextOptions::Enable::kYes == options.fDistanceFieldGlyphVerticesAlwaysHaveW) {
122 atlasTextContextOptions.fDistanceFieldVerticesAlwaysHaveW = true;
123 }
124#endif
Brian Salomonaf597482017-11-07 16:23:34 -0500125
Robert Phillips4150eea2018-02-07 17:08:21 -0500126 fDrawingManager.reset(new GrDrawingManager(this, prcOptions, atlasTextContextOptions,
127 &fSingleOwner, options.fSortRenderTargets));
joshualitt7c3a2f82015-03-31 13:32:05 -0700128
Robert Phillipsaf4adef2018-03-07 11:59:37 -0500129 fGlyphCache = new GrGlyphCache(fCaps.get(), options.fGlyphCacheTextureMaximumBytes);
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500130
Robert Phillips303cd582018-02-14 18:54:01 -0500131 fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB,
132 this, this->uniqueID(), SkToBool(fGpu)));
Brian Salomon91a3e522017-06-23 10:58:19 -0400133
Robert Phillipsfde6fa02018-03-02 08:53:14 -0500134 // DDL TODO: we need to think through how the task group & persistent cache
135 // get passed on to/shared between all the DDLRecorders created with this context.
Brian Osman51279982017-08-23 10:12:00 -0400136 if (options.fExecutor) {
137 fTaskGroup = skstd::make_unique<SkTaskGroup>(*options.fExecutor);
138 }
139
Ethan Nicholasd1b2eec2017-11-01 15:45:43 -0400140 fPersistentCache = options.fPersistentCache;
141
Brian Salomon91a3e522017-06-23 10:58:19 -0400142 return true;
bsalomon@google.comc0af3172012-06-15 14:10:09 +0000143}
144
bsalomon@google.com27847de2011-02-22 20:59:41 +0000145GrContext::~GrContext() {
joshualitt1de610a2016-01-06 08:26:09 -0800146 ASSERT_SINGLE_OWNER
147
Robert Phillips2e6feed2018-01-22 15:27:20 -0500148 if (fDrawingManager) {
149 fDrawingManager->cleanup();
150 }
robertphillips2334fb62015-06-17 05:43:33 -0700151
Robert Phillips41a3b872018-03-09 12:00:34 -0500152 fTextureStripAtlasManager = nullptr;
halcanary385fe4d2015-08-26 13:07:48 -0700153 delete fResourceProvider;
154 delete fResourceCache;
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500155 delete fProxyProvider;
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500156 delete fGlyphCache;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000157}
158
bungeman6bd52842016-10-27 09:30:08 -0700159sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
bungeman6bd52842016-10-27 09:30:08 -0700160 return fThreadSafeProxy;
bsalomon41b952c2016-03-11 06:46:33 -0800161}
162
Robert Phillipsfc711a22018-02-13 17:03:00 -0500163SkSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization(
164 size_t cacheMaxResourceBytes,
165 const SkImageInfo& ii, const GrBackendFormat& backendFormat,
166 int sampleCnt, GrSurfaceOrigin origin,
167 const SkSurfaceProps& surfaceProps,
168 bool isMipMapped) {
169 if (!backendFormat.isValid()) {
170 return SkSurfaceCharacterization(); // return an invalid characterization
171 }
172
173 // We're assuming GrFSAAType::kMixedSamples will never be specified via this code path
174 GrFSAAType FSAAType = sampleCnt > 1 ? GrFSAAType::kUnifiedMSAA : GrFSAAType::kNone;
175
176 if (!fCaps->mipMapSupport()) {
177 isMipMapped = false;
178 }
179
180 GrPixelConfig config = kUnknown_GrPixelConfig;
181 if (!fCaps->getConfigFromBackendFormat(backendFormat, ii.colorType(), &config)) {
182 return SkSurfaceCharacterization(); // return an invalid characterization
183 }
184
185 // This surface characterization factory assumes that the resulting characterization is
186 // textureable.
187 if (!fCaps->isConfigTexturable(config)) {
188 return SkSurfaceCharacterization(); // return an invalid characterization
189 }
190
191 return SkSurfaceCharacterization(sk_ref_sp<GrContextThreadSafeProxy>(this),
192 cacheMaxResourceBytes,
193 origin, ii.width(), ii.height(), config, FSAAType, sampleCnt,
194 SkSurfaceCharacterization::Textureable(true),
195 SkSurfaceCharacterization::MipMapped(isMipMapped),
196 ii.refColorSpace(), surfaceProps);
197}
198
bsalomon2354f842014-07-28 13:48:36 -0700199void GrContext::abandonContext() {
joshualitt1de610a2016-01-06 08:26:09 -0800200 ASSERT_SINGLE_OWNER
201
Robert Phillips41a3b872018-03-09 12:00:34 -0500202 fTextureStripAtlasManager->abandon();
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500203 fProxyProvider->abandon();
bsalomond309e7a2015-04-30 14:18:54 -0700204 fResourceProvider->abandon();
robertphillips0dfa62c2015-11-16 06:23:31 -0800205
206 // Need to abandon the drawing manager first so all the render targets
207 // will be released/forgotten before they too are abandoned.
208 fDrawingManager->abandon();
209
bsalomon@google.com205d4602011-04-25 12:43:45 +0000210 // abandon first to so destructors
211 // don't try to free the resources in the API.
bsalomon0ea80f42015-02-11 10:49:59 -0800212 fResourceCache->abandonAll();
bsalomonc8dc1f72014-08-21 13:02:13 -0700213
bsalomon6e2aad42016-04-01 11:54:31 -0700214 fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
215
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500216 fGlyphCache->freeAll();
bsalomon6e2aad42016-04-01 11:54:31 -0700217 fTextBlobCache->freeAll();
218}
219
220void GrContext::releaseResourcesAndAbandonContext() {
221 ASSERT_SINGLE_OWNER
222
Robert Phillips41a3b872018-03-09 12:00:34 -0500223 fTextureStripAtlasManager->abandon();
Robert Phillips1afd4cd2018-01-08 13:40:32 -0500224 fProxyProvider->abandon();
bsalomon6e2aad42016-04-01 11:54:31 -0700225 fResourceProvider->abandon();
226
227 // Need to abandon the drawing manager first so all the render targets
228 // will be released/forgotten before they too are abandoned.
229 fDrawingManager->abandon();
230
231 // Release all resources in the backend 3D API.
232 fResourceCache->releaseAll();
233
234 fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000235
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500236 fGlyphCache->freeAll();
joshualitt26ffc002015-04-16 11:24:04 -0700237 fTextBlobCache->freeAll();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000238}
239
bsalomon@google.com0a208a12013-06-28 18:57:35 +0000240void GrContext::resetContext(uint32_t state) {
joshualitt1de610a2016-01-06 08:26:09 -0800241 ASSERT_SINGLE_OWNER
bsalomon@google.com0a208a12013-06-28 18:57:35 +0000242 fGpu->markContextDirty(state);
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000243}
244
245void GrContext::freeGpuResources() {
joshualitt1de610a2016-01-06 08:26:09 -0800246 ASSERT_SINGLE_OWNER
247
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500248 fGlyphCache->freeAll();
robertphillips68737822015-10-29 12:12:21 -0700249
250 fDrawingManager->freeGpuResources();
bsalomon3033b9f2015-04-13 11:09:56 -0700251
252 fResourceCache->purgeAllUnlocked();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000253}
254
Jim Van Verth76d917c2017-12-13 09:26:37 -0500255void GrContext::performDeferredCleanup(std::chrono::milliseconds msNotUsed) {
Brian Salomon5e150852017-03-22 14:53:13 -0400256 ASSERT_SINGLE_OWNER
Jim Van Verth76d917c2017-12-13 09:26:37 -0500257 fResourceCache->purgeAsNeeded();
258 fResourceCache->purgeResourcesNotUsedSince(GrStdSteadyClock::now() - msNotUsed);
259
260 fTextBlobCache->purgeStaleBlobs();
Brian Salomon5e150852017-03-22 14:53:13 -0400261}
262
Derek Sollenberger5480a182017-05-25 16:43:59 -0400263void GrContext::purgeUnlockedResources(size_t bytesToPurge, bool preferScratchResources) {
264 ASSERT_SINGLE_OWNER
265 fResourceCache->purgeUnlockedResources(bytesToPurge, preferScratchResources);
266}
267
commit-bot@chromium.org95c20032014-05-09 14:29:32 +0000268void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
joshualitt1de610a2016-01-06 08:26:09 -0800269 ASSERT_SINGLE_OWNER
270
bsalomon71cb0c22014-11-14 12:10:14 -0800271 if (resourceCount) {
bsalomon0ea80f42015-02-11 10:49:59 -0800272 *resourceCount = fResourceCache->getBudgetedResourceCount();
bsalomon71cb0c22014-11-14 12:10:14 -0800273 }
274 if (resourceBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -0800275 *resourceBytes = fResourceCache->getBudgetedResourceBytes();
bsalomon71cb0c22014-11-14 12:10:14 -0800276 }
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000277}
278
Derek Sollenbergeree479142017-05-24 11:41:33 -0400279size_t GrContext::getResourceCachePurgeableBytes() const {
280 ASSERT_SINGLE_OWNER
281 return fResourceCache->getPurgeableBytes();
282}
283
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000284////////////////////////////////////////////////////////////////////////////////
285
Brian Salomonbdecacf2018-02-02 20:32:49 -0500286bool GrContext::colorTypeSupportedAsImage(SkColorType colorType) const {
287 GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps());
288 return this->caps()->isConfigTexturable(config);
289}
290
291int GrContext::maxSurfaceSampleCountForColorType(SkColorType colorType) const {
292 GrPixelConfig config = SkImageInfo2GrPixelConfig(colorType, nullptr, *this->caps());
293 return this->caps()->maxRenderTargetSampleCount(config);
294}
295
296////////////////////////////////////////////////////////////////////////////////
297
joshualitt0db6dfa2015-04-10 07:01:30 -0700298void GrContext::TextBlobCacheOverBudgetCB(void* data) {
299 SkASSERT(data);
Brian Osman11052242016-10-27 14:47:55 -0400300 // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on
301 // GrRenderTargetContext to perform a necessary flush. The solution is to move drawText calls
302 // to below the GrContext level, but this is not trivial because they call drawPath on
303 // SkGpuDevice.
joshualitt0db6dfa2015-04-10 07:01:30 -0700304 GrContext* context = reinterpret_cast<GrContext*>(data);
305 context->flush();
306}
307
bsalomon@google.com27847de2011-02-22 20:59:41 +0000308////////////////////////////////////////////////////////////////////////////////
309
bsalomonb77a9072016-09-07 10:02:04 -0700310void GrContext::flush() {
joshualitt1de610a2016-01-06 08:26:09 -0800311 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700312 RETURN_IF_ABANDONED
Robert Phillips7ee385e2017-03-30 08:02:11 -0400313
314 fDrawingManager->flush(nullptr);
315}
316
Greg Daniel51316782017-08-02 15:10:09 +0000317GrSemaphoresSubmitted GrContext::flushAndSignalSemaphores(int numSemaphores,
318 GrBackendSemaphore signalSemaphores[]) {
319 ASSERT_SINGLE_OWNER
320 if (fDrawingManager->wasAbandoned()) { return GrSemaphoresSubmitted::kNo; }
321
322 return fDrawingManager->flush(nullptr, numSemaphores, signalSemaphores);
323}
324
Robert Phillips7ee385e2017-03-30 08:02:11 -0400325void GrContextPriv::flush(GrSurfaceProxy* proxy) {
326 ASSERT_SINGLE_OWNER_PRIV
327 RETURN_IF_ABANDONED_PRIV
328 ASSERT_OWNED_PROXY_PRIV(proxy);
329
330 fContext->fDrawingManager->flush(proxy);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000331}
332
Brian Salomonc320b152018-02-20 14:05:36 -0500333bool sw_convert_to_premul(GrColorType srcColorType, int width, int height, size_t inRowBytes,
bsalomon81beccc2014-10-13 12:32:55 -0700334 const void* inPixels, size_t outRowBytes, void* outPixels) {
Brian Salomonc320b152018-02-20 14:05:36 -0500335 SkColorType colorType = GrColorTypeToSkColorType(srcColorType);
336 if (kUnknown_SkColorType == colorType || 4 != SkColorTypeBytesPerPixel(colorType)) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000337 return false;
338 }
bsalomon81beccc2014-10-13 12:32:55 -0700339
Matt Sarettc7b29082017-02-09 16:22:39 -0500340 for (int y = 0; y < height; y++) {
341 SkOpts::RGBA_to_rgbA((uint32_t*) outPixels, inPixels, width);
342 outPixels = SkTAddOffset<void>(outPixels, outRowBytes);
343 inPixels = SkTAddOffset<const void>(inPixels, inRowBytes);
344 }
bsalomon81beccc2014-10-13 12:32:55 -0700345
Matt Sarettc7b29082017-02-09 16:22:39 -0500346 return true;
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000347}
348
Brian Salomonc320b152018-02-20 14:05:36 -0500349// TODO: This will be removed when GrSurfaceContexts are aware of their color types.
350// (skbug.com/6718)
Brian Osmand2ca59a2017-04-13 14:03:57 -0400351static bool valid_premul_config(GrPixelConfig config) {
Brian Salomonc320b152018-02-20 14:05:36 -0500352 switch (config) {
353 case kUnknown_GrPixelConfig: return false;
354 case kAlpha_8_GrPixelConfig: return false;
355 case kGray_8_GrPixelConfig: return false;
356 case kRGB_565_GrPixelConfig: return false;
357 case kRGBA_4444_GrPixelConfig: return true;
358 case kRGBA_8888_GrPixelConfig: return true;
359 case kBGRA_8888_GrPixelConfig: return true;
360 case kSRGBA_8888_GrPixelConfig: return true;
361 case kSBGRA_8888_GrPixelConfig: return true;
Brian Osman10fc6fd2018-03-02 11:01:10 -0500362 case kRGBA_1010102_GrPixelConfig: return true;
Brian Salomonc320b152018-02-20 14:05:36 -0500363 case kRGBA_float_GrPixelConfig: return true;
364 case kRG_float_GrPixelConfig: return false;
365 case kAlpha_half_GrPixelConfig: return false;
366 case kRGBA_half_GrPixelConfig: return true;
367 case kAlpha_8_as_Alpha_GrPixelConfig: return false;
368 case kAlpha_8_as_Red_GrPixelConfig: return false;
369 case kAlpha_half_as_Red_GrPixelConfig: return false;
370 case kGray_8_as_Lum_GrPixelConfig: return false;
371 case kGray_8_as_Red_GrPixelConfig: return false;
372 }
373 SK_ABORT("Invalid GrPixelConfig");
374 return false;
Brian Osmance425512017-03-22 14:37:50 -0400375}
376
Brian Salomonc320b152018-02-20 14:05:36 -0500377static bool valid_premul_color_type(GrColorType ct) {
378 switch (ct) {
Brian Osman10fc6fd2018-03-02 11:01:10 -0500379 case GrColorType::kUnknown: return false;
380 case GrColorType::kAlpha_8: return false;
381 case GrColorType::kRGB_565: return false;
382 case GrColorType::kABGR_4444: return true;
383 case GrColorType::kRGBA_8888: return true;
384 case GrColorType::kBGRA_8888: return true;
385 case GrColorType::kRGBA_1010102: return true;
386 case GrColorType::kGray_8: return false;
387 case GrColorType::kAlpha_F16: return false;
388 case GrColorType::kRGBA_F16: return true;
389 case GrColorType::kRG_F32: return false;
390 case GrColorType::kRGBA_F32: return true;
Brian Salomonc320b152018-02-20 14:05:36 -0500391 }
392 SK_ABORT("Invalid GrColorType");
393 return false;
394}
395
396static bool valid_pixel_conversion(GrColorType cpuColorType, GrPixelConfig gpuConfig,
Brian Osmand2ca59a2017-04-13 14:03:57 -0400397 bool premulConversion) {
Brian Osmand2ca59a2017-04-13 14:03:57 -0400398 // We only allow premul <-> unpremul conversions for some formats
Brian Salomonc320b152018-02-20 14:05:36 -0500399 if (premulConversion &&
400 (!valid_premul_color_type(cpuColorType) || !valid_premul_config(gpuConfig))) {
Brian Osmand2ca59a2017-04-13 14:03:57 -0400401 return false;
402 }
403
404 return true;
405}
406
Brian Salomonc320b152018-02-20 14:05:36 -0500407static bool pm_upm_must_round_trip(GrColorType cpuColorType, const SkColorSpace* cpuColorSpace) {
408 return !cpuColorSpace &&
409 (GrColorType::kRGBA_8888 == cpuColorType || GrColorType::kBGRA_8888 == cpuColorType);
Brian Osman409e74f2017-04-17 11:48:28 -0400410}
411
Brian Salomonc320b152018-02-20 14:05:36 -0500412// TODO: This will be removed when GrSurfaceContexts are aware of their color types.
413// (skbug.com/6718)
414static bool pm_upm_must_round_trip(GrPixelConfig surfaceConfig,
415 const SkColorSpace* surfaceColorSpace) {
416 return !surfaceColorSpace &&
417 (kRGBA_8888_GrPixelConfig == surfaceConfig || kBGRA_8888_GrPixelConfig == surfaceConfig);
418}
419
420static GrSRGBConversion determine_write_pixels_srgb_conversion(GrColorType srcColorType,
421 const SkColorSpace* srcColorSpace,
422 GrSRGBEncoded dstSRGBEncoded,
423 const SkColorSpace* dstColorSpace,
424 const GrCaps& caps) {
Brian Salomon9b009bb2018-02-14 13:53:55 -0500425 // No support for sRGB-encoded alpha.
Brian Salomonc320b152018-02-20 14:05:36 -0500426 if (GrColorTypeIsAlphaOnly(srcColorType)) {
Brian Salomon9b009bb2018-02-14 13:53:55 -0500427 return GrSRGBConversion::kNone;
428 }
Brian Salomonc320b152018-02-20 14:05:36 -0500429 // No conversions without GPU support for sRGB. (Legacy mode)
430 if (!caps.srgbSupport()) {
Brian Salomon9b009bb2018-02-14 13:53:55 -0500431 return GrSRGBConversion::kNone;
432 }
Brian Salomonc320b152018-02-20 14:05:36 -0500433 // If the GrSurfaceContext has no color space then it is in legacy mode.
434 if (!dstColorSpace) {
Brian Salomon9b009bb2018-02-14 13:53:55 -0500435 return GrSRGBConversion::kNone;
436 }
437
438 bool srcColorSpaceIsSRGB = srcColorSpace && srcColorSpace->gammaCloseToSRGB();
439 bool dstColorSpaceIsSRGB = dstColorSpace->gammaCloseToSRGB();
440
441 // For now we are assuming that if color space of the dst does not have sRGB gamma then the
442 // texture format is not sRGB encoded and vice versa. Note that we already checked for "legacy"
Brian Salomonc320b152018-02-20 14:05:36 -0500443 // mode being forced on by caps above. This may change in the future. We will then have to
444 // perform shader based conversions.
Brian Salomon9b009bb2018-02-14 13:53:55 -0500445 SkASSERT(dstColorSpaceIsSRGB == (GrSRGBEncoded::kYes == dstSRGBEncoded));
446
Brian Salomon9b009bb2018-02-14 13:53:55 -0500447 if (srcColorSpaceIsSRGB == dstColorSpaceIsSRGB) {
448 return GrSRGBConversion::kNone;
449 }
450 return srcColorSpaceIsSRGB ? GrSRGBConversion::kSRGBToLinear : GrSRGBConversion::kLinearToSRGB;
451}
452
Brian Salomonc320b152018-02-20 14:05:36 -0500453static GrSRGBConversion determine_read_pixels_srgb_conversion(GrSRGBEncoded srcSRGBEncoded,
454 const SkColorSpace* srcColorSpace,
455 GrColorType dstColorType,
456 const SkColorSpace* dstColorSpace,
457 const GrCaps& caps) {
Brian Salomon9b009bb2018-02-14 13:53:55 -0500458 // This is symmetrical with the write version.
Brian Salomonc320b152018-02-20 14:05:36 -0500459 switch (determine_write_pixels_srgb_conversion(dstColorType, dstColorSpace, srcSRGBEncoded,
460 srcColorSpace, caps)) {
Brian Salomon9b009bb2018-02-14 13:53:55 -0500461 case GrSRGBConversion::kNone: return GrSRGBConversion::kNone;
462 case GrSRGBConversion::kLinearToSRGB: return GrSRGBConversion::kSRGBToLinear;
463 case GrSRGBConversion::kSRGBToLinear: return GrSRGBConversion::kLinearToSRGB;
464 }
465 return GrSRGBConversion::kNone;
466}
467
Brian Salomonc320b152018-02-20 14:05:36 -0500468bool GrContextPriv::writeSurfacePixels(GrSurfaceContext* dst, int left, int top, int width,
469 int height, GrColorType srcColorType,
470 SkColorSpace* srcColorSpace, const void* buffer,
471 size_t rowBytes, uint32_t pixelOpsFlags) {
Brian Salomon5f33a8c2018-02-26 14:32:39 -0500472#ifndef SK_LEGACY_GPU_PIXEL_OPS
473 return this->writeSurfacePixels2(dst, left, top, width, height, srcColorType, srcColorSpace,
474 buffer, rowBytes, pixelOpsFlags);
475#endif
476
Brian Osmanb62ea222016-12-22 11:12:16 -0500477 // TODO: Color space conversion
478
Robert Phillipse78b7252017-04-06 07:59:41 -0400479 ASSERT_SINGLE_OWNER_PRIV
480 RETURN_FALSE_IF_ABANDONED_PRIV
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400481 SkASSERT(dst);
482 ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy());
Brian Salomondcbb9d92017-07-19 10:53:20 -0400483 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels", fContext);
bsalomon6c6f6582015-09-10 08:12:46 -0700484
Robert Phillips6be756b2018-01-16 15:07:54 -0500485 if (!dst->asSurfaceProxy()->instantiate(this->resourceProvider())) {
Robert Phillipse78b7252017-04-06 07:59:41 -0400486 return false;
487 }
488
Robert Phillips16d8ec62017-07-27 16:16:25 -0400489 GrSurfaceProxy* dstProxy = dst->asSurfaceProxy();
490 GrSurface* dstSurface = dstProxy->priv().peekSurface();
Robert Phillipseee4d6e2017-06-05 09:26:07 -0400491
Brian Osmand2ca59a2017-04-13 14:03:57 -0400492 // The src is unpremul but the dst is premul -> premul the src before or as part of the write
Brian Osman409e74f2017-04-17 11:48:28 -0400493 const bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
Brian Salomonc320b152018-02-20 14:05:36 -0500494
495 if (!valid_pixel_conversion(srcColorType, dstProxy->config(), premul)) {
Brian Osmand2ca59a2017-04-13 14:03:57 -0400496 return false;
497 }
498
Brian Osman409e74f2017-04-17 11:48:28 -0400499 // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
500 // without any color spaces attached, and the caller wants us to premul.
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400501 bool useConfigConversionEffect =
Brian Salomonc320b152018-02-20 14:05:36 -0500502 premul && pm_upm_must_round_trip(srcColorType, srcColorSpace) &&
Brian Salomonf3569f02017-10-24 12:52:33 -0400503 pm_upm_must_round_trip(dstProxy->config(), dst->colorSpaceInfo().colorSpace());
Brian Osman409e74f2017-04-17 11:48:28 -0400504
505 // Are we going to try to premul as part of a draw? For the non-legacy case, we always allow
506 // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
507 bool premulOnGpu = premul &&
508 (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
bsalomon81beccc2014-10-13 12:32:55 -0700509
bsalomone8d21e82015-07-16 08:23:13 -0700510 // Trim the params here so that if we wind up making a temporary surface it can be as small as
bsalomonf0674512015-07-28 13:26:15 -0700511 // necessary and because GrGpu::getWritePixelsInfo requires it.
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400512 if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(),
Brian Salomonc320b152018-02-20 14:05:36 -0500513 GrColorTypeBytesPerPixel(srcColorType), &left, &top,
514 &width, &height, &buffer, &rowBytes)) {
bsalomone8d21e82015-07-16 08:23:13 -0700515 return false;
516 }
517
Brian Osman409e74f2017-04-17 11:48:28 -0400518 GrGpu::DrawPreference drawPreference = premulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
519 : GrGpu::kNoDraw_DrawPreference;
bsalomonf0674512015-07-28 13:26:15 -0700520 GrGpu::WritePixelTempDrawInfo tempDrawInfo;
Brian Salomon9b009bb2018-02-14 13:53:55 -0500521 GrSRGBConversion srgbConversion = determine_write_pixels_srgb_conversion(
Brian Salomonc320b152018-02-20 14:05:36 -0500522 srcColorType, srcColorSpace, GrPixelConfigIsSRGBEncoded(dstProxy->config()),
523 dst->colorSpaceInfo().colorSpace(), *fContext->caps());
Robert Phillipsb0e93a22017-08-29 08:26:54 -0400524 if (!fContext->fGpu->getWritePixelsInfo(dstSurface, dstProxy->origin(), width, height,
Brian Salomonc320b152018-02-20 14:05:36 -0500525 srcColorType, srgbConversion, &drawPreference,
Brian Salomon9b009bb2018-02-14 13:53:55 -0500526 &tempDrawInfo)) {
bsalomonf0674512015-07-28 13:26:15 -0700527 return false;
528 }
529
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400530 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) {
Robert Phillipse78b7252017-04-06 07:59:41 -0400531 this->flush(nullptr); // MDB TODO: tighten this
bsalomonf0674512015-07-28 13:26:15 -0700532 }
533
Robert Phillips2f493142017-03-02 18:18:38 -0500534 sk_sp<GrTextureProxy> tempProxy;
bsalomonf0674512015-07-28 13:26:15 -0700535 if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
Robert Phillips0bd24dc2018-01-16 08:06:32 -0500536 tempProxy = this->proxyProvider()->createProxy(tempDrawInfo.fTempSurfaceDesc,
Brian Salomon2a4f9832018-03-03 22:43:43 -0500537 kTopLeft_GrSurfaceOrigin,
538 SkBackingFit::kApprox, SkBudgeted::kYes);
Robert Phillips2f493142017-03-02 18:18:38 -0500539 if (!tempProxy && GrGpu::kRequireDraw_DrawPreference == drawPreference) {
bsalomonf0674512015-07-28 13:26:15 -0700540 return false;
541 }
542 }
543
544 // temp buffer for doing sw premul conversion, if needed.
545 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
Brian Osman409e74f2017-04-17 11:48:28 -0400546 // We need to do sw premul if we were unable to create a RT for drawing, or if we can't do the
547 // premul on the GPU
548 if (premul && (!tempProxy || !premulOnGpu)) {
549 size_t tmpRowBytes = 4 * width;
550 tmpPixels.reset(width * height);
Brian Salomonc320b152018-02-20 14:05:36 -0500551 if (!sw_convert_to_premul(srcColorType, width, height, rowBytes, buffer, tmpRowBytes,
Brian Osman409e74f2017-04-17 11:48:28 -0400552 tmpPixels.get())) {
553 return false;
bsalomonf0674512015-07-28 13:26:15 -0700554 }
Brian Osman409e74f2017-04-17 11:48:28 -0400555 rowBytes = tmpRowBytes;
556 buffer = tmpPixels.get();
bsalomonf0674512015-07-28 13:26:15 -0700557 }
Brian Osman409e74f2017-04-17 11:48:28 -0400558
559 if (tempProxy) {
Brian Osman2240be92017-10-18 13:15:13 -0400560 auto fp = GrSimpleTextureEffect::Make(tempProxy, SkMatrix::I());
Brian Osman409e74f2017-04-17 11:48:28 -0400561 if (premulOnGpu) {
562 fp = fContext->createUPMToPMEffect(std::move(fp), useConfigConversionEffect);
bsalomon81beccc2014-10-13 12:32:55 -0700563 }
Brian Osman409e74f2017-04-17 11:48:28 -0400564 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
Robert Phillips1c9686b2017-06-30 08:40:28 -0400565 if (!fp) {
566 return false;
567 }
Brian Osman409e74f2017-04-17 11:48:28 -0400568
Robert Phillips6be756b2018-01-16 15:07:54 -0500569 if (!tempProxy->instantiate(this->resourceProvider())) {
Brian Osman409e74f2017-04-17 11:48:28 -0400570 return false;
571 }
Robert Phillipseee4d6e2017-06-05 09:26:07 -0400572 GrTexture* texture = tempProxy->priv().peekTexture();
Robert Phillips7bbbf622017-10-17 07:36:59 -0400573
574 if (tempProxy->priv().hasPendingIO()) {
575 this->flush(tempProxy.get());
576 }
577
Robert Phillipsb0e93a22017-08-29 08:26:54 -0400578 if (!fContext->fGpu->writePixels(texture, tempProxy->origin(), 0, 0, width, height,
Brian Salomonc320b152018-02-20 14:05:36 -0500579 tempDrawInfo.fWriteColorType, buffer, rowBytes)) {
Brian Osman409e74f2017-04-17 11:48:28 -0400580 return false;
581 }
Robert Phillips7bbbf622017-10-17 07:36:59 -0400582 tempProxy = nullptr;
583
Brian Osman409e74f2017-04-17 11:48:28 -0400584 SkMatrix matrix;
585 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400586 GrRenderTargetContext* renderTargetContext = dst->asRenderTargetContext();
Brian Osman409e74f2017-04-17 11:48:28 -0400587 if (!renderTargetContext) {
588 return false;
589 }
590 GrPaint paint;
591 paint.addColorFragmentProcessor(std::move(fp));
592 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Brian Salomonf3569f02017-10-24 12:52:33 -0400593 paint.setAllowSRGBInputs(dst->colorSpaceInfo().isGammaCorrect() ||
594 GrPixelConfigIsSRGB(dst->colorSpaceInfo().config()));
Brian Osman409e74f2017-04-17 11:48:28 -0400595 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
596 renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect,
597 nullptr);
598
599 if (kFlushWrites_PixelOp & pixelOpsFlags) {
600 this->flushSurfaceWrites(renderTargetContext->asRenderTargetProxy());
601 }
602 } else {
Brian Salomonc320b152018-02-20 14:05:36 -0500603 return fContext->fGpu->writePixels(dstSurface, dstProxy->origin(), left, top, width, height,
604 srcColorType, buffer, rowBytes);
bsalomon81beccc2014-10-13 12:32:55 -0700605 }
bsalomon81beccc2014-10-13 12:32:55 -0700606 return true;
607}
bsalomon@google.coma91e9232012-02-23 15:39:54 +0000608
Brian Salomonc320b152018-02-20 14:05:36 -0500609bool GrContextPriv::readSurfacePixels(GrSurfaceContext* src, int left, int top, int width,
610 int height, GrColorType dstColorType,
611 SkColorSpace* dstColorSpace, void* buffer, size_t rowBytes,
612 uint32_t flags) {
Brian Osmanb62ea222016-12-22 11:12:16 -0500613 // TODO: Color space conversion
614
Robert Phillipse78b7252017-04-06 07:59:41 -0400615 ASSERT_SINGLE_OWNER_PRIV
616 RETURN_FALSE_IF_ABANDONED_PRIV
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400617 SkASSERT(src);
618 ASSERT_OWNED_PROXY_PRIV(src->asSurfaceProxy());
Brian Salomondcbb9d92017-07-19 10:53:20 -0400619 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "readSurfacePixels", fContext);
bsalomon32ab2602015-09-09 18:57:49 -0700620
Robert Phillipse78b7252017-04-06 07:59:41 -0400621 // MDB TODO: delay this instantiation until later in the method
Robert Phillips6be756b2018-01-16 15:07:54 -0500622 if (!src->asSurfaceProxy()->instantiate(this->resourceProvider())) {
Robert Phillipse78b7252017-04-06 07:59:41 -0400623 return false;
624 }
625
Robert Phillips16d8ec62017-07-27 16:16:25 -0400626 GrSurfaceProxy* srcProxy = src->asSurfaceProxy();
627 GrSurface* srcSurface = srcProxy->priv().peekSurface();
Robert Phillipseee4d6e2017-06-05 09:26:07 -0400628
Brian Osmand2ca59a2017-04-13 14:03:57 -0400629 // The src is premul but the dst is unpremul -> unpremul the src after or as part of the read
630 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
Brian Salomonc320b152018-02-20 14:05:36 -0500631
632 if (!valid_pixel_conversion(dstColorType, srcProxy->config(), unpremul)) {
Brian Osmand2ca59a2017-04-13 14:03:57 -0400633 return false;
634 }
635
Brian Osman409e74f2017-04-17 11:48:28 -0400636 // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
637 // without any color spaces attached, and the caller wants us to unpremul.
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400638 bool useConfigConversionEffect =
Brian Salomonf3569f02017-10-24 12:52:33 -0400639 unpremul &&
640 pm_upm_must_round_trip(srcProxy->config(), src->colorSpaceInfo().colorSpace()) &&
Brian Salomonc320b152018-02-20 14:05:36 -0500641 pm_upm_must_round_trip(dstColorType, dstColorSpace);
Brian Osman409e74f2017-04-17 11:48:28 -0400642
643 // Are we going to try to unpremul as part of a draw? For the non-legacy case, we always allow
644 // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
645 bool unpremulOnGpu = unpremul &&
646 (!useConfigConversionEffect || fContext->validPMUPMConversionExists());
bsalomon6c6f6582015-09-10 08:12:46 -0700647
bsalomone8d21e82015-07-16 08:23:13 -0700648 // Adjust the params so that if we wind up using an intermediate surface we've already done
649 // all the trimming and the temporary can be the min size required.
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400650 if (!GrSurfacePriv::AdjustReadPixelParams(srcSurface->width(), srcSurface->height(),
Brian Salomonc320b152018-02-20 14:05:36 -0500651 GrColorTypeBytesPerPixel(dstColorType), &left, &top,
652 &width, &height, &buffer, &rowBytes)) {
bsalomone8d21e82015-07-16 08:23:13 -0700653 return false;
654 }
655
Brian Osman409e74f2017-04-17 11:48:28 -0400656 GrGpu::DrawPreference drawPreference = unpremulOnGpu ? GrGpu::kCallerPrefersDraw_DrawPreference
657 : GrGpu::kNoDraw_DrawPreference;
bsalomon39826022015-07-23 08:07:21 -0700658 GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
Brian Salomon9b009bb2018-02-14 13:53:55 -0500659 GrSRGBConversion srgbConversion = determine_read_pixels_srgb_conversion(
660 GrPixelConfigIsSRGBEncoded(srcProxy->config()), src->colorSpaceInfo().colorSpace(),
Brian Salomonc320b152018-02-20 14:05:36 -0500661 dstColorType, dstColorSpace, *fContext->caps());
662
Robert Phillipsb0e93a22017-08-29 08:26:54 -0400663 if (!fContext->fGpu->getReadPixelsInfo(srcSurface, srcProxy->origin(), width, height, rowBytes,
Brian Salomonc320b152018-02-20 14:05:36 -0500664 dstColorType, srgbConversion, &drawPreference,
Brian Salomon9b009bb2018-02-14 13:53:55 -0500665 &tempDrawInfo)) {
bsalomon39826022015-07-23 08:07:21 -0700666 return false;
667 }
bsalomon191bcc02014-11-14 11:31:13 -0800668
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400669 if (!(kDontFlush_PixelOpsFlag & flags) && srcSurface->surfacePriv().hasPendingWrite()) {
Brian Osmand2ca59a2017-04-13 14:03:57 -0400670 this->flush(nullptr); // MDB TODO: tighten this
671 }
672
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400673 sk_sp<GrSurfaceProxy> proxyToRead = src->asSurfaceProxyRef();
bsalomon39826022015-07-23 08:07:21 -0700674 bool didTempDraw = false;
675 if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
bsalomonb117ff12016-07-19 07:24:40 -0700676 if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) {
bsalomon39826022015-07-23 08:07:21 -0700677 // We only respect this when the entire src is being read. Otherwise we can trigger too
678 // many odd ball texture sizes and trash the cache.
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400679 if (width != srcSurface->width() || height != srcSurface->height()) {
bsalomonb117ff12016-07-19 07:24:40 -0700680 tempDrawInfo.fTempSurfaceFit= SkBackingFit::kApprox;
bsalomon39826022015-07-23 08:07:21 -0700681 }
bsalomon@google.com56d11e02011-11-30 19:59:08 +0000682 }
brianosmandfe4f2e2016-07-21 13:28:36 -0700683 // TODO: Need to decide the semantics of this function for color spaces. Do we support
684 // conversion to a passed-in color space? For now, specifying nullptr means that this
Brian Salomon366093f2018-02-13 09:25:22 -0500685 // path will do no conversion, so it will match the behavior of the non-draw path. For
686 // now we simply infer an sRGB color space if the config is sRGB in order to avoid an
687 // illegal combination.
688 sk_sp<SkColorSpace> colorSpace;
689 if (GrPixelConfigIsSRGB(tempDrawInfo.fTempSurfaceDesc.fConfig)) {
690 colorSpace = SkColorSpace::MakeSRGB();
691 }
692 sk_sp<GrRenderTargetContext> tempRTC =
Robert Phillips0c4b7b12018-03-06 08:20:37 -0500693 fContext->contextPriv().makeDeferredRenderTargetContext(
694 tempDrawInfo.fTempSurfaceFit,
Brian Salomon366093f2018-02-13 09:25:22 -0500695 tempDrawInfo.fTempSurfaceDesc.fWidth,
696 tempDrawInfo.fTempSurfaceDesc.fHeight,
697 tempDrawInfo.fTempSurfaceDesc.fConfig,
698 std::move(colorSpace),
699 tempDrawInfo.fTempSurfaceDesc.fSampleCnt,
700 GrMipMapped::kNo,
Brian Salomon2a4f9832018-03-03 22:43:43 -0500701 kTopLeft_GrSurfaceOrigin);
Brian Osman693a5402016-10-27 15:13:22 -0400702 if (tempRTC) {
Greg Danielf44cb482018-02-27 14:26:32 -0500703 // Adding discard to appease vulkan validation warning about loading uninitialized data
704 // on draw
705 tempRTC->discard();
Robert Phillips67c18d62017-01-20 12:44:06 -0500706 SkMatrix textureMatrix = SkMatrix::MakeTrans(SkIntToScalar(left), SkIntToScalar(top));
Robert Phillipsf41c22f2017-04-18 07:48:58 -0400707 sk_sp<GrTextureProxy> proxy = src->asTextureProxyRef();
Brian Osman2240be92017-10-18 13:15:13 -0400708 auto fp = GrSimpleTextureEffect::Make(std::move(proxy), textureMatrix);
Brian Osman409e74f2017-04-17 11:48:28 -0400709 if (unpremulOnGpu) {
710 fp = fContext->createPMToUPMEffect(std::move(fp), useConfigConversionEffect);
711 // We no longer need to do this on CPU after the read back.
712 unpremul = false;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000713 }
Brian Osman409e74f2017-04-17 11:48:28 -0400714 fp = GrFragmentProcessor::SwizzleOutput(std::move(fp), tempDrawInfo.fSwizzle);
Robert Phillips1c9686b2017-06-30 08:40:28 -0400715 if (!fp) {
716 return false;
717 }
Brian Osman60cd57e2017-04-06 10:19:06 -0400718
Brian Osman409e74f2017-04-17 11:48:28 -0400719 GrPaint paint;
720 paint.addColorFragmentProcessor(std::move(fp));
721 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
722 paint.setAllowSRGBInputs(true);
723 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
724 tempRTC->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect,
725 nullptr);
726 proxyToRead = tempRTC->asTextureProxyRef();
727 left = 0;
728 top = 0;
729 didTempDraw = true;
bsalomon@google.com0342a852012-08-20 19:22:38 +0000730 }
bsalomon@google.comc4364992011-11-07 15:54:49 +0000731 }
joshualitt5c55fef2014-10-31 14:04:35 -0700732
Robert Phillipse78b7252017-04-06 07:59:41 -0400733 if (!proxyToRead) {
734 return false;
735 }
736
bsalomon39826022015-07-23 08:07:21 -0700737 if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000738 return false;
739 }
Brian Salomonc320b152018-02-20 14:05:36 -0500740 GrColorType colorTypeToRead = dstColorType;
bsalomon39826022015-07-23 08:07:21 -0700741 if (didTempDraw) {
Robert Phillipse78b7252017-04-06 07:59:41 -0400742 this->flushSurfaceWrites(proxyToRead.get());
Brian Salomonc320b152018-02-20 14:05:36 -0500743 colorTypeToRead = tempDrawInfo.fReadColorType;
bsalomon39826022015-07-23 08:07:21 -0700744 }
Robert Phillips09dfc472017-09-13 15:25:47 -0400745
Robert Phillips6be756b2018-01-16 15:07:54 -0500746 if (!proxyToRead->instantiate(this->resourceProvider())) {
Robert Phillips09dfc472017-09-13 15:25:47 -0400747 return false;
748 }
749
750 GrSurface* surfaceToRead = proxyToRead->priv().peekSurface();
751
Brian Salomonc320b152018-02-20 14:05:36 -0500752 if (!fContext->fGpu->readPixels(surfaceToRead, proxyToRead->origin(), left, top, width, height,
753 colorTypeToRead, buffer, rowBytes)) {
bsalomon39826022015-07-23 08:07:21 -0700754 return false;
755 }
756
757 // Perform umpremul conversion if we weren't able to perform it as a draw.
758 if (unpremul) {
Brian Salomonc320b152018-02-20 14:05:36 -0500759 SkColorType colorType = GrColorTypeToSkColorType(dstColorType);
760 if (kUnknown_SkColorType == colorType || 4 != SkColorTypeBytesPerPixel(colorType)) {
reed@google.com7111d462014-03-25 16:20:24 +0000761 return false;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000762 }
reed@google.com7111d462014-03-25 16:20:24 +0000763
Matt Sarettc7b29082017-02-09 16:22:39 -0500764 for (int y = 0; y < height; y++) {
765 SkUnpremultiplyRow<false>((uint32_t*) buffer, (const uint32_t*) buffer, width);
766 buffer = SkTAddOffset<void>(buffer, rowBytes);
767 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000768 }
769 return true;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000770}
771
Brian Salomon5f33a8c2018-02-26 14:32:39 -0500772bool GrContextPriv::writeSurfacePixels2(GrSurfaceContext* dst, int left, int top, int width,
773 int height, GrColorType srcColorType,
774 SkColorSpace* srcColorSpace, const void* buffer,
775 size_t rowBytes, uint32_t pixelOpsFlags) {
776 ASSERT_SINGLE_OWNER_PRIV
777 RETURN_FALSE_IF_ABANDONED_PRIV
778 SkASSERT(dst);
779 SkASSERT(buffer);
780 ASSERT_OWNED_PROXY_PRIV(dst->asSurfaceProxy());
781 GR_CREATE_TRACE_MARKER_CONTEXT("GrContextPriv", "writeSurfacePixels2", fContext);
782
783 if (GrColorType::kUnknown == srcColorType) {
784 return false;
785 }
786
787 if (!dst->asSurfaceProxy()->instantiate(this->resourceProvider())) {
788 return false;
789 }
790
791 GrSurfaceProxy* dstProxy = dst->asSurfaceProxy();
792 GrSurface* dstSurface = dstProxy->priv().peekSurface();
793
794 if (!GrSurfacePriv::AdjustWritePixelParams(dstSurface->width(), dstSurface->height(),
795 GrColorTypeBytesPerPixel(srcColorType), &left, &top,
796 &width, &height, &buffer, &rowBytes)) {
797 return false;
798 }
799
Brian Salomon3d86a192018-02-27 16:46:11 -0500800 if (!fContext->caps()->surfaceSupportsWritePixels(dstSurface)) {
Brian Salomon5f33a8c2018-02-26 14:32:39 -0500801 GrSurfaceDesc desc;
802 desc.fConfig = dstProxy->config();
803 desc.fWidth = width;
804 desc.fHeight = height;
805 desc.fSampleCnt = 1;
Brian Salomon2a4f9832018-03-03 22:43:43 -0500806 auto tempProxy = this->proxyProvider()->createProxy(
807 desc, kTopLeft_GrSurfaceOrigin, SkBackingFit::kApprox, SkBudgeted::kYes);
Brian Salomon5f33a8c2018-02-26 14:32:39 -0500808 if (!tempProxy) {
809 return false;
810 }
811 auto tempCtx = this->drawingManager()->makeTextureContext(
812 tempProxy, dst->colorSpaceInfo().refColorSpace());
813 if (!tempCtx) {
814 return false;
815 }
816 if (!this->writeSurfacePixels2(tempCtx.get(), 0, 0, width, height, srcColorType,
817 srcColorSpace, buffer, rowBytes, pixelOpsFlags)) {
818 return false;
819 }
Brian Salomon3d86a192018-02-27 16:46:11 -0500820 return dst->copy(tempProxy.get(), SkIRect::MakeWH(width, height), {left, top});
Brian Salomon5f33a8c2018-02-26 14:32:39 -0500821 }
822
823 // TODO: Make GrSurfaceContext know its alpha type and pass src buffer's alpha type.
824 bool premul = SkToBool(kUnpremul_PixelOpsFlag & pixelOpsFlags);
825 bool convert = premul;
826
827 if (!valid_pixel_conversion(srcColorType, dstProxy->config(), premul)) {
828 return false;
829 }
830
831 GrColorType allowedColorType =
832 fContext->caps()->supportedWritePixelsColorType(dstProxy->config(), srcColorType);
833 convert = convert || (srcColorType != allowedColorType);
834
835 if (!dst->colorSpaceInfo().colorSpace()) {
836 // "Legacy" mode - no color space conversions.
837 srcColorSpace = nullptr;
838 }
839 convert = convert || !SkColorSpace::Equals(srcColorSpace, dst->colorSpaceInfo().colorSpace());
840
841 std::unique_ptr<char[]> tempBuffer;
842 if (convert) {
843 auto srcSkColorType = GrColorTypeToSkColorType(srcColorType);
844 auto dstSkColorType = GrColorTypeToSkColorType(allowedColorType);
845 if (kUnknown_SkColorType == srcSkColorType || kUnknown_SkColorType == dstSkColorType) {
846 return false;
847 }
848 auto srcAlphaType = premul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
849 SkPixmap src(SkImageInfo::Make(width, height, srcSkColorType, srcAlphaType,
850 sk_ref_sp(srcColorSpace)),
851 buffer, rowBytes);
852 auto tempSrcII = SkImageInfo::Make(width, height, dstSkColorType, kPremul_SkAlphaType,
853 dst->colorSpaceInfo().refColorSpace());
854 auto size = tempSrcII.computeMinByteSize();
855 if (!size) {
856 return false;
857 }
858 tempBuffer.reset(new char[size]);
859 SkPixmap tempSrc(tempSrcII, tempBuffer.get(), tempSrcII.minRowBytes());
860 if (!src.readPixels(tempSrc)) {
861 return false;
862 }
863 srcColorType = allowedColorType;
864 buffer = tempSrc.addr();
865 rowBytes = tempSrc.rowBytes();
866 if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
867 std::unique_ptr<char[]> row(new char[rowBytes]);
868 for (int y = 0; y < height / 2; ++y) {
869 memcpy(row.get(), tempSrc.addr(0, y), rowBytes);
870 memcpy(tempSrc.writable_addr(0, y), tempSrc.addr(0, height - 1 - y), rowBytes);
871 memcpy(tempSrc.writable_addr(0, height - 1 - y), row.get(), rowBytes);
872 }
873 top = dstProxy->height() - top - height;
874 }
875 } else if (dstProxy->origin() == kBottomLeft_GrSurfaceOrigin) {
876 size_t trimRowBytes = GrColorTypeBytesPerPixel(srcColorType) * width;
877 tempBuffer.reset(new char[trimRowBytes * height]);
878 char* dst = reinterpret_cast<char*>(tempBuffer.get()) + trimRowBytes * (height - 1);
879 const char* src = reinterpret_cast<const char*>(buffer);
880 for (int i = 0; i < height; ++i, src += rowBytes, dst -= trimRowBytes) {
881 memcpy(dst, src, trimRowBytes);
882 }
883 buffer = tempBuffer.get();
884 rowBytes = trimRowBytes;
885 top = dstProxy->height() - top - height;
886 }
887
888 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && dstSurface->surfacePriv().hasPendingIO()) {
889 this->flush(nullptr); // MDB TODO: tighten this
890 }
891
892 return this->getGpu()->writePixels(dstSurface, left, top, width, height, srcColorType, buffer,
893 rowBytes);
894}
895
Robert Phillips7ee385e2017-03-30 08:02:11 -0400896void GrContextPriv::prepareSurfaceForExternalIO(GrSurfaceProxy* proxy) {
897 ASSERT_SINGLE_OWNER_PRIV
898 RETURN_IF_ABANDONED_PRIV
899 SkASSERT(proxy);
900 ASSERT_OWNED_PROXY_PRIV(proxy);
Greg Daniel51316782017-08-02 15:10:09 +0000901 fContext->fDrawingManager->prepareSurfaceForExternalIO(proxy, 0, nullptr);
bsalomon@google.com75f9f252012-01-31 13:35:56 +0000902}
903
Robert Phillips7ee385e2017-03-30 08:02:11 -0400904void GrContextPriv::flushSurfaceWrites(GrSurfaceProxy* proxy) {
905 ASSERT_SINGLE_OWNER_PRIV
906 RETURN_IF_ABANDONED_PRIV
907 SkASSERT(proxy);
908 ASSERT_OWNED_PROXY_PRIV(proxy);
909 if (proxy->priv().hasPendingWrite()) {
910 this->flush(proxy);
bsalomonf80bfed2014-10-07 05:56:02 -0700911 }
912}
913
Robert Phillips7ee385e2017-03-30 08:02:11 -0400914void GrContextPriv::flushSurfaceIO(GrSurfaceProxy* proxy) {
915 ASSERT_SINGLE_OWNER_PRIV
916 RETURN_IF_ABANDONED_PRIV
917 SkASSERT(proxy);
918 ASSERT_OWNED_PROXY_PRIV(proxy);
919 if (proxy->priv().hasPendingIO()) {
920 this->flush(proxy);
ajuma95243eb2016-08-24 08:19:02 -0700921 }
922}
923
bsalomon@google.com27847de2011-02-22 20:59:41 +0000924////////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000925
Robert Phillips2c862492017-01-18 10:08:39 -0500926sk_sp<GrSurfaceContext> GrContextPriv::makeWrappedSurfaceContext(sk_sp<GrSurfaceProxy> proxy,
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500927 sk_sp<SkColorSpace> colorSpace,
928 const SkSurfaceProps* props) {
Brian Osman45580d32016-11-23 09:37:01 -0500929 ASSERT_SINGLE_OWNER_PRIV
930
Brian Salomon366093f2018-02-13 09:25:22 -0500931 // sRGB pixel configs may only be used with near-sRGB gamma color spaces.
932 if (GrPixelConfigIsSRGB(proxy->config())) {
933 if (!colorSpace || !colorSpace->gammaCloseToSRGB()) {
934 return nullptr;
935 }
936 }
Brian Osman45580d32016-11-23 09:37:01 -0500937 if (proxy->asRenderTargetProxy()) {
Robert Phillips2c862492017-01-18 10:08:39 -0500938 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500939 std::move(colorSpace), props);
Brian Osman45580d32016-11-23 09:37:01 -0500940 } else {
941 SkASSERT(proxy->asTextureProxy());
Robert Phillipsd5f9cdd2018-01-31 09:29:48 -0500942 SkASSERT(!props);
Robert Phillips2c862492017-01-18 10:08:39 -0500943 return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
Brian Osman45580d32016-11-23 09:37:01 -0500944 }
945}
946
Robert Phillipse2f7d182016-12-15 09:23:05 -0500947sk_sp<GrSurfaceContext> GrContextPriv::makeDeferredSurfaceContext(const GrSurfaceDesc& dstDesc,
Brian Salomon2a4f9832018-03-03 22:43:43 -0500948 GrSurfaceOrigin origin,
Greg Daniel65c7f662017-10-30 13:39:09 -0400949 GrMipMapped mipMapped,
Robert Phillipse2f7d182016-12-15 09:23:05 -0500950 SkBackingFit fit,
Brian Salomon366093f2018-02-13 09:25:22 -0500951 SkBudgeted isDstBudgeted,
952 sk_sp<SkColorSpace> colorSpace,
953 const SkSurfaceProps* props) {
Greg Daniel65c7f662017-10-30 13:39:09 -0400954 sk_sp<GrTextureProxy> proxy;
955 if (GrMipMapped::kNo == mipMapped) {
Brian Salomon2a4f9832018-03-03 22:43:43 -0500956 proxy = this->proxyProvider()->createProxy(dstDesc, origin, fit, isDstBudgeted);
Greg Daniel65c7f662017-10-30 13:39:09 -0400957 } else {
958 SkASSERT(SkBackingFit::kExact == fit);
Brian Salomon2a4f9832018-03-03 22:43:43 -0500959 proxy = this->proxyProvider()->createMipMapProxy(dstDesc, origin, isDstBudgeted);
Greg Daniel65c7f662017-10-30 13:39:09 -0400960 }
Robert Phillips77b3f322017-01-31 18:24:12 -0500961 if (!proxy) {
962 return nullptr;
963 }
Robert Phillipse2f7d182016-12-15 09:23:05 -0500964
Brian Salomon366093f2018-02-13 09:25:22 -0500965 return this->makeWrappedSurfaceContext(std::move(proxy), std::move(colorSpace), props);
Robert Phillipse2f7d182016-12-15 09:23:05 -0500966}
967
Brian Salomond17f6582017-07-19 18:28:58 -0400968sk_sp<GrTextureContext> GrContextPriv::makeBackendTextureContext(const GrBackendTexture& tex,
Greg Daniel7ef28f32017-04-20 16:41:55 +0000969 GrSurfaceOrigin origin,
Brian Osmanc1e37052017-03-09 14:19:20 -0500970 sk_sp<SkColorSpace> colorSpace) {
Robert Phillips26caf892017-01-27 10:58:31 -0500971 ASSERT_SINGLE_OWNER_PRIV
972
Brian Salomon7578f3e2018-03-07 14:39:54 -0500973 sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->wrapBackendTexture(tex, origin);
Robert Phillips77b3f322017-01-31 18:24:12 -0500974 if (!proxy) {
975 return nullptr;
976 }
Robert Phillips26caf892017-01-27 10:58:31 -0500977
Brian Salomond17f6582017-07-19 18:28:58 -0400978 return this->drawingManager()->makeTextureContext(std::move(proxy), std::move(colorSpace));
Robert Phillips26caf892017-01-27 10:58:31 -0500979}
980
Brian Osman11052242016-10-27 14:47:55 -0400981sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureRenderTargetContext(
Greg Daniel7ef28f32017-04-20 16:41:55 +0000982 const GrBackendTexture& tex,
983 GrSurfaceOrigin origin,
984 int sampleCnt,
Brian Osman11052242016-10-27 14:47:55 -0400985 sk_sp<SkColorSpace> colorSpace,
Brian Osmanc1e37052017-03-09 14:19:20 -0500986 const SkSurfaceProps* props) {
robertphillips4fd74ae2016-08-03 14:26:53 -0700987 ASSERT_SINGLE_OWNER_PRIV
Brian Salomonbdecacf2018-02-02 20:32:49 -0500988 SkASSERT(sampleCnt > 0);
robertphillips4fd74ae2016-08-03 14:26:53 -0700989
Brian Salomon7578f3e2018-03-07 14:39:54 -0500990 sk_sp<GrTextureProxy> proxy(
991 this->proxyProvider()->wrapRenderableBackendTexture(tex, origin, sampleCnt));
Robert Phillips77b3f322017-01-31 18:24:12 -0500992 if (!proxy) {
993 return nullptr;
994 }
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400995
Robert Phillips37430132016-11-09 06:50:43 -0500996 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
Brian Osman11052242016-10-27 14:47:55 -0400997 std::move(colorSpace), props);
robertphillips4fd74ae2016-08-03 14:26:53 -0700998}
999
Brian Osman11052242016-10-27 14:47:55 -04001000sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendRenderTargetRenderTargetContext(
Greg Danielbcf612b2017-05-01 13:50:58 +00001001 const GrBackendRenderTarget& backendRT,
1002 GrSurfaceOrigin origin,
robertphillips4fd74ae2016-08-03 14:26:53 -07001003 sk_sp<SkColorSpace> colorSpace,
1004 const SkSurfaceProps* surfaceProps) {
1005 ASSERT_SINGLE_OWNER_PRIV
1006
Brian Salomon7578f3e2018-03-07 14:39:54 -05001007 sk_sp<GrSurfaceProxy> proxy = this->proxyProvider()->wrapBackendRenderTarget(backendRT, origin);
Robert Phillips77b3f322017-01-31 18:24:12 -05001008 if (!proxy) {
1009 return nullptr;
1010 }
Robert Phillipsc7635fa2016-10-28 13:25:24 -04001011
Robert Phillips37430132016-11-09 06:50:43 -05001012 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
Robert Phillipsc7635fa2016-10-28 13:25:24 -04001013 std::move(colorSpace),
Brian Osman11052242016-10-27 14:47:55 -04001014 surfaceProps);
robertphillips4fd74ae2016-08-03 14:26:53 -07001015}
1016
Brian Osman11052242016-10-27 14:47:55 -04001017sk_sp<GrRenderTargetContext> GrContextPriv::makeBackendTextureAsRenderTargetRenderTargetContext(
Greg Daniel7ef28f32017-04-20 16:41:55 +00001018 const GrBackendTexture& tex,
1019 GrSurfaceOrigin origin,
1020 int sampleCnt,
robertphillips4fd74ae2016-08-03 14:26:53 -07001021 sk_sp<SkColorSpace> colorSpace,
Robert Phillips0bd24dc2018-01-16 08:06:32 -05001022 const SkSurfaceProps* props) {
robertphillips4fd74ae2016-08-03 14:26:53 -07001023 ASSERT_SINGLE_OWNER_PRIV
Brian Salomonbdecacf2018-02-02 20:32:49 -05001024 SkASSERT(sampleCnt > 0);
Brian Salomon7578f3e2018-03-07 14:39:54 -05001025 sk_sp<GrSurfaceProxy> proxy(
1026 this->proxyProvider()->wrapBackendTextureAsRenderTarget(tex, origin, sampleCnt));
Robert Phillips77b3f322017-01-31 18:24:12 -05001027 if (!proxy) {
1028 return nullptr;
1029 }
Robert Phillipsc7635fa2016-10-28 13:25:24 -04001030
Robert Phillips37430132016-11-09 06:50:43 -05001031 return this->drawingManager()->makeRenderTargetContext(std::move(proxy),
Robert Phillipsc7635fa2016-10-28 13:25:24 -04001032 std::move(colorSpace),
Robert Phillips0bd24dc2018-01-16 08:06:32 -05001033 props);
robertphillips77a2e522015-10-17 07:43:27 -07001034}
1035
Chris Daltonfe199b72017-05-05 11:26:15 -04001036void GrContextPriv::addOnFlushCallbackObject(GrOnFlushCallbackObject* onFlushCBObject) {
1037 fContext->fDrawingManager->addOnFlushCallbackObject(onFlushCBObject);
Robert Phillipseb35f4d2017-03-21 07:56:47 -04001038}
1039
Robert Phillips62000362018-02-01 09:10:04 -05001040void GrContextPriv::moveOpListsToDDL(SkDeferredDisplayList* ddl) {
1041 fContext->fDrawingManager->moveOpListsToDDL(ddl);
1042}
1043
1044void GrContextPriv::copyOpListsFromDDL(const SkDeferredDisplayList* ddl,
1045 GrRenderTargetProxy* newDest) {
1046 fContext->fDrawingManager->copyOpListsFromDDL(ddl, newDest);
1047}
1048
robertphillips48fde9c2016-09-06 05:20:20 -07001049static inline GrPixelConfig GrPixelConfigFallback(GrPixelConfig config) {
Brian Osman78f20e02017-01-12 10:28:01 -05001050 switch (config) {
1051 case kAlpha_8_GrPixelConfig:
1052 case kRGB_565_GrPixelConfig:
1053 case kRGBA_4444_GrPixelConfig:
1054 case kBGRA_8888_GrPixelConfig:
Brian Osman10fc6fd2018-03-02 11:01:10 -05001055 case kRGBA_1010102_GrPixelConfig:
Brian Osman78f20e02017-01-12 10:28:01 -05001056 return kRGBA_8888_GrPixelConfig;
1057 case kSBGRA_8888_GrPixelConfig:
1058 return kSRGBA_8888_GrPixelConfig;
1059 case kAlpha_half_GrPixelConfig:
1060 return kRGBA_half_GrPixelConfig;
1061 default:
1062 return kUnknown_GrPixelConfig;
1063 }
robertphillips48fde9c2016-09-06 05:20:20 -07001064}
1065
Robert Phillips0c4b7b12018-03-06 08:20:37 -05001066sk_sp<GrRenderTargetContext> GrContextPriv::makeDeferredRenderTargetContextWithFallback(
robertphillipsd728f0c2016-11-21 11:05:03 -08001067 SkBackingFit fit,
1068 int width, int height,
1069 GrPixelConfig config,
1070 sk_sp<SkColorSpace> colorSpace,
1071 int sampleCnt,
Greg Daniel45d63032017-10-30 13:41:26 -04001072 GrMipMapped mipMapped,
robertphillipsd728f0c2016-11-21 11:05:03 -08001073 GrSurfaceOrigin origin,
1074 const SkSurfaceProps* surfaceProps,
1075 SkBudgeted budgeted) {
Brian Salomonbdecacf2018-02-02 20:32:49 -05001076 SkASSERT(sampleCnt > 0);
Robert Phillips0c4b7b12018-03-06 08:20:37 -05001077 if (0 == fContext->caps()->getRenderTargetSampleCount(sampleCnt, config)) {
robertphillipsd728f0c2016-11-21 11:05:03 -08001078 config = GrPixelConfigFallback(config);
1079 }
1080
1081 return this->makeDeferredRenderTargetContext(fit, width, height, config, std::move(colorSpace),
Greg Daniel45d63032017-10-30 13:41:26 -04001082 sampleCnt, mipMapped, origin, surfaceProps,
Greg Daniele1da1d92017-10-06 15:59:27 -04001083 budgeted);
robertphillipsd728f0c2016-11-21 11:05:03 -08001084}
1085
Robert Phillips0c4b7b12018-03-06 08:20:37 -05001086sk_sp<GrRenderTargetContext> GrContextPriv::makeDeferredRenderTargetContext(
Robert Phillipsc7635fa2016-10-28 13:25:24 -04001087 SkBackingFit fit,
1088 int width, int height,
1089 GrPixelConfig config,
1090 sk_sp<SkColorSpace> colorSpace,
1091 int sampleCnt,
Greg Daniel45d63032017-10-30 13:41:26 -04001092 GrMipMapped mipMapped,
Robert Phillipsc7635fa2016-10-28 13:25:24 -04001093 GrSurfaceOrigin origin,
1094 const SkSurfaceProps* surfaceProps,
1095 SkBudgeted budgeted) {
Brian Salomonbdecacf2018-02-02 20:32:49 -05001096 SkASSERT(sampleCnt > 0);
Brian Salomon79e4d1b2017-07-13 11:17:11 -04001097 if (this->abandoned()) {
1098 return nullptr;
1099 }
1100
Robert Phillipsc7635fa2016-10-28 13:25:24 -04001101 GrSurfaceDesc desc;
1102 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillipsc7635fa2016-10-28 13:25:24 -04001103 desc.fWidth = width;
1104 desc.fHeight = height;
1105 desc.fConfig = config;
1106 desc.fSampleCnt = sampleCnt;
1107
Greg Daniele1da1d92017-10-06 15:59:27 -04001108 sk_sp<GrTextureProxy> rtp;
Greg Daniel45d63032017-10-30 13:41:26 -04001109 if (GrMipMapped::kNo == mipMapped) {
Robert Phillips0c4b7b12018-03-06 08:20:37 -05001110 rtp = fContext->fProxyProvider->createProxy(desc, origin, fit, budgeted);
Greg Daniele1da1d92017-10-06 15:59:27 -04001111 } else {
Robert Phillips0c4b7b12018-03-06 08:20:37 -05001112 rtp = fContext->fProxyProvider->createMipMapProxy(desc, origin, budgeted);
Greg Daniele1da1d92017-10-06 15:59:27 -04001113 }
Robert Phillips08c5ec72017-01-30 12:26:47 -05001114 if (!rtp) {
1115 return nullptr;
1116 }
Robert Phillipsc7635fa2016-10-28 13:25:24 -04001117
Robert Phillips1119dc32017-04-11 12:54:57 -04001118 sk_sp<GrRenderTargetContext> renderTargetContext(
Robert Phillips0c4b7b12018-03-06 08:20:37 -05001119 fContext->fDrawingManager->makeRenderTargetContext(std::move(rtp),
1120 std::move(colorSpace),
1121 surfaceProps));
Robert Phillips1119dc32017-04-11 12:54:57 -04001122 if (!renderTargetContext) {
1123 return nullptr;
1124 }
1125
1126 renderTargetContext->discard();
1127
1128 return renderTargetContext;
Robert Phillipsc7635fa2016-10-28 13:25:24 -04001129}
1130
Robert Phillips0c4b7b12018-03-06 08:20:37 -05001131bool GrContextPriv::abandoned() const {
1132 ASSERT_SINGLE_OWNER_PRIV
1133 return fContext->fDrawingManager->wasAbandoned();
robertphillips77a2e522015-10-17 07:43:27 -07001134}
1135
Brian Salomonaff329b2017-08-11 09:40:37 -04001136std::unique_ptr<GrFragmentProcessor> GrContext::createPMToUPMEffect(
1137 std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) {
Robert Phillips757914d2017-01-25 15:48:30 -05001138 ASSERT_SINGLE_OWNER
Brian Osman409e74f2017-04-17 11:48:28 -04001139 // We have specialized effects that guarantee round-trip conversion for some formats
1140 if (useConfigConversionEffect) {
1141 // We should have already called this->validPMUPMConversionExists() in this case
1142 SkASSERT(fDidTestPMConversions);
1143 // ...and it should have succeeded
1144 SkASSERT(this->validPMUPMConversionExists());
1145
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001146 return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToUnpremul);
Brian Osman2d2da4f2017-04-12 17:07:22 -04001147 } else {
1148 // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
1149 // explicitly round the results. Just do the obvious, naive thing in the shader.
1150 return GrFragmentProcessor::UnpremulOutput(std::move(fp));
Robert Phillips757914d2017-01-25 15:48:30 -05001151 }
1152}
1153
Brian Salomonaff329b2017-08-11 09:40:37 -04001154std::unique_ptr<GrFragmentProcessor> GrContext::createUPMToPMEffect(
1155 std::unique_ptr<GrFragmentProcessor> fp, bool useConfigConversionEffect) {
joshualitt1de610a2016-01-06 08:26:09 -08001156 ASSERT_SINGLE_OWNER
Brian Osman2d2da4f2017-04-12 17:07:22 -04001157 // We have specialized effects that guarantee round-trip conversion for these formats
Brian Osman409e74f2017-04-17 11:48:28 -04001158 if (useConfigConversionEffect) {
1159 // We should have already called this->validPMUPMConversionExists() in this case
1160 SkASSERT(fDidTestPMConversions);
1161 // ...and it should have succeeded
1162 SkASSERT(this->validPMUPMConversionExists());
1163
Ethan Nicholasaae47c82017-11-10 15:34:03 -05001164 return GrConfigConversionEffect::Make(std::move(fp), PMConversion::kToPremul);
Brian Osman2d2da4f2017-04-12 17:07:22 -04001165 } else {
1166 // For everything else (sRGB, half-float, etc...), it doesn't make sense to try and
1167 // explicitly round the results. Just do the obvious, naive thing in the shader.
1168 return GrFragmentProcessor::PremulOutput(std::move(fp));
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001169 }
1170}
1171
Brian Osman409e74f2017-04-17 11:48:28 -04001172bool GrContext::validPMUPMConversionExists() {
joshualitt1de610a2016-01-06 08:26:09 -08001173 ASSERT_SINGLE_OWNER
Brian Osman409e74f2017-04-17 11:48:28 -04001174 if (!fDidTestPMConversions) {
Brian Osman28804f32017-04-20 10:24:36 -04001175 fPMUPMConversionsRoundTrip = GrConfigConversionEffect::TestForPreservingPMConversions(this);
Brian Osman409e74f2017-04-17 11:48:28 -04001176 fDidTestPMConversions = true;
1177 }
1178
bsalomon636e8022015-07-29 06:08:46 -07001179 // The PM<->UPM tests fail or succeed together so we only need to check one.
Brian Osman28804f32017-04-20 10:24:36 -04001180 return fPMUPMConversionsRoundTrip;
bsalomon636e8022015-07-29 06:08:46 -07001181}
1182
bsalomon37f9a262015-02-02 13:00:10 -08001183//////////////////////////////////////////////////////////////////////////////
1184
Robert Phillipsfc711a22018-02-13 17:03:00 -05001185// DDL TODO: remove 'maxResources'
Robert Phillips8d1e67e2017-12-04 13:48:14 -05001186void GrContext::getResourceCacheLimits(int* maxResources, size_t* maxResourceBytes) const {
joshualitt1de610a2016-01-06 08:26:09 -08001187 ASSERT_SINGLE_OWNER
Robert Phillips8d1e67e2017-12-04 13:48:14 -05001188 if (maxResources) {
1189 *maxResources = fResourceCache->getMaxResourceCount();
bsalomon37f9a262015-02-02 13:00:10 -08001190 }
Robert Phillips8d1e67e2017-12-04 13:48:14 -05001191 if (maxResourceBytes) {
1192 *maxResourceBytes = fResourceCache->getMaxResourceBytes();
bsalomon37f9a262015-02-02 13:00:10 -08001193 }
1194}
1195
Robert Phillips8d1e67e2017-12-04 13:48:14 -05001196void GrContext::setResourceCacheLimits(int maxResources, size_t maxResourceBytes) {
joshualitt1de610a2016-01-06 08:26:09 -08001197 ASSERT_SINGLE_OWNER
Robert Phillips8d1e67e2017-12-04 13:48:14 -05001198 fResourceCache->setLimits(maxResources, maxResourceBytes);
bsalomon37f9a262015-02-02 13:00:10 -08001199}
1200
ericrk0a5fa482015-09-15 14:16:10 -07001201//////////////////////////////////////////////////////////////////////////////
ericrk0a5fa482015-09-15 14:16:10 -07001202void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
joshualitt1de610a2016-01-06 08:26:09 -08001203 ASSERT_SINGLE_OWNER
ericrk0a5fa482015-09-15 14:16:10 -07001204 fResourceCache->dumpMemoryStatistics(traceMemoryDump);
1205}
Brian Osman71a18892017-08-10 10:23:25 -04001206
1207//////////////////////////////////////////////////////////////////////////////
1208
Robert Phillips0c4b7b12018-03-06 08:20:37 -05001209SkString GrContextPriv::dump() const {
Brian Osman71a18892017-08-10 10:23:25 -04001210 SkDynamicMemoryWStream stream;
1211 SkJSONWriter writer(&stream, SkJSONWriter::Mode::kPretty);
1212 writer.beginObject();
1213
1214 static const char* kBackendStr[] = {
1215 "Metal",
1216 "OpenGL",
1217 "Vulkan",
1218 "Mock",
1219 };
1220 GR_STATIC_ASSERT(0 == kMetal_GrBackend);
1221 GR_STATIC_ASSERT(1 == kOpenGL_GrBackend);
1222 GR_STATIC_ASSERT(2 == kVulkan_GrBackend);
1223 GR_STATIC_ASSERT(3 == kMock_GrBackend);
Robert Phillips0c4b7b12018-03-06 08:20:37 -05001224 writer.appendString("backend", kBackendStr[fContext->fBackend]);
Brian Osman71a18892017-08-10 10:23:25 -04001225
1226 writer.appendName("caps");
Robert Phillips0c4b7b12018-03-06 08:20:37 -05001227 fContext->fCaps->dumpJSON(&writer);
Brian Osman71a18892017-08-10 10:23:25 -04001228
1229 writer.appendName("gpu");
Robert Phillips0c4b7b12018-03-06 08:20:37 -05001230 fContext->fGpu->dumpJSON(&writer);
Brian Osman71a18892017-08-10 10:23:25 -04001231
1232 // Flush JSON to the memory stream
1233 writer.endObject();
1234 writer.flush();
1235
1236 // Null terminate the JSON data in the memory stream
1237 stream.write8(0);
1238
1239 // Allocate a string big enough to hold all the data, then copy out of the stream
1240 SkString result(stream.bytesWritten());
1241 stream.copyToAndReset(result.writable_str());
1242 return result;
1243}