blob: e0ee801ecb2e1b49ddb773b50ade27b35ee2aaf6 [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"
robertphillips@google.come930a072014-04-03 00:34:27 +000012#include "GrLayerCache.h"
bsalomon0ea80f42015-02-11 10:49:59 -080013#include "GrResourceCache.h"
bsalomond309e7a2015-04-30 14:18:54 -070014#include "GrResourceProvider.h"
robertphillips@google.com72176b22012-05-23 13:19:12 +000015#include "GrSoftwarePathRenderer.h"
bsalomonafbf2d62014-09-30 12:18:44 -070016#include "GrSurfacePriv.h"
robertphillips3dc6ae52015-10-20 09:54:32 -070017
bsalomon81beccc2014-10-13 12:32:55 -070018#include "SkConfig8888.h"
bsalomonf276ac52015-10-09 13:36:42 -070019#include "SkGrPriv.h"
joshualitt74417822015-08-07 11:42:16 -070020
joshualitt5478d422014-11-14 16:00:38 -080021#include "effects/GrConfigConversionEffect.h"
joshualitte8042922015-12-11 06:11:21 -080022#include "text/GrTextBlobCache.h"
joshualitt5478d422014-11-14 16:00:38 -080023
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000024#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
joshualitt1de610a2016-01-06 08:26:09 -080025#define ASSERT_SINGLE_OWNER \
26 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(&fSingleOwner);)
robertphillips77a2e522015-10-17 07:43:27 -070027#define RETURN_IF_ABANDONED if (fDrawingManager->abandoned()) { return; }
28#define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->abandoned()) { return false; }
29#define RETURN_NULL_IF_ABANDONED if (fDrawingManager->abandoned()) { return nullptr; }
bsalomon@google.combc4b6542011-11-19 13:56:11 +000030
robertphillipsea461502015-05-26 11:38:03 -070031////////////////////////////////////////////////////////////////////////////////
32
bsalomon682c2692015-05-22 14:01:46 -070033GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
34 GrContextOptions defaultOptions;
35 return Create(backend, backendContext, defaultOptions);
36}
bsalomonf28cff72015-05-22 12:25:41 -070037
bsalomon682c2692015-05-22 14:01:46 -070038GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
39 const GrContextOptions& options) {
halcanary385fe4d2015-08-26 13:07:48 -070040 GrContext* context = new GrContext;
bsalomon682c2692015-05-22 14:01:46 -070041
42 if (context->init(backend, backendContext, options)) {
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000043 return context;
44 } else {
45 context->unref();
halcanary96fcdcc2015-08-27 07:41:13 -070046 return nullptr;
bsalomon@google.com27847de2011-02-22 20:59:41 +000047 }
bsalomon@google.com27847de2011-02-22 20:59:41 +000048}
49
joshualitt0acd0d32015-05-07 08:23:19 -070050static int32_t gNextID = 1;
51static int32_t next_id() {
52 int32_t id;
53 do {
54 id = sk_atomic_inc(&gNextID);
55 } while (id == SK_InvalidGenID);
56 return id;
57}
58
bsalomon682c2692015-05-22 14:01:46 -070059GrContext::GrContext() : fUniqueID(next_id()) {
halcanary96fcdcc2015-08-27 07:41:13 -070060 fGpu = nullptr;
61 fCaps = nullptr;
62 fResourceCache = nullptr;
63 fResourceProvider = nullptr;
halcanary96fcdcc2015-08-27 07:41:13 -070064 fBatchFontCache = nullptr;
bsalomonf21dab92014-11-13 13:33:28 -080065 fFlushToReduceCacheSize = false;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000066}
67
bsalomon682c2692015-05-22 14:01:46 -070068bool GrContext::init(GrBackend backend, GrBackendContext backendContext,
69 const GrContextOptions& options) {
joshualitt1de610a2016-01-06 08:26:09 -080070 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -070071 SkASSERT(!fGpu);
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000072
bsalomon682c2692015-05-22 14:01:46 -070073 fGpu = GrGpu::Create(backend, backendContext, options, this);
robertphillipsea461502015-05-26 11:38:03 -070074 if (!fGpu) {
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000075 return false;
76 }
bsalomon69cfe952015-11-30 13:27:47 -080077 this->initCommon(options);
bsalomon33435572014-11-05 14:47:41 -080078 return true;
79}
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000080
bsalomon69cfe952015-11-30 13:27:47 -080081void GrContext::initCommon(const GrContextOptions& options) {
joshualitt1de610a2016-01-06 08:26:09 -080082 ASSERT_SINGLE_OWNER
83
bsalomon76228632015-05-29 08:02:10 -070084 fCaps = SkRef(fGpu->caps());
halcanary385fe4d2015-08-26 13:07:48 -070085 fResourceCache = new GrResourceCache(fCaps);
bsalomon0ea80f42015-02-11 10:49:59 -080086 fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
joshualitt6d0872d2016-01-11 08:27:48 -080087 fResourceProvider = new GrResourceProvider(fGpu, fResourceCache, &fSingleOwner);
commit-bot@chromium.org1836d332013-07-16 22:55:03 +000088
halcanary385fe4d2015-08-26 13:07:48 -070089 fLayerCache.reset(new GrLayerCache(this));
robertphillips@google.come930a072014-04-03 00:34:27 +000090
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000091 fDidTestPMConversions = false;
92
bsalomon69cfe952015-11-30 13:27:47 -080093 GrDrawTarget::Options dtOptions;
94 dtOptions.fClipBatchToBounds = options.fClipBatchToBounds;
bsalomon6dea83f2015-12-03 12:58:06 -080095 dtOptions.fDrawBatchBounds = options.fDrawBatchBounds;
bsalomon489147c2015-12-14 12:13:09 -080096 dtOptions.fMaxBatchLookback = options.fMaxBatchLookback;
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
bsalomon2354f842014-07-28 13:48:36 -0700129void GrContext::abandonContext() {
joshualitt1de610a2016-01-06 08:26:09 -0800130 ASSERT_SINGLE_OWNER
131
bsalomond309e7a2015-04-30 14:18:54 -0700132 fResourceProvider->abandon();
robertphillips0dfa62c2015-11-16 06:23:31 -0800133
134 // Need to abandon the drawing manager first so all the render targets
135 // will be released/forgotten before they too are abandoned.
136 fDrawingManager->abandon();
137
bsalomon@google.com205d4602011-04-25 12:43:45 +0000138 // abandon first to so destructors
139 // don't try to free the resources in the API.
bsalomon0ea80f42015-02-11 10:49:59 -0800140 fResourceCache->abandonAll();
bsalomonc8dc1f72014-08-21 13:02:13 -0700141
robertphillipse3371302014-09-17 06:01:06 -0700142 fGpu->contextAbandoned();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000143
joshualitt7c3a2f82015-03-31 13:32:05 -0700144 fBatchFontCache->freeAll();
robertphillips@google.come930a072014-04-03 00:34:27 +0000145 fLayerCache->freeAll();
joshualitt26ffc002015-04-16 11:24:04 -0700146 fTextBlobCache->freeAll();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000147}
148
bsalomon@google.com0a208a12013-06-28 18:57:35 +0000149void GrContext::resetContext(uint32_t state) {
joshualitt1de610a2016-01-06 08:26:09 -0800150 ASSERT_SINGLE_OWNER
bsalomon@google.com0a208a12013-06-28 18:57:35 +0000151 fGpu->markContextDirty(state);
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000152}
153
154void GrContext::freeGpuResources() {
joshualitt1de610a2016-01-06 08:26:09 -0800155 ASSERT_SINGLE_OWNER
156
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000157 this->flush();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000158
joshualitt7c3a2f82015-03-31 13:32:05 -0700159 fBatchFontCache->freeAll();
robertphillips@google.come930a072014-04-03 00:34:27 +0000160 fLayerCache->freeAll();
robertphillips68737822015-10-29 12:12:21 -0700161
162 fDrawingManager->freeGpuResources();
bsalomon3033b9f2015-04-13 11:09:56 -0700163
164 fResourceCache->purgeAllUnlocked();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000165}
166
commit-bot@chromium.org95c20032014-05-09 14:29:32 +0000167void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
joshualitt1de610a2016-01-06 08:26:09 -0800168 ASSERT_SINGLE_OWNER
169
bsalomon71cb0c22014-11-14 12:10:14 -0800170 if (resourceCount) {
bsalomon0ea80f42015-02-11 10:49:59 -0800171 *resourceCount = fResourceCache->getBudgetedResourceCount();
bsalomon71cb0c22014-11-14 12:10:14 -0800172 }
173 if (resourceBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -0800174 *resourceBytes = fResourceCache->getBudgetedResourceBytes();
bsalomon71cb0c22014-11-14 12:10:14 -0800175 }
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000176}
177
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000178////////////////////////////////////////////////////////////////////////////////
179
bsalomon71cb0c22014-11-14 12:10:14 -0800180void GrContext::OverBudgetCB(void* data) {
bsalomon66a450f2014-11-13 13:19:10 -0800181 SkASSERT(data);
bsalomonf21dab92014-11-13 13:33:28 -0800182
bsalomon66a450f2014-11-13 13:19:10 -0800183 GrContext* context = reinterpret_cast<GrContext*>(data);
bsalomonf21dab92014-11-13 13:33:28 -0800184
joshualittb542bae2015-07-28 09:58:39 -0700185 // Flush the GrBufferedDrawTarget to possibly free up some textures
bsalomonf21dab92014-11-13 13:33:28 -0800186 context->fFlushToReduceCacheSize = true;
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000187}
188
joshualitt0db6dfa2015-04-10 07:01:30 -0700189void GrContext::TextBlobCacheOverBudgetCB(void* data) {
190 SkASSERT(data);
191
192 // Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level, therefore they
193 // cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush. The solution is to move
194 // drawText calls to below the GrContext level, but this is not trivial because they call
195 // drawPath on SkGpuDevice
196 GrContext* context = reinterpret_cast<GrContext*>(data);
197 context->flush();
198}
199
bsalomon@google.com27847de2011-02-22 20:59:41 +0000200////////////////////////////////////////////////////////////////////////////////
201
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000202void GrContext::flush(int flagsBitfield) {
joshualitt1de610a2016-01-06 08:26:09 -0800203 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700204 RETURN_IF_ABANDONED
robertphillips@google.come7db8d62013-07-04 11:48:52 +0000205
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000206 if (kDiscard_FlushBit & flagsBitfield) {
robertphillips77a2e522015-10-17 07:43:27 -0700207 fDrawingManager->reset();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000208 } else {
robertphillips77a2e522015-10-17 07:43:27 -0700209 fDrawingManager->flush();
junov@google.com53a55842011-06-08 22:55:10 +0000210 }
bsalomon3f324322015-04-08 11:01:54 -0700211 fResourceCache->notifyFlushOccurred();
bsalomonf21dab92014-11-13 13:33:28 -0800212 fFlushToReduceCacheSize = false;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000213}
214
bsalomon81beccc2014-10-13 12:32:55 -0700215bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
216 const void* inPixels, size_t outRowBytes, void* outPixels) {
217 SkSrcPixelInfo srcPI;
halcanary96fcdcc2015-08-27 07:41:13 -0700218 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, nullptr)) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000219 return false;
220 }
bsalomon81beccc2014-10-13 12:32:55 -0700221 srcPI.fAlphaType = kUnpremul_SkAlphaType;
222 srcPI.fPixels = inPixels;
223 srcPI.fRowBytes = inRowBytes;
224
225 SkDstPixelInfo dstPI;
226 dstPI.fColorType = srcPI.fColorType;
227 dstPI.fAlphaType = kPremul_SkAlphaType;
228 dstPI.fPixels = outPixels;
229 dstPI.fRowBytes = outRowBytes;
230
231 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000232}
233
bsalomon81beccc2014-10-13 12:32:55 -0700234bool GrContext::writeSurfacePixels(GrSurface* surface,
235 int left, int top, int width, int height,
236 GrPixelConfig srcConfig, const void* buffer, size_t rowBytes,
237 uint32_t pixelOpsFlags) {
joshualitt1de610a2016-01-06 08:26:09 -0800238 ASSERT_SINGLE_OWNER
joshualitt5f5a8d72015-02-25 14:09:45 -0800239 RETURN_FALSE_IF_ABANDONED
bsalomon6c6f6582015-09-10 08:12:46 -0700240 ASSERT_OWNED_RESOURCE(surface);
241 SkASSERT(surface);
joshualittbc907352016-01-13 06:45:40 -0800242 GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::writeSurfacePixels");
bsalomon6c6f6582015-09-10 08:12:46 -0700243
244 this->testPMConversionsIfNecessary(pixelOpsFlags);
bsalomon81beccc2014-10-13 12:32:55 -0700245
bsalomone8d21e82015-07-16 08:23:13 -0700246 // 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 -0700247 // necessary and because GrGpu::getWritePixelsInfo requires it.
bsalomone8d21e82015-07-16 08:23:13 -0700248 if (!GrSurfacePriv::AdjustWritePixelParams(surface->width(), surface->height(),
249 GrBytesPerPixel(srcConfig), &left, &top, &width,
250 &height, &buffer, &rowBytes)) {
251 return false;
252 }
253
bsalomonf0674512015-07-28 13:26:15 -0700254 bool applyPremulToSrc = false;
bsalomon81beccc2014-10-13 12:32:55 -0700255 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) {
256 if (!GrPixelConfigIs8888(srcConfig)) {
257 return false;
258 }
bsalomonf0674512015-07-28 13:26:15 -0700259 applyPremulToSrc = true;
260 }
bsalomon636e8022015-07-29 06:08:46 -0700261
262 GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
263 // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
264 // we've already determined that there isn't a roundtrip preserving conversion processor pair.
265 if (applyPremulToSrc && !this->didFailPMUPMConversionTest()) {
266 drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference;
267 }
268
bsalomonf0674512015-07-28 13:26:15 -0700269 GrGpu::WritePixelTempDrawInfo tempDrawInfo;
270 if (!fGpu->getWritePixelsInfo(surface, width, height, rowBytes, srcConfig, &drawPreference,
271 &tempDrawInfo)) {
272 return false;
273 }
274
275 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && surface->surfacePriv().hasPendingIO()) {
276 this->flush();
277 }
278
279 SkAutoTUnref<GrTexture> tempTexture;
280 if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
bsalomoneae62002015-07-31 13:59:30 -0700281 tempTexture.reset(
282 this->textureProvider()->createApproxTexture(tempDrawInfo.fTempSurfaceDesc));
bsalomonf0674512015-07-28 13:26:15 -0700283 if (!tempTexture && GrGpu::kRequireDraw_DrawPreference == drawPreference) {
284 return false;
285 }
286 }
287
288 // temp buffer for doing sw premul conversion, if needed.
benjaminwagner67e8bd22016-02-02 16:01:39 -0800289#if defined(GOOGLE3)
290 // Stack frame size is limited in GOOGLE3.
291 SkAutoSTMalloc<48 * 48, uint32_t> tmpPixels(0);
292#else
bsalomonf0674512015-07-28 13:26:15 -0700293 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
benjaminwagner67e8bd22016-02-02 16:01:39 -0800294#endif
bsalomonf0674512015-07-28 13:26:15 -0700295 if (tempTexture) {
296 SkAutoTUnref<const GrFragmentProcessor> fp;
297 SkMatrix textureMatrix;
298 textureMatrix.setIDiv(tempTexture->width(), tempTexture->height());
bsalomonf0674512015-07-28 13:26:15 -0700299 if (applyPremulToSrc) {
bsalomon6c9cd552016-01-22 07:17:34 -0800300 fp.reset(this->createUPMToPMEffect(tempTexture, tempDrawInfo.fSwizzle,
bsalomon4a339522015-10-06 08:40:50 -0700301 textureMatrix));
bsalomonf0674512015-07-28 13:26:15 -0700302 // If premultiplying was the only reason for the draw, fall back to a straight write.
303 if (!fp) {
304 if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
halcanary96fcdcc2015-08-27 07:41:13 -0700305 tempTexture.reset(nullptr);
bsalomonf0674512015-07-28 13:26:15 -0700306 }
307 } else {
308 applyPremulToSrc = false;
309 }
310 }
311 if (tempTexture) {
312 if (!fp) {
bsalomon6c9cd552016-01-22 07:17:34 -0800313 fp.reset(GrConfigConversionEffect::Create(tempTexture, tempDrawInfo.fSwizzle,
bsalomonf0674512015-07-28 13:26:15 -0700314 GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
315 if (!fp) {
316 return false;
317 }
318 }
319 GrRenderTarget* renderTarget = surface->asRenderTarget();
320 SkASSERT(renderTarget);
321 if (tempTexture->surfacePriv().hasPendingIO()) {
322 this->flush();
323 }
324 if (applyPremulToSrc) {
325 size_t tmpRowBytes = 4 * width;
326 tmpPixels.reset(width * height);
327 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
328 tmpPixels.get())) {
329 return false;
330 }
331 rowBytes = tmpRowBytes;
332 buffer = tmpPixels.get();
333 applyPremulToSrc = false;
334 }
bsalomon6cb3cbe2015-07-30 07:34:27 -0700335 if (!fGpu->writePixels(tempTexture, 0, 0, width, height,
bsalomon6c9cd552016-01-22 07:17:34 -0800336 tempDrawInfo.fWriteConfig, buffer,
bsalomon6cb3cbe2015-07-30 07:34:27 -0700337 rowBytes)) {
bsalomonf0674512015-07-28 13:26:15 -0700338 return false;
339 }
340 SkMatrix matrix;
341 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
robertphillips2e1e51f2015-10-15 08:01:48 -0700342 SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(renderTarget));
bsalomonf0674512015-07-28 13:26:15 -0700343 if (!drawContext) {
344 return false;
345 }
egdanielc4b72722015-11-23 13:20:41 -0800346 GrPaint paint;
bsalomonac856c92015-08-27 06:30:17 -0700347 paint.addColorFragmentProcessor(fp);
egdanielc4b72722015-11-23 13:20:41 -0800348 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
bsalomonf0674512015-07-28 13:26:15 -0700349 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
robertphillips2e1e51f2015-10-15 08:01:48 -0700350 drawContext->drawRect(GrClip::WideOpen(), paint, matrix, rect, nullptr);
bsalomonf0674512015-07-28 13:26:15 -0700351
352 if (kFlushWrites_PixelOp & pixelOpsFlags) {
353 this->flushSurfaceWrites(surface);
354 }
355 }
356 }
357 if (!tempTexture) {
bsalomonf0674512015-07-28 13:26:15 -0700358 if (applyPremulToSrc) {
bsalomon81beccc2014-10-13 12:32:55 -0700359 size_t tmpRowBytes = 4 * width;
360 tmpPixels.reset(width * height);
361 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
362 tmpPixels.get())) {
363 return false;
364 }
365 rowBytes = tmpRowBytes;
366 buffer = tmpPixels.get();
bsalomonf0674512015-07-28 13:26:15 -0700367 applyPremulToSrc = false;
bsalomon81beccc2014-10-13 12:32:55 -0700368 }
bsalomon6cb3cbe2015-07-30 07:34:27 -0700369 return fGpu->writePixels(surface, left, top, width, height, srcConfig, buffer, rowBytes);
bsalomon81beccc2014-10-13 12:32:55 -0700370 }
bsalomon81beccc2014-10-13 12:32:55 -0700371 return true;
372}
bsalomon@google.coma91e9232012-02-23 15:39:54 +0000373
bsalomone8d21e82015-07-16 08:23:13 -0700374bool GrContext::readSurfacePixels(GrSurface* src,
375 int left, int top, int width, int height,
376 GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
377 uint32_t flags) {
joshualitt1de610a2016-01-06 08:26:09 -0800378 ASSERT_SINGLE_OWNER
joshualitt5f5a8d72015-02-25 14:09:45 -0800379 RETURN_FALSE_IF_ABANDONED
bsalomone8d21e82015-07-16 08:23:13 -0700380 ASSERT_OWNED_RESOURCE(src);
381 SkASSERT(src);
joshualittbc907352016-01-13 06:45:40 -0800382 GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::readSurfacePixels");
bsalomon32ab2602015-09-09 18:57:49 -0700383
bsalomon6c6f6582015-09-10 08:12:46 -0700384 this->testPMConversionsIfNecessary(flags);
385 SkAutoMutexAcquire ama(fReadPixelsMutex);
386
bsalomone8d21e82015-07-16 08:23:13 -0700387 // Adjust the params so that if we wind up using an intermediate surface we've already done
388 // all the trimming and the temporary can be the min size required.
389 if (!GrSurfacePriv::AdjustReadPixelParams(src->width(), src->height(),
390 GrBytesPerPixel(dstConfig), &left,
391 &top, &width, &height, &buffer, &rowBytes)) {
392 return false;
393 }
394
395 if (!(kDontFlush_PixelOpsFlag & flags) && src->surfacePriv().hasPendingWrite()) {
bsalomon@google.com6f379512011-11-16 20:36:03 +0000396 this->flush();
397 }
bsalomon@google.comc4364992011-11-07 15:54:49 +0000398
bsalomone8d21e82015-07-16 08:23:13 -0700399 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
bsalomon@google.com9c680582013-02-06 18:17:50 +0000400 if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
bsalomon39826022015-07-23 08:07:21 -0700401 // The unpremul flag is only allowed for 8888 configs.
bsalomon@google.com0a97be22011-11-08 19:20:57 +0000402 return false;
403 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000404
bsalomon636e8022015-07-29 06:08:46 -0700405 GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
406 // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
407 // we've already determined that there isn't a roundtrip preserving conversion processor pair.
408 if (unpremul && !this->didFailPMUPMConversionTest()) {
409 drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference;
410 }
411
bsalomon39826022015-07-23 08:07:21 -0700412 GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
413 if (!fGpu->getReadPixelsInfo(src, width, height, rowBytes, dstConfig, &drawPreference,
414 &tempDrawInfo)) {
415 return false;
416 }
bsalomon191bcc02014-11-14 11:31:13 -0800417
bsalomon6cb3cbe2015-07-30 07:34:27 -0700418 SkAutoTUnref<GrSurface> surfaceToRead(SkRef(src));
bsalomon39826022015-07-23 08:07:21 -0700419 bool didTempDraw = false;
420 if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
bsalomon39826022015-07-23 08:07:21 -0700421 if (tempDrawInfo.fUseExactScratch) {
422 // We only respect this when the entire src is being read. Otherwise we can trigger too
423 // many odd ball texture sizes and trash the cache.
bsalomoneae62002015-07-31 13:59:30 -0700424 if (width != src->width() || height != src->height()) {
425 tempDrawInfo.fUseExactScratch = false;
bsalomon39826022015-07-23 08:07:21 -0700426 }
bsalomon@google.com56d11e02011-11-30 19:59:08 +0000427 }
bsalomon39826022015-07-23 08:07:21 -0700428 SkAutoTUnref<GrTexture> temp;
bsalomoneae62002015-07-31 13:59:30 -0700429 if (tempDrawInfo.fUseExactScratch) {
430 temp.reset(this->textureProvider()->createTexture(tempDrawInfo.fTempSurfaceDesc, true));
431 } else {
432 temp.reset(this->textureProvider()->createApproxTexture(tempDrawInfo.fTempSurfaceDesc));
433 }
bsalomon39826022015-07-23 08:07:21 -0700434 if (temp) {
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000435 SkMatrix textureMatrix;
bsalomon39826022015-07-23 08:07:21 -0700436 textureMatrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000437 textureMatrix.postIDiv(src->width(), src->height());
joshualittb0a8a372014-09-23 09:50:21 -0700438 SkAutoTUnref<const GrFragmentProcessor> fp;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000439 if (unpremul) {
bsalomon6c9cd552016-01-22 07:17:34 -0800440 fp.reset(this->createPMToUPMEffect(src->asTexture(), tempDrawInfo.fSwizzle,
bsalomon39826022015-07-23 08:07:21 -0700441 textureMatrix));
joshualittb0a8a372014-09-23 09:50:21 -0700442 if (fp) {
bsalomon@google.com9c680582013-02-06 18:17:50 +0000443 unpremul = false; // we no longer need to do this on CPU after the read back.
bsalomon39826022015-07-23 08:07:21 -0700444 } else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
445 // We only wanted to do the draw in order to perform the unpremul so don't
446 // bother.
halcanary96fcdcc2015-08-27 07:41:13 -0700447 temp.reset(nullptr);
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000448 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000449 }
bsalomon39826022015-07-23 08:07:21 -0700450 if (!fp && temp) {
bsalomon6c9cd552016-01-22 07:17:34 -0800451 fp.reset(GrConfigConversionEffect::Create(src->asTexture(), tempDrawInfo.fSwizzle,
bsalomon39826022015-07-23 08:07:21 -0700452 GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
453 }
454 if (fp) {
egdanielc4b72722015-11-23 13:20:41 -0800455 GrPaint paint;
bsalomonac856c92015-08-27 06:30:17 -0700456 paint.addColorFragmentProcessor(fp);
egdanielc4b72722015-11-23 13:20:41 -0800457 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
bsalomon39826022015-07-23 08:07:21 -0700458 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
robertphillips2e1e51f2015-10-15 08:01:48 -0700459 SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(temp->asRenderTarget()));
460 drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, nullptr);
bsalomon6cb3cbe2015-07-30 07:34:27 -0700461 surfaceToRead.reset(SkRef(temp.get()));
bsalomon39826022015-07-23 08:07:21 -0700462 left = 0;
463 top = 0;
464 didTempDraw = true;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000465 }
bsalomon@google.com0342a852012-08-20 19:22:38 +0000466 }
bsalomon@google.comc4364992011-11-07 15:54:49 +0000467 }
joshualitt5c55fef2014-10-31 14:04:35 -0700468
bsalomon39826022015-07-23 08:07:21 -0700469 if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000470 return false;
471 }
bsalomon39826022015-07-23 08:07:21 -0700472 GrPixelConfig configToRead = dstConfig;
473 if (didTempDraw) {
bsalomon6cb3cbe2015-07-30 07:34:27 -0700474 this->flushSurfaceWrites(surfaceToRead);
bsalomon6c9cd552016-01-22 07:17:34 -0800475 configToRead = tempDrawInfo.fReadConfig;
bsalomon39826022015-07-23 08:07:21 -0700476 }
bsalomon6cb3cbe2015-07-30 07:34:27 -0700477 if (!fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead, buffer,
478 rowBytes)) {
bsalomon39826022015-07-23 08:07:21 -0700479 return false;
480 }
481
482 // Perform umpremul conversion if we weren't able to perform it as a draw.
483 if (unpremul) {
reed@google.com7111d462014-03-25 16:20:24 +0000484 SkDstPixelInfo dstPI;
halcanary96fcdcc2015-08-27 07:41:13 -0700485 if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, nullptr)) {
reed@google.com7111d462014-03-25 16:20:24 +0000486 return false;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000487 }
reed@google.com7111d462014-03-25 16:20:24 +0000488 dstPI.fAlphaType = kUnpremul_SkAlphaType;
489 dstPI.fPixels = buffer;
490 dstPI.fRowBytes = rowBytes;
491
492 SkSrcPixelInfo srcPI;
bsalomon39826022015-07-23 08:07:21 -0700493 srcPI.fColorType = dstPI.fColorType;
reed@google.com7111d462014-03-25 16:20:24 +0000494 srcPI.fAlphaType = kPremul_SkAlphaType;
495 srcPI.fPixels = buffer;
496 srcPI.fRowBytes = rowBytes;
497
498 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000499 }
500 return true;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000501}
502
bsalomonc49e8682015-06-30 11:37:35 -0700503void GrContext::prepareSurfaceForExternalIO(GrSurface* surface) {
joshualitt1de610a2016-01-06 08:26:09 -0800504 ASSERT_SINGLE_OWNER
joshualitt5f5a8d72015-02-25 14:09:45 -0800505 RETURN_IF_ABANDONED
bsalomon87a94eb2014-11-03 14:28:32 -0800506 SkASSERT(surface);
507 ASSERT_OWNED_RESOURCE(surface);
508 if (surface->surfacePriv().hasPendingIO()) {
509 this->flush();
510 }
511 GrRenderTarget* rt = surface->asRenderTarget();
512 if (fGpu && rt) {
513 fGpu->resolveRenderTarget(rt);
bsalomon41ebbdd2014-08-04 08:31:39 -0700514 }
bsalomon@google.com75f9f252012-01-31 13:35:56 +0000515}
516
bsalomonf80bfed2014-10-07 05:56:02 -0700517void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
518 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) {
joshualitt1de610a2016-01-06 08:26:09 -0800519 ASSERT_SINGLE_OWNER
joshualitt5f5a8d72015-02-25 14:09:45 -0800520 RETURN_IF_ABANDONED
joshualittbc907352016-01-13 06:45:40 -0800521 GR_AUDIT_TRAIL_AUTO_FRAME(&fAuditTrail, "GrContext::copySurface");
522
robertphillipsea461502015-05-26 11:38:03 -0700523 if (!src || !dst) {
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000524 return;
525 }
bsalomone3d4bf22014-09-23 09:15:03 -0700526 ASSERT_OWNED_RESOURCE(src);
junov2bb52102014-09-29 10:18:59 -0700527 ASSERT_OWNED_RESOURCE(dst);
Brian Salomon34a98952014-09-24 11:41:24 -0400528
bsalomonf80bfed2014-10-07 05:56:02 -0700529 // Since we're going to the draw target and not GPU, no need to check kNoFlush
530 // here.
robertphillipsea461502015-05-26 11:38:03 -0700531 if (!dst->asRenderTarget()) {
junov96c118e2014-09-26 13:09:47 -0700532 return;
533 }
robertphillipsea461502015-05-26 11:38:03 -0700534
robertphillips2e1e51f2015-10-15 08:01:48 -0700535 SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700536 if (!drawContext) {
537 return;
538 }
539
robertphillips2e1e51f2015-10-15 08:01:48 -0700540 drawContext->copySurface(src, srcRect, dstPoint);
bsalomonf80bfed2014-10-07 05:56:02 -0700541
542 if (kFlushWrites_PixelOp & pixelOpsFlags) {
543 this->flush();
544 }
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000545}
546
bsalomonf80bfed2014-10-07 05:56:02 -0700547void GrContext::flushSurfaceWrites(GrSurface* surface) {
joshualitt1de610a2016-01-06 08:26:09 -0800548 ASSERT_SINGLE_OWNER
joshualitt5f5a8d72015-02-25 14:09:45 -0800549 RETURN_IF_ABANDONED
bsalomonf80bfed2014-10-07 05:56:02 -0700550 if (surface->surfacePriv().hasPendingWrite()) {
551 this->flush();
552 }
553}
554
bsalomon@google.com27847de2011-02-22 20:59:41 +0000555////////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000556int GrContext::getRecommendedSampleCount(GrPixelConfig config,
557 SkScalar dpi) const {
joshualitt1de610a2016-01-06 08:26:09 -0800558 ASSERT_SINGLE_OWNER
559
bsalomon76228632015-05-29 08:02:10 -0700560 if (!this->caps()->isConfigRenderable(config, true)) {
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000561 return 0;
562 }
563 int chosenSampleCount = 0;
jvanverthe9c0fc62015-04-29 11:18:05 -0700564 if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) {
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000565 if (dpi >= 250.0f) {
566 chosenSampleCount = 4;
567 } else {
568 chosenSampleCount = 16;
569 }
570 }
egdanieleed519e2016-01-15 11:36:18 -0800571 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ? chosenSampleCount : 0;
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000572}
573
robertphillips77a2e522015-10-17 07:43:27 -0700574
575GrDrawContext* GrContext::drawContext(GrRenderTarget* rt, const SkSurfaceProps* surfaceProps) {
joshualitt1de610a2016-01-06 08:26:09 -0800576 ASSERT_SINGLE_OWNER
robertphillips77a2e522015-10-17 07:43:27 -0700577 return fDrawingManager->drawContext(rt, surfaceProps);
578}
579
joshualitt1de610a2016-01-06 08:26:09 -0800580bool GrContext::abandoned() const {
581 ASSERT_SINGLE_OWNER
robertphillips77a2e522015-10-17 07:43:27 -0700582 return fDrawingManager->abandoned();
583}
584
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000585namespace {
586void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
587 GrConfigConversionEffect::PMConversion pmToUPM;
588 GrConfigConversionEffect::PMConversion upmToPM;
589 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
590 *pmToUPMValue = pmToUPM;
591 *upmToPMValue = upmToPM;
592}
593}
594
bsalomon6c6f6582015-09-10 08:12:46 -0700595void GrContext::testPMConversionsIfNecessary(uint32_t flags) {
joshualitt1de610a2016-01-06 08:26:09 -0800596 ASSERT_SINGLE_OWNER
bsalomon6c6f6582015-09-10 08:12:46 -0700597 if (SkToBool(kUnpremul_PixelOpsFlag & flags)) {
598 SkAutoMutexAcquire ama(fTestPMConversionsMutex);
599 if (!fDidTestPMConversions) {
600 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
601 fDidTestPMConversions = true;
602 }
603 }
604}
605
bsalomon4a339522015-10-06 08:40:50 -0700606const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
bsalomon6c9cd552016-01-22 07:17:34 -0800607 const GrSwizzle& swizzle,
bsalomon6c6f6582015-09-10 08:12:46 -0700608 const SkMatrix& matrix) const {
joshualitt1de610a2016-01-06 08:26:09 -0800609 ASSERT_SINGLE_OWNER
bsalomon6c6f6582015-09-10 08:12:46 -0700610 // We should have already called this->testPMConversionsIfNecessary().
611 SkASSERT(fDidTestPMConversions);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000612 GrConfigConversionEffect::PMConversion pmToUPM =
613 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
614 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
bsalomon6c9cd552016-01-22 07:17:34 -0800615 return GrConfigConversionEffect::Create(texture, swizzle, pmToUPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000616 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700617 return nullptr;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000618 }
619}
620
bsalomon4a339522015-10-06 08:40:50 -0700621const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
bsalomon6c9cd552016-01-22 07:17:34 -0800622 const GrSwizzle& swizzle,
bsalomon6c6f6582015-09-10 08:12:46 -0700623 const SkMatrix& matrix) const {
joshualitt1de610a2016-01-06 08:26:09 -0800624 ASSERT_SINGLE_OWNER
bsalomon6c6f6582015-09-10 08:12:46 -0700625 // We should have already called this->testPMConversionsIfNecessary().
626 SkASSERT(fDidTestPMConversions);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000627 GrConfigConversionEffect::PMConversion upmToPM =
628 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
629 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
bsalomon6c9cd552016-01-22 07:17:34 -0800630 return GrConfigConversionEffect::Create(texture, swizzle, upmToPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000631 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700632 return nullptr;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000633 }
634}
635
bsalomon636e8022015-07-29 06:08:46 -0700636bool GrContext::didFailPMUPMConversionTest() const {
joshualitt1de610a2016-01-06 08:26:09 -0800637 ASSERT_SINGLE_OWNER
bsalomon6c6f6582015-09-10 08:12:46 -0700638 // We should have already called this->testPMConversionsIfNecessary().
639 SkASSERT(fDidTestPMConversions);
bsalomon636e8022015-07-29 06:08:46 -0700640 // The PM<->UPM tests fail or succeed together so we only need to check one.
bsalomon6c6f6582015-09-10 08:12:46 -0700641 return GrConfigConversionEffect::kNone_PMConversion == fPMToUPMConversion;
bsalomon636e8022015-07-29 06:08:46 -0700642}
643
bsalomon37f9a262015-02-02 13:00:10 -0800644//////////////////////////////////////////////////////////////////////////////
645
646void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
joshualitt1de610a2016-01-06 08:26:09 -0800647 ASSERT_SINGLE_OWNER
bsalomon37f9a262015-02-02 13:00:10 -0800648 if (maxTextures) {
bsalomon0ea80f42015-02-11 10:49:59 -0800649 *maxTextures = fResourceCache->getMaxResourceCount();
bsalomon37f9a262015-02-02 13:00:10 -0800650 }
651 if (maxTextureBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -0800652 *maxTextureBytes = fResourceCache->getMaxResourceBytes();
bsalomon37f9a262015-02-02 13:00:10 -0800653 }
654}
655
656void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
joshualitt1de610a2016-01-06 08:26:09 -0800657 ASSERT_SINGLE_OWNER
bsalomon0ea80f42015-02-11 10:49:59 -0800658 fResourceCache->setLimits(maxTextures, maxTextureBytes);
bsalomon37f9a262015-02-02 13:00:10 -0800659}
660
ericrk0a5fa482015-09-15 14:16:10 -0700661//////////////////////////////////////////////////////////////////////////////
662
663void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
joshualitt1de610a2016-01-06 08:26:09 -0800664 ASSERT_SINGLE_OWNER
ericrk0a5fa482015-09-15 14:16:10 -0700665 fResourceCache->dumpMemoryStatistics(traceMemoryDump);
666}