blob: 5a5173c53086e1bc202a8f62967aacee42125355 [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"
bsalomon682c2692015-05-22 14:01:46 -07009#include "GrContextOptions.h"
robertphillips77a2e522015-10-17 07:43:27 -070010#include "GrDrawingManager.h"
robertphillipsea461502015-05-26 11:38:03 -070011#include "GrDrawContext.h"
bsalomon0ea80f42015-02-11 10:49:59 -080012#include "GrResourceCache.h"
bsalomond309e7a2015-04-30 14:18:54 -070013#include "GrResourceProvider.h"
robertphillips@google.com72176b22012-05-23 13:19:12 +000014#include "GrSoftwarePathRenderer.h"
bsalomonafbf2d62014-09-30 12:18:44 -070015#include "GrSurfacePriv.h"
robertphillips3dc6ae52015-10-20 09:54:32 -070016
bsalomon81beccc2014-10-13 12:32:55 -070017#include "SkConfig8888.h"
bsalomonf276ac52015-10-09 13:36:42 -070018#include "SkGrPriv.h"
joshualitt74417822015-08-07 11:42:16 -070019
bsalomonb8fea972016-02-16 07:34:17 -080020#include "batches/GrCopySurfaceBatch.h"
joshualitt5478d422014-11-14 16:00:38 -080021#include "effects/GrConfigConversionEffect.h"
brianosman2d1ee792016-05-05 12:24:31 -070022#include "effects/GrGammaEffect.h"
joshualitte8042922015-12-11 06:11:21 -080023#include "text/GrTextBlobCache.h"
joshualitt5478d422014-11-14 16:00:38 -080024
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000025#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
joshualitt1de610a2016-01-06 08:26:09 -080026#define ASSERT_SINGLE_OWNER \
27 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);)
robertphillips7761d612016-05-16 09:14:53 -070028#define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; }
29#define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; }
30#define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; }
bsalomon@google.combc4b6542011-11-19 13:56:11 +000031
robertphillipsea461502015-05-26 11:38:03 -070032////////////////////////////////////////////////////////////////////////////////
33
bsalomon682c2692015-05-22 14:01:46 -070034GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
35 GrContextOptions defaultOptions;
36 return Create(backend, backendContext, defaultOptions);
37}
bsalomonf28cff72015-05-22 12:25:41 -070038
bsalomon682c2692015-05-22 14:01:46 -070039GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
40 const GrContextOptions& options) {
halcanary385fe4d2015-08-26 13:07:48 -070041 GrContext* context = new GrContext;
bsalomon682c2692015-05-22 14:01:46 -070042
43 if (context->init(backend, backendContext, options)) {
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000044 return context;
45 } else {
46 context->unref();
halcanary96fcdcc2015-08-27 07:41:13 -070047 return nullptr;
bsalomon@google.com27847de2011-02-22 20:59:41 +000048 }
bsalomon@google.com27847de2011-02-22 20:59:41 +000049}
50
joshualitt0acd0d32015-05-07 08:23:19 -070051static int32_t gNextID = 1;
52static int32_t next_id() {
53 int32_t id;
54 do {
55 id = sk_atomic_inc(&gNextID);
56 } while (id == SK_InvalidGenID);
57 return id;
58}
59
bsalomon682c2692015-05-22 14:01:46 -070060GrContext::GrContext() : fUniqueID(next_id()) {
halcanary96fcdcc2015-08-27 07:41:13 -070061 fGpu = nullptr;
62 fCaps = nullptr;
63 fResourceCache = nullptr;
64 fResourceProvider = nullptr;
halcanary96fcdcc2015-08-27 07:41:13 -070065 fBatchFontCache = nullptr;
bsalomonf21dab92014-11-13 13:33:28 -080066 fFlushToReduceCacheSize = false;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000067}
68
bsalomon682c2692015-05-22 14:01:46 -070069bool GrContext::init(GrBackend backend, GrBackendContext backendContext,
70 const GrContextOptions& options) {
joshualitt1de610a2016-01-06 08:26:09 -080071 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -070072 SkASSERT(!fGpu);
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000073
bsalomon682c2692015-05-22 14:01:46 -070074 fGpu = GrGpu::Create(backend, backendContext, options, this);
robertphillipsea461502015-05-26 11:38:03 -070075 if (!fGpu) {
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000076 return false;
77 }
bsalomon69cfe952015-11-30 13:27:47 -080078 this->initCommon(options);
bsalomon33435572014-11-05 14:47:41 -080079 return true;
80}
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000081
bsalomon69cfe952015-11-30 13:27:47 -080082void GrContext::initCommon(const GrContextOptions& options) {
joshualitt1de610a2016-01-06 08:26:09 -080083 ASSERT_SINGLE_OWNER
84
bsalomon76228632015-05-29 08:02:10 -070085 fCaps = SkRef(fGpu->caps());
halcanary385fe4d2015-08-26 13:07:48 -070086 fResourceCache = new GrResourceCache(fCaps);
bsalomon0ea80f42015-02-11 10:49:59 -080087 fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
joshualitt6d0872d2016-01-11 08:27:48 -080088 fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner);
commit-bot@chromium.org1836d332013-07-16 22:55:03 +000089
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000090 fDidTestPMConversions = false;
91
bsalomon69cfe952015-11-30 13:27:47 -080092 GrDrawTarget::Options dtOptions;
93 dtOptions.fClipBatchToBounds = options.fClipBatchToBounds;
bsalomon6dea83f2015-12-03 12:58:06 -080094 dtOptions.fDrawBatchBounds = options.fDrawBatchBounds;
bsalomon489147c2015-12-14 12:13:09 -080095 dtOptions.fMaxBatchLookback = options.fMaxBatchLookback;
bsalomonaecc0182016-03-07 11:50:44 -080096 dtOptions.fMaxBatchLookahead = options.fMaxBatchLookahead;
joshualittde8dc7e2016-01-08 10:09:13 -080097 fDrawingManager.reset(new GrDrawingManager(this, dtOptions, &fSingleOwner));
joshualitt7c3a2f82015-03-31 13:32:05 -070098
99 // GrBatchFontCache will eventually replace GrFontCache
halcanary385fe4d2015-08-26 13:07:48 -0700100 fBatchFontCache = new GrBatchFontCache(this);
joshualittb7133be2015-04-08 09:08:31 -0700101
halcanary385fe4d2015-08-26 13:07:48 -0700102 fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this));
bsalomon@google.comc0af3172012-06-15 14:10:09 +0000103}
104
bsalomon@google.com27847de2011-02-22 20:59:41 +0000105GrContext::~GrContext() {
joshualitt1de610a2016-01-06 08:26:09 -0800106 ASSERT_SINGLE_OWNER
107
robertphillipsea461502015-05-26 11:38:03 -0700108 if (!fGpu) {
bsalomon76228632015-05-29 08:02:10 -0700109 SkASSERT(!fCaps);
bsalomon@google.com733c0622013-04-24 17:59:32 +0000110 return;
111 }
112
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000113 this->flush();
robertphillips@google.com5acc0e32012-05-17 12:01:02 +0000114
robertphillips77a2e522015-10-17 07:43:27 -0700115 fDrawingManager->cleanup();
robertphillips2334fb62015-06-17 05:43:33 -0700116
robertphillips@google.com950b1b02013-10-21 17:37:28 +0000117 for (int i = 0; i < fCleanUpData.count(); ++i) {
118 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
119 }
120
halcanary385fe4d2015-08-26 13:07:48 -0700121 delete fResourceProvider;
122 delete fResourceCache;
123 delete fBatchFontCache;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000124
bsalomon@google.com205d4602011-04-25 12:43:45 +0000125 fGpu->unref();
bsalomon76228632015-05-29 08:02:10 -0700126 fCaps->unref();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000127}
128
bsalomon41b952c2016-03-11 06:46:33 -0800129GrContextThreadSafeProxy* GrContext::threadSafeProxy() {
130 if (!fThreadSafeProxy) {
131 fThreadSafeProxy.reset(new GrContextThreadSafeProxy(fCaps, this->uniqueID()));
132 }
133 return SkRef(fThreadSafeProxy.get());
134}
135
bsalomon2354f842014-07-28 13:48:36 -0700136void GrContext::abandonContext() {
joshualitt1de610a2016-01-06 08:26:09 -0800137 ASSERT_SINGLE_OWNER
138
bsalomond309e7a2015-04-30 14:18:54 -0700139 fResourceProvider->abandon();
robertphillips0dfa62c2015-11-16 06:23:31 -0800140
141 // Need to abandon the drawing manager first so all the render targets
142 // will be released/forgotten before they too are abandoned.
143 fDrawingManager->abandon();
144
bsalomon@google.com205d4602011-04-25 12:43:45 +0000145 // abandon first to so destructors
146 // don't try to free the resources in the API.
bsalomon0ea80f42015-02-11 10:49:59 -0800147 fResourceCache->abandonAll();
bsalomonc8dc1f72014-08-21 13:02:13 -0700148
bsalomon6e2aad42016-04-01 11:54:31 -0700149 fGpu->disconnect(GrGpu::DisconnectType::kAbandon);
150
151 fBatchFontCache->freeAll();
bsalomon6e2aad42016-04-01 11:54:31 -0700152 fTextBlobCache->freeAll();
153}
154
155void GrContext::releaseResourcesAndAbandonContext() {
156 ASSERT_SINGLE_OWNER
157
158 fResourceProvider->abandon();
159
160 // Need to abandon the drawing manager first so all the render targets
161 // will be released/forgotten before they too are abandoned.
162 fDrawingManager->abandon();
163
164 // Release all resources in the backend 3D API.
165 fResourceCache->releaseAll();
166
167 fGpu->disconnect(GrGpu::DisconnectType::kCleanup);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000168
joshualitt7c3a2f82015-03-31 13:32:05 -0700169 fBatchFontCache->freeAll();
joshualitt26ffc002015-04-16 11:24:04 -0700170 fTextBlobCache->freeAll();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000171}
172
bsalomon@google.com0a208a12013-06-28 18:57:35 +0000173void GrContext::resetContext(uint32_t state) {
joshualitt1de610a2016-01-06 08:26:09 -0800174 ASSERT_SINGLE_OWNER
bsalomon@google.com0a208a12013-06-28 18:57:35 +0000175 fGpu->markContextDirty(state);
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000176}
177
178void GrContext::freeGpuResources() {
joshualitt1de610a2016-01-06 08:26:09 -0800179 ASSERT_SINGLE_OWNER
180
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000181 this->flush();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000182
joshualitt7c3a2f82015-03-31 13:32:05 -0700183 fBatchFontCache->freeAll();
robertphillips68737822015-10-29 12:12:21 -0700184
185 fDrawingManager->freeGpuResources();
bsalomon3033b9f2015-04-13 11:09:56 -0700186
187 fResourceCache->purgeAllUnlocked();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000188}
189
commit-bot@chromium.org95c20032014-05-09 14:29:32 +0000190void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
joshualitt1de610a2016-01-06 08:26:09 -0800191 ASSERT_SINGLE_OWNER
192
bsalomon71cb0c22014-11-14 12:10:14 -0800193 if (resourceCount) {
bsalomon0ea80f42015-02-11 10:49:59 -0800194 *resourceCount = fResourceCache->getBudgetedResourceCount();
bsalomon71cb0c22014-11-14 12:10:14 -0800195 }
196 if (resourceBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -0800197 *resourceBytes = fResourceCache->getBudgetedResourceBytes();
bsalomon71cb0c22014-11-14 12:10:14 -0800198 }
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000199}
200
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000201////////////////////////////////////////////////////////////////////////////////
202
bsalomon71cb0c22014-11-14 12:10:14 -0800203void GrContext::OverBudgetCB(void* data) {
bsalomon66a450f2014-11-13 13:19:10 -0800204 SkASSERT(data);
bsalomonf21dab92014-11-13 13:33:28 -0800205
bsalomon66a450f2014-11-13 13:19:10 -0800206 GrContext* context = reinterpret_cast<GrContext*>(data);
bsalomonf21dab92014-11-13 13:33:28 -0800207
joshualittb542bae2015-07-28 09:58:39 -0700208 // Flush the GrBufferedDrawTarget to possibly free up some textures
bsalomonf21dab92014-11-13 13:33:28 -0800209 context->fFlushToReduceCacheSize = true;
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000210}
211
joshualitt0db6dfa2015-04-10 07:01:30 -0700212void GrContext::TextBlobCacheOverBudgetCB(void* data) {
213 SkASSERT(data);
214
215 // Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level, therefore they
216 // cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush. The solution is to move
217 // drawText calls to below the GrContext level, but this is not trivial because they call
218 // drawPath on SkGpuDevice
219 GrContext* context = reinterpret_cast<GrContext*>(data);
220 context->flush();
221}
222
bsalomon@google.com27847de2011-02-22 20:59:41 +0000223////////////////////////////////////////////////////////////////////////////////
224
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000225void GrContext::flush(int flagsBitfield) {
joshualitt1de610a2016-01-06 08:26:09 -0800226 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700227 RETURN_IF_ABANDONED
robertphillips@google.come7db8d62013-07-04 11:48:52 +0000228
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000229 if (kDiscard_FlushBit & flagsBitfield) {
robertphillips77a2e522015-10-17 07:43:27 -0700230 fDrawingManager->reset();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000231 } else {
robertphillips77a2e522015-10-17 07:43:27 -0700232 fDrawingManager->flush();
junov@google.com53a55842011-06-08 22:55:10 +0000233 }
bsalomon3f324322015-04-08 11:01:54 -0700234 fResourceCache->notifyFlushOccurred();
bsalomonf21dab92014-11-13 13:33:28 -0800235 fFlushToReduceCacheSize = false;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000236}
237
bsalomon81beccc2014-10-13 12:32:55 -0700238bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
239 const void* inPixels, size_t outRowBytes, void* outPixels) {
240 SkSrcPixelInfo srcPI;
brianosman396fcdb2016-07-22 06:26:11 -0700241 if (!GrPixelConfigToColorType(srcConfig, &srcPI.fColorType)) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000242 return false;
243 }
bsalomon81beccc2014-10-13 12:32:55 -0700244 srcPI.fAlphaType = kUnpremul_SkAlphaType;
245 srcPI.fPixels = inPixels;
246 srcPI.fRowBytes = inRowBytes;
247
248 SkDstPixelInfo dstPI;
249 dstPI.fColorType = srcPI.fColorType;
250 dstPI.fAlphaType = kPremul_SkAlphaType;
251 dstPI.fPixels = outPixels;
252 dstPI.fRowBytes = outRowBytes;
253
254 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000255}
256
bsalomon81beccc2014-10-13 12:32:55 -0700257bool GrContext::writeSurfacePixels(GrSurface* surface,
258 int left, int top, int width, int height,
259 GrPixelConfig srcConfig, const void* buffer, size_t rowBytes,
260 uint32_t pixelOpsFlags) {
joshualitt1de610a2016-01-06 08:26:09 -0800261 ASSERT_SINGLE_OWNER
joshualitt5f5a8d72015-02-25 14:09:45 -0800262 RETURN_FALSE_IF_ABANDONED
bsalomon6c6f6582015-09-10 08:12:46 -0700263 ASSERT_OWNED_RESOURCE(surface);
264 SkASSERT(surface);
joshualittbc907352016-01-13 06:45:40 -0800265 GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::writeSurfacePixels");
bsalomon6c6f6582015-09-10 08:12:46 -0700266
267 this->testPMConversionsIfNecessary(pixelOpsFlags);
bsalomon81beccc2014-10-13 12:32:55 -0700268
bsalomone8d21e82015-07-16 08:23:13 -0700269 // 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 -0700270 // necessary and because GrGpu::getWritePixelsInfo requires it.
bsalomone8d21e82015-07-16 08:23:13 -0700271 if (!GrSurfacePriv::AdjustWritePixelParams(surface->width(), surface->height(),
272 GrBytesPerPixel(srcConfig), &left, &top, &width,
273 &height, &buffer, &rowBytes)) {
274 return false;
275 }
276
bsalomonf0674512015-07-28 13:26:15 -0700277 bool applyPremulToSrc = false;
bsalomon81beccc2014-10-13 12:32:55 -0700278 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) {
279 if (!GrPixelConfigIs8888(srcConfig)) {
280 return false;
281 }
bsalomonf0674512015-07-28 13:26:15 -0700282 applyPremulToSrc = true;
283 }
bsalomon636e8022015-07-29 06:08:46 -0700284
285 GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
286 // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
287 // we've already determined that there isn't a roundtrip preserving conversion processor pair.
288 if (applyPremulToSrc && !this->didFailPMUPMConversionTest()) {
289 drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference;
290 }
291
bsalomonf0674512015-07-28 13:26:15 -0700292 GrGpu::WritePixelTempDrawInfo tempDrawInfo;
cblumeed828002016-02-16 13:00:01 -0800293 if (!fGpu->getWritePixelsInfo(surface, width, height, srcConfig, &drawPreference,
bsalomonf0674512015-07-28 13:26:15 -0700294 &tempDrawInfo)) {
295 return false;
296 }
297
298 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && surface->surfacePriv().hasPendingIO()) {
299 this->flush();
300 }
301
302 SkAutoTUnref<GrTexture> tempTexture;
303 if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
bsalomoneae62002015-07-31 13:59:30 -0700304 tempTexture.reset(
305 this->textureProvider()->createApproxTexture(tempDrawInfo.fTempSurfaceDesc));
bsalomonf0674512015-07-28 13:26:15 -0700306 if (!tempTexture && GrGpu::kRequireDraw_DrawPreference == drawPreference) {
307 return false;
308 }
309 }
310
311 // temp buffer for doing sw premul conversion, if needed.
312 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
313 if (tempTexture) {
bungeman06ca8ec2016-06-09 08:01:03 -0700314 sk_sp<GrFragmentProcessor> fp;
bsalomonf0674512015-07-28 13:26:15 -0700315 SkMatrix textureMatrix;
316 textureMatrix.setIDiv(tempTexture->width(), tempTexture->height());
bsalomonf0674512015-07-28 13:26:15 -0700317 if (applyPremulToSrc) {
bungeman06ca8ec2016-06-09 08:01:03 -0700318 fp = this->createUPMToPMEffect(tempTexture, tempDrawInfo.fSwizzle, textureMatrix);
bsalomonf0674512015-07-28 13:26:15 -0700319 // If premultiplying was the only reason for the draw, fall back to a straight write.
320 if (!fp) {
321 if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
halcanary96fcdcc2015-08-27 07:41:13 -0700322 tempTexture.reset(nullptr);
bsalomonf0674512015-07-28 13:26:15 -0700323 }
324 } else {
325 applyPremulToSrc = false;
326 }
327 }
328 if (tempTexture) {
329 if (!fp) {
bungeman06ca8ec2016-06-09 08:01:03 -0700330 fp = GrConfigConversionEffect::Make(tempTexture, tempDrawInfo.fSwizzle,
331 GrConfigConversionEffect::kNone_PMConversion,
332 textureMatrix);
bsalomonf0674512015-07-28 13:26:15 -0700333 if (!fp) {
334 return false;
335 }
336 }
337 GrRenderTarget* renderTarget = surface->asRenderTarget();
338 SkASSERT(renderTarget);
339 if (tempTexture->surfacePriv().hasPendingIO()) {
340 this->flush();
341 }
342 if (applyPremulToSrc) {
343 size_t tmpRowBytes = 4 * width;
344 tmpPixels.reset(width * height);
345 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
346 tmpPixels.get())) {
347 return false;
348 }
349 rowBytes = tmpRowBytes;
350 buffer = tmpPixels.get();
351 applyPremulToSrc = false;
352 }
bsalomon6cb3cbe2015-07-30 07:34:27 -0700353 if (!fGpu->writePixels(tempTexture, 0, 0, width, height,
bsalomon6c9cd552016-01-22 07:17:34 -0800354 tempDrawInfo.fWriteConfig, buffer,
bsalomon6cb3cbe2015-07-30 07:34:27 -0700355 rowBytes)) {
bsalomonf0674512015-07-28 13:26:15 -0700356 return false;
357 }
358 SkMatrix matrix;
359 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
brianosmandfe4f2e2016-07-21 13:28:36 -0700360 // TODO: Need to decide the semantics of this function for color spaces. Do we support
361 // conversion from a passed-in color space? For now, specifying nullptr means that this
362 // path will do no conversion, so it will match the behavior of the non-draw path.
363 sk_sp<GrDrawContext> drawContext(this->drawContext(sk_ref_sp(renderTarget), nullptr));
bsalomonf0674512015-07-28 13:26:15 -0700364 if (!drawContext) {
365 return false;
366 }
egdanielc4b72722015-11-23 13:20:41 -0800367 GrPaint paint;
bungeman06ca8ec2016-06-09 08:01:03 -0700368 paint.addColorFragmentProcessor(std::move(fp));
egdanielc4b72722015-11-23 13:20:41 -0800369 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
brianosmana167e742016-05-24 06:18:48 -0700370 paint.setAllowSRGBInputs(true);
bsalomonf0674512015-07-28 13:26:15 -0700371 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
cdalton846c0512016-05-13 10:25:00 -0700372 drawContext->drawRect(GrNoClip(), paint, matrix, rect, nullptr);
bsalomonf0674512015-07-28 13:26:15 -0700373
374 if (kFlushWrites_PixelOp & pixelOpsFlags) {
375 this->flushSurfaceWrites(surface);
376 }
377 }
378 }
379 if (!tempTexture) {
bsalomonf0674512015-07-28 13:26:15 -0700380 if (applyPremulToSrc) {
bsalomon81beccc2014-10-13 12:32:55 -0700381 size_t tmpRowBytes = 4 * width;
382 tmpPixels.reset(width * height);
383 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
384 tmpPixels.get())) {
385 return false;
386 }
387 rowBytes = tmpRowBytes;
388 buffer = tmpPixels.get();
bsalomonf0674512015-07-28 13:26:15 -0700389 applyPremulToSrc = false;
bsalomon81beccc2014-10-13 12:32:55 -0700390 }
bsalomon6cb3cbe2015-07-30 07:34:27 -0700391 return fGpu->writePixels(surface, left, top, width, height, srcConfig, buffer, rowBytes);
bsalomon81beccc2014-10-13 12:32:55 -0700392 }
bsalomon81beccc2014-10-13 12:32:55 -0700393 return true;
394}
bsalomon@google.coma91e9232012-02-23 15:39:54 +0000395
bsalomone8d21e82015-07-16 08:23:13 -0700396bool GrContext::readSurfacePixels(GrSurface* src,
397 int left, int top, int width, int height,
398 GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
399 uint32_t flags) {
joshualitt1de610a2016-01-06 08:26:09 -0800400 ASSERT_SINGLE_OWNER
joshualitt5f5a8d72015-02-25 14:09:45 -0800401 RETURN_FALSE_IF_ABANDONED
bsalomone8d21e82015-07-16 08:23:13 -0700402 ASSERT_OWNED_RESOURCE(src);
403 SkASSERT(src);
joshualittbc907352016-01-13 06:45:40 -0800404 GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::readSurfacePixels");
bsalomon32ab2602015-09-09 18:57:49 -0700405
bsalomon6c6f6582015-09-10 08:12:46 -0700406 this->testPMConversionsIfNecessary(flags);
407 SkAutoMutexAcquire ama(fReadPixelsMutex);
408
bsalomone8d21e82015-07-16 08:23:13 -0700409 // Adjust the params so that if we wind up using an intermediate surface we've already done
410 // all the trimming and the temporary can be the min size required.
411 if (!GrSurfacePriv::AdjustReadPixelParams(src->width(), src->height(),
412 GrBytesPerPixel(dstConfig), &left,
413 &top, &width, &height, &buffer, &rowBytes)) {
414 return false;
415 }
416
417 if (!(kDontFlush_PixelOpsFlag & flags) && src->surfacePriv().hasPendingWrite()) {
bsalomon@google.com6f379512011-11-16 20:36:03 +0000418 this->flush();
419 }
bsalomon@google.comc4364992011-11-07 15:54:49 +0000420
bsalomone8d21e82015-07-16 08:23:13 -0700421 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
bsalomon@google.com9c680582013-02-06 18:17:50 +0000422 if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
bsalomon39826022015-07-23 08:07:21 -0700423 // The unpremul flag is only allowed for 8888 configs.
bsalomon@google.com0a97be22011-11-08 19:20:57 +0000424 return false;
425 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000426
bsalomon636e8022015-07-29 06:08:46 -0700427 GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
428 // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
429 // we've already determined that there isn't a roundtrip preserving conversion processor pair.
430 if (unpremul && !this->didFailPMUPMConversionTest()) {
431 drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference;
432 }
433
bsalomon39826022015-07-23 08:07:21 -0700434 GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
435 if (!fGpu->getReadPixelsInfo(src, width, height, rowBytes, dstConfig, &drawPreference,
436 &tempDrawInfo)) {
437 return false;
438 }
bsalomon191bcc02014-11-14 11:31:13 -0800439
bsalomon6cb3cbe2015-07-30 07:34:27 -0700440 SkAutoTUnref<GrSurface> surfaceToRead(SkRef(src));
bsalomon39826022015-07-23 08:07:21 -0700441 bool didTempDraw = false;
442 if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
bsalomonb117ff12016-07-19 07:24:40 -0700443 if (SkBackingFit::kExact == tempDrawInfo.fTempSurfaceFit) {
bsalomon39826022015-07-23 08:07:21 -0700444 // We only respect this when the entire src is being read. Otherwise we can trigger too
445 // many odd ball texture sizes and trash the cache.
bsalomoneae62002015-07-31 13:59:30 -0700446 if (width != src->width() || height != src->height()) {
bsalomonb117ff12016-07-19 07:24:40 -0700447 tempDrawInfo.fTempSurfaceFit= SkBackingFit::kApprox;
bsalomon39826022015-07-23 08:07:21 -0700448 }
bsalomon@google.com56d11e02011-11-30 19:59:08 +0000449 }
brianosmandfe4f2e2016-07-21 13:28:36 -0700450 // TODO: Need to decide the semantics of this function for color spaces. Do we support
451 // conversion to a passed-in color space? For now, specifying nullptr means that this
452 // path will do no conversion, so it will match the behavior of the non-draw path.
bsalomonb117ff12016-07-19 07:24:40 -0700453 sk_sp<GrDrawContext> tempDC = this->newDrawContext(tempDrawInfo.fTempSurfaceFit,
454 tempDrawInfo.fTempSurfaceDesc.fWidth,
455 tempDrawInfo.fTempSurfaceDesc.fHeight,
456 tempDrawInfo.fTempSurfaceDesc.fConfig,
brianosmandfe4f2e2016-07-21 13:28:36 -0700457 nullptr,
bsalomonb117ff12016-07-19 07:24:40 -0700458 tempDrawInfo.fTempSurfaceDesc.fSampleCnt,
459 tempDrawInfo.fTempSurfaceDesc.fOrigin);
460 if (tempDC) {
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000461 SkMatrix textureMatrix;
bsalomon39826022015-07-23 08:07:21 -0700462 textureMatrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000463 textureMatrix.postIDiv(src->width(), src->height());
bungeman06ca8ec2016-06-09 08:01:03 -0700464 sk_sp<GrFragmentProcessor> fp;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000465 if (unpremul) {
bungeman06ca8ec2016-06-09 08:01:03 -0700466 fp = this->createPMToUPMEffect(src->asTexture(), tempDrawInfo.fSwizzle,
467 textureMatrix);
joshualittb0a8a372014-09-23 09:50:21 -0700468 if (fp) {
bsalomon@google.com9c680582013-02-06 18:17:50 +0000469 unpremul = false; // we no longer need to do this on CPU after the read back.
bsalomon39826022015-07-23 08:07:21 -0700470 } else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
471 // We only wanted to do the draw in order to perform the unpremul so don't
472 // bother.
bsalomonb117ff12016-07-19 07:24:40 -0700473 tempDC.reset(nullptr);
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000474 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000475 }
bsalomonb117ff12016-07-19 07:24:40 -0700476 if (!fp && tempDC) {
bungeman06ca8ec2016-06-09 08:01:03 -0700477 fp = GrConfigConversionEffect::Make(src->asTexture(), tempDrawInfo.fSwizzle,
478 GrConfigConversionEffect::kNone_PMConversion,
479 textureMatrix);
bsalomon39826022015-07-23 08:07:21 -0700480 }
481 if (fp) {
egdanielc4b72722015-11-23 13:20:41 -0800482 GrPaint paint;
bungeman06ca8ec2016-06-09 08:01:03 -0700483 paint.addColorFragmentProcessor(std::move(fp));
egdanielc4b72722015-11-23 13:20:41 -0800484 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
brianosmana167e742016-05-24 06:18:48 -0700485 paint.setAllowSRGBInputs(true);
bsalomon39826022015-07-23 08:07:21 -0700486 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
bsalomonb117ff12016-07-19 07:24:40 -0700487 tempDC->drawRect(GrNoClip(), paint, SkMatrix::I(), rect, nullptr);
488 surfaceToRead.reset(tempDC->asTexture().release());
bsalomon39826022015-07-23 08:07:21 -0700489 left = 0;
490 top = 0;
491 didTempDraw = true;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000492 }
bsalomon@google.com0342a852012-08-20 19:22:38 +0000493 }
bsalomon@google.comc4364992011-11-07 15:54:49 +0000494 }
joshualitt5c55fef2014-10-31 14:04:35 -0700495
bsalomon39826022015-07-23 08:07:21 -0700496 if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000497 return false;
498 }
bsalomon39826022015-07-23 08:07:21 -0700499 GrPixelConfig configToRead = dstConfig;
500 if (didTempDraw) {
bsalomon6cb3cbe2015-07-30 07:34:27 -0700501 this->flushSurfaceWrites(surfaceToRead);
bsalomon6c9cd552016-01-22 07:17:34 -0800502 configToRead = tempDrawInfo.fReadConfig;
bsalomon39826022015-07-23 08:07:21 -0700503 }
bsalomon6cb3cbe2015-07-30 07:34:27 -0700504 if (!fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead, buffer,
505 rowBytes)) {
bsalomon39826022015-07-23 08:07:21 -0700506 return false;
507 }
508
509 // Perform umpremul conversion if we weren't able to perform it as a draw.
510 if (unpremul) {
reed@google.com7111d462014-03-25 16:20:24 +0000511 SkDstPixelInfo dstPI;
brianosman396fcdb2016-07-22 06:26:11 -0700512 if (!GrPixelConfigToColorType(dstConfig, &dstPI.fColorType)) {
reed@google.com7111d462014-03-25 16:20:24 +0000513 return false;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000514 }
reed@google.com7111d462014-03-25 16:20:24 +0000515 dstPI.fAlphaType = kUnpremul_SkAlphaType;
516 dstPI.fPixels = buffer;
517 dstPI.fRowBytes = rowBytes;
518
519 SkSrcPixelInfo srcPI;
bsalomon39826022015-07-23 08:07:21 -0700520 srcPI.fColorType = dstPI.fColorType;
reed@google.com7111d462014-03-25 16:20:24 +0000521 srcPI.fAlphaType = kPremul_SkAlphaType;
522 srcPI.fPixels = buffer;
523 srcPI.fRowBytes = rowBytes;
524
525 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000526 }
527 return true;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000528}
529
brianosman2d1ee792016-05-05 12:24:31 -0700530bool GrContext::applyGamma(GrRenderTarget* dst, GrTexture* src, SkScalar gamma){
531 ASSERT_SINGLE_OWNER
532 RETURN_FALSE_IF_ABANDONED
533 ASSERT_OWNED_RESOURCE(dst);
534 ASSERT_OWNED_RESOURCE(src);
535 GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::applyGamma");
536
537 // Dimensions must match exactly.
538 if (dst->width() != src->width() || dst->height() != src->height()) {
539 return false;
540 }
541
542 SkSurfaceProps props(SkSurfaceProps::kGammaCorrect_Flag,
543 SkSurfaceProps::kLegacyFontHost_InitType);
brianosmandfe4f2e2016-07-21 13:28:36 -0700544 // TODO: Supply color space?
545 sk_sp<GrDrawContext> drawContext(this->drawContext(sk_ref_sp(dst), nullptr, &props));
brianosman2d1ee792016-05-05 12:24:31 -0700546 if (!drawContext) {
547 return false;
548 }
549
550 GrPaint paint;
brianosman54f30c12016-07-18 10:53:52 -0700551 paint.addColorTextureProcessor(src, nullptr, GrCoordTransform::MakeDivByTextureWHMatrix(src));
brianosmanfe4d5d32016-05-11 06:49:32 -0700552 if (!SkScalarNearlyEqual(gamma, 1.0f)) {
bungeman06ca8ec2016-06-09 08:01:03 -0700553 paint.addColorFragmentProcessor(GrGammaEffect::Make(gamma));
brianosman2d1ee792016-05-05 12:24:31 -0700554 }
555 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
556 paint.setGammaCorrect(true);
557
558 SkRect rect;
559 src->getBoundsRect(&rect);
cdalton846c0512016-05-13 10:25:00 -0700560 drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), rect);
brianosman2d1ee792016-05-05 12:24:31 -0700561
562 this->flushSurfaceWrites(dst);
563 return true;
564}
565
bsalomonc49e8682015-06-30 11:37:35 -0700566void GrContext::prepareSurfaceForExternalIO(GrSurface* surface) {
joshualitt1de610a2016-01-06 08:26:09 -0800567 ASSERT_SINGLE_OWNER
joshualitt5f5a8d72015-02-25 14:09:45 -0800568 RETURN_IF_ABANDONED
bsalomon87a94eb2014-11-03 14:28:32 -0800569 SkASSERT(surface);
570 ASSERT_OWNED_RESOURCE(surface);
571 if (surface->surfacePriv().hasPendingIO()) {
572 this->flush();
573 }
574 GrRenderTarget* rt = surface->asRenderTarget();
575 if (fGpu && rt) {
576 fGpu->resolveRenderTarget(rt);
bsalomon41ebbdd2014-08-04 08:31:39 -0700577 }
bsalomon@google.com75f9f252012-01-31 13:35:56 +0000578}
579
bsalomonb8fea972016-02-16 07:34:17 -0800580bool GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
581 const SkIPoint& dstPoint) {
joshualitt1de610a2016-01-06 08:26:09 -0800582 ASSERT_SINGLE_OWNER
bsalomonb8fea972016-02-16 07:34:17 -0800583 RETURN_FALSE_IF_ABANDONED
joshualittbc907352016-01-13 06:45:40 -0800584 GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::copySurface");
585
robertphillipsea461502015-05-26 11:38:03 -0700586 if (!src || !dst) {
bsalomonb8fea972016-02-16 07:34:17 -0800587 return false;
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000588 }
bsalomone3d4bf22014-09-23 09:15:03 -0700589 ASSERT_OWNED_RESOURCE(src);
junov2bb52102014-09-29 10:18:59 -0700590 ASSERT_OWNED_RESOURCE(dst);
Brian Salomon34a98952014-09-24 11:41:24 -0400591
robertphillipsea461502015-05-26 11:38:03 -0700592 if (!dst->asRenderTarget()) {
bsalomonb8fea972016-02-16 07:34:17 -0800593 SkIRect clippedSrcRect;
594 SkIPoint clippedDstPoint;
595 if (!GrCopySurfaceBatch::ClipSrcRectAndDstPoint(dst, src, srcRect, dstPoint,
596 &clippedSrcRect, &clippedDstPoint)) {
597 return false;
598 }
599 // If we don't have an RT for the dst then we won't have a GrDrawContext to insert the
600 // the copy surface into. In the future we plan to have a more limited Context type
601 // (GrCopyContext?) that has the subset of GrDrawContext operations that should be
602 // allowed on textures that aren't render targets.
603 // For now we just flush any writes to the src and issue an immediate copy to the dst.
604 src->flushWrites();
605 return fGpu->copySurface(dst, src, clippedSrcRect, clippedDstPoint);
robertphillipsea461502015-05-26 11:38:03 -0700606 }
brianosmandfe4f2e2016-07-21 13:28:36 -0700607 sk_sp<GrDrawContext> drawContext(this->drawContext(sk_ref_sp(dst->asRenderTarget()), nullptr));
kjlubick0eed9452016-02-11 12:05:24 -0800608 if (!drawContext) {
bsalomonb8fea972016-02-16 07:34:17 -0800609 return false;
bsalomonf80bfed2014-10-07 05:56:02 -0700610 }
kjlubick0eed9452016-02-11 12:05:24 -0800611
bsalomonb8fea972016-02-16 07:34:17 -0800612 if (!drawContext->copySurface(src, srcRect, dstPoint)) {
613 return false;
kjlubick0eed9452016-02-11 12:05:24 -0800614 }
bsalomonb8fea972016-02-16 07:34:17 -0800615 return true;
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000616}
617
bsalomonf80bfed2014-10-07 05:56:02 -0700618void GrContext::flushSurfaceWrites(GrSurface* surface) {
joshualitt1de610a2016-01-06 08:26:09 -0800619 ASSERT_SINGLE_OWNER
joshualitt5f5a8d72015-02-25 14:09:45 -0800620 RETURN_IF_ABANDONED
bsalomonf80bfed2014-10-07 05:56:02 -0700621 if (surface->surfacePriv().hasPendingWrite()) {
622 this->flush();
623 }
624}
625
bsalomon@google.com27847de2011-02-22 20:59:41 +0000626////////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000627int GrContext::getRecommendedSampleCount(GrPixelConfig config,
628 SkScalar dpi) const {
joshualitt1de610a2016-01-06 08:26:09 -0800629 ASSERT_SINGLE_OWNER
630
bsalomon76228632015-05-29 08:02:10 -0700631 if (!this->caps()->isConfigRenderable(config, true)) {
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000632 return 0;
633 }
634 int chosenSampleCount = 0;
jvanverthe9c0fc62015-04-29 11:18:05 -0700635 if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) {
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000636 if (dpi >= 250.0f) {
637 chosenSampleCount = 4;
638 } else {
639 chosenSampleCount = 16;
640 }
641 }
egdanieleed519e2016-01-15 11:36:18 -0800642 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? chosenSampleCount : 0;
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000643}
644
robertphillips77a2e522015-10-17 07:43:27 -0700645
robertphillips6c7e3252016-04-27 10:47:51 -0700646sk_sp<GrDrawContext> GrContext::drawContext(sk_sp<GrRenderTarget> rt,
brianosmandfe4f2e2016-07-21 13:28:36 -0700647 sk_sp<SkColorSpace> colorSpace,
robertphillips6c7e3252016-04-27 10:47:51 -0700648 const SkSurfaceProps* surfaceProps) {
joshualitt1de610a2016-01-06 08:26:09 -0800649 ASSERT_SINGLE_OWNER
brianosmandfe4f2e2016-07-21 13:28:36 -0700650 return fDrawingManager->drawContext(std::move(rt), std::move(colorSpace), surfaceProps);
robertphillips77a2e522015-10-17 07:43:27 -0700651}
652
robertphillips76948d42016-05-04 12:47:41 -0700653sk_sp<GrDrawContext> GrContext::newDrawContext(SkBackingFit fit,
robertphillipsd4c741e2016-04-28 09:55:15 -0700654 int width, int height,
655 GrPixelConfig config,
brianosmandfe4f2e2016-07-21 13:28:36 -0700656 sk_sp<SkColorSpace> colorSpace,
robertphillipsd4c741e2016-04-28 09:55:15 -0700657 int sampleCnt,
robertphillipsa8966a82016-05-09 06:45:37 -0700658 GrSurfaceOrigin origin,
robertphillipsca6eafc2016-05-17 09:57:46 -0700659 const SkSurfaceProps* surfaceProps,
660 SkBudgeted budgeted) {
robertphillipsd4c741e2016-04-28 09:55:15 -0700661 GrSurfaceDesc desc;
662 desc.fFlags = kRenderTarget_GrSurfaceFlag;
663 desc.fOrigin = origin;
664 desc.fWidth = width;
665 desc.fHeight = height;
666 desc.fConfig = config;
667 desc.fSampleCnt = sampleCnt;
668
669 sk_sp<GrTexture> tex;
robertphillips76948d42016-05-04 12:47:41 -0700670 if (SkBackingFit::kExact == fit) {
robertphillipsca6eafc2016-05-17 09:57:46 -0700671 tex.reset(this->textureProvider()->createTexture(desc, budgeted));
robertphillipsd4c741e2016-04-28 09:55:15 -0700672 } else {
673 tex.reset(this->textureProvider()->createApproxTexture(desc));
674 }
675 if (!tex) {
676 return nullptr;
677 }
678
robertphillipsa8966a82016-05-09 06:45:37 -0700679 sk_sp<GrDrawContext> drawContext(this->drawContext(sk_ref_sp(tex->asRenderTarget()),
brianosmandfe4f2e2016-07-21 13:28:36 -0700680 std::move(colorSpace), surfaceProps));
robertphillipsd4c741e2016-04-28 09:55:15 -0700681 if (!drawContext) {
682 return nullptr;
683 }
684
685 return drawContext;
686}
687
joshualitt1de610a2016-01-06 08:26:09 -0800688bool GrContext::abandoned() const {
689 ASSERT_SINGLE_OWNER
robertphillips7761d612016-05-16 09:14:53 -0700690 return fDrawingManager->wasAbandoned();
robertphillips77a2e522015-10-17 07:43:27 -0700691}
692
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000693namespace {
694void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
695 GrConfigConversionEffect::PMConversion pmToUPM;
696 GrConfigConversionEffect::PMConversion upmToPM;
697 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
698 *pmToUPMValue = pmToUPM;
699 *upmToPMValue = upmToPM;
700}
701}
702
bsalomon6c6f6582015-09-10 08:12:46 -0700703void GrContext::testPMConversionsIfNecessary(uint32_t flags) {
joshualitt1de610a2016-01-06 08:26:09 -0800704 ASSERT_SINGLE_OWNER
bsalomon6c6f6582015-09-10 08:12:46 -0700705 if (SkToBool(kUnpremul_PixelOpsFlag & flags)) {
706 SkAutoMutexAcquire ama(fTestPMConversionsMutex);
707 if (!fDidTestPMConversions) {
708 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
709 fDidTestPMConversions = true;
710 }
711 }
712}
713
bungeman06ca8ec2016-06-09 08:01:03 -0700714sk_sp<GrFragmentProcessor> GrContext::createPMToUPMEffect(GrTexture* texture,
bsalomon6c9cd552016-01-22 07:17:34 -0800715 const GrSwizzle& swizzle,
bsalomon6c6f6582015-09-10 08:12:46 -0700716 const SkMatrix& matrix) const {
joshualitt1de610a2016-01-06 08:26:09 -0800717 ASSERT_SINGLE_OWNER
bsalomon6c6f6582015-09-10 08:12:46 -0700718 // We should have already called this->testPMConversionsIfNecessary().
719 SkASSERT(fDidTestPMConversions);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000720 GrConfigConversionEffect::PMConversion pmToUPM =
721 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
722 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
bungeman06ca8ec2016-06-09 08:01:03 -0700723 return GrConfigConversionEffect::Make(texture, swizzle, pmToUPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000724 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700725 return nullptr;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000726 }
727}
728
bungeman06ca8ec2016-06-09 08:01:03 -0700729sk_sp<GrFragmentProcessor> GrContext::createUPMToPMEffect(GrTexture* texture,
bsalomon6c9cd552016-01-22 07:17:34 -0800730 const GrSwizzle& swizzle,
bsalomon6c6f6582015-09-10 08:12:46 -0700731 const SkMatrix& matrix) const {
joshualitt1de610a2016-01-06 08:26:09 -0800732 ASSERT_SINGLE_OWNER
bsalomon6c6f6582015-09-10 08:12:46 -0700733 // We should have already called this->testPMConversionsIfNecessary().
734 SkASSERT(fDidTestPMConversions);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000735 GrConfigConversionEffect::PMConversion upmToPM =
736 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
737 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
bungeman06ca8ec2016-06-09 08:01:03 -0700738 return GrConfigConversionEffect::Make(texture, swizzle, upmToPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000739 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700740 return nullptr;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000741 }
742}
743
bsalomon636e8022015-07-29 06:08:46 -0700744bool GrContext::didFailPMUPMConversionTest() const {
joshualitt1de610a2016-01-06 08:26:09 -0800745 ASSERT_SINGLE_OWNER
bsalomon6c6f6582015-09-10 08:12:46 -0700746 // We should have already called this->testPMConversionsIfNecessary().
747 SkASSERT(fDidTestPMConversions);
bsalomon636e8022015-07-29 06:08:46 -0700748 // The PM<->UPM tests fail or succeed together so we only need to check one.
bsalomon6c6f6582015-09-10 08:12:46 -0700749 return GrConfigConversionEffect::kNone_PMConversion == fPMToUPMConversion;
bsalomon636e8022015-07-29 06:08:46 -0700750}
751
bsalomon37f9a262015-02-02 13:00:10 -0800752//////////////////////////////////////////////////////////////////////////////
753
754void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
joshualitt1de610a2016-01-06 08:26:09 -0800755 ASSERT_SINGLE_OWNER
bsalomon37f9a262015-02-02 13:00:10 -0800756 if (maxTextures) {
bsalomon0ea80f42015-02-11 10:49:59 -0800757 *maxTextures = fResourceCache->getMaxResourceCount();
bsalomon37f9a262015-02-02 13:00:10 -0800758 }
759 if (maxTextureBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -0800760 *maxTextureBytes = fResourceCache->getMaxResourceBytes();
bsalomon37f9a262015-02-02 13:00:10 -0800761 }
762}
763
764void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
joshualitt1de610a2016-01-06 08:26:09 -0800765 ASSERT_SINGLE_OWNER
bsalomon0ea80f42015-02-11 10:49:59 -0800766 fResourceCache->setLimits(maxTextures, maxTextureBytes);
bsalomon37f9a262015-02-02 13:00:10 -0800767}
768
ericrk0a5fa482015-09-15 14:16:10 -0700769//////////////////////////////////////////////////////////////////////////////
770
771void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
joshualitt1de610a2016-01-06 08:26:09 -0800772 ASSERT_SINGLE_OWNER
ericrk0a5fa482015-09-15 14:16:10 -0700773 fResourceCache->dumpMemoryStatistics(traceMemoryDump);
774}