blob: 2ca3461a692917a1c2a97c2bb5a42aa8f41a1b1c [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
bsalomon@google.com27847de2011-02-22 20:59:41 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
bsalomon@google.com27847de2011-02-22 20:59:41 +00007 */
8
bsalomon@google.com1fadb202011-12-12 16:10:08 +00009#include "GrContext.h"
bsalomon682c2692015-05-22 14:01:46 -070010#include "GrContextOptions.h"
robertphillips77a2e522015-10-17 07:43:27 -070011#include "GrDrawingManager.h"
robertphillipsea461502015-05-26 11:38:03 -070012#include "GrDrawContext.h"
robertphillips@google.come930a072014-04-03 00:34:27 +000013#include "GrLayerCache.h"
bsalomon0ea80f42015-02-11 10:49:59 -080014#include "GrResourceCache.h"
bsalomond309e7a2015-04-30 14:18:54 -070015#include "GrResourceProvider.h"
robertphillips@google.com72176b22012-05-23 13:19:12 +000016#include "GrSoftwarePathRenderer.h"
bsalomonafbf2d62014-09-30 12:18:44 -070017#include "GrSurfacePriv.h"
joshualittb7133be2015-04-08 09:08:31 -070018#include "GrTextBlobCache.h"
robertphillips3dc6ae52015-10-20 09:54:32 -070019
bsalomon81beccc2014-10-13 12:32:55 -070020#include "SkConfig8888.h"
bsalomonf276ac52015-10-09 13:36:42 -070021#include "SkGrPriv.h"
joshualitt74417822015-08-07 11:42:16 -070022
joshualitt5478d422014-11-14 16:00:38 -080023#include "effects/GrConfigConversionEffect.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)
robertphillips77a2e522015-10-17 07:43:27 -070026#define RETURN_IF_ABANDONED if (fDrawingManager->abandoned()) { return; }
27#define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->abandoned()) { return false; }
28#define RETURN_NULL_IF_ABANDONED if (fDrawingManager->abandoned()) { return nullptr; }
bsalomon@google.combc4b6542011-11-19 13:56:11 +000029
robertphillipsea461502015-05-26 11:38:03 -070030////////////////////////////////////////////////////////////////////////////////
31
bsalomon682c2692015-05-22 14:01:46 -070032GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext) {
33 GrContextOptions defaultOptions;
34 return Create(backend, backendContext, defaultOptions);
35}
bsalomonf28cff72015-05-22 12:25:41 -070036
bsalomon682c2692015-05-22 14:01:46 -070037GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
38 const GrContextOptions& options) {
halcanary385fe4d2015-08-26 13:07:48 -070039 GrContext* context = new GrContext;
bsalomon682c2692015-05-22 14:01:46 -070040
41 if (context->init(backend, backendContext, options)) {
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000042 return context;
43 } else {
44 context->unref();
halcanary96fcdcc2015-08-27 07:41:13 -070045 return nullptr;
bsalomon@google.com27847de2011-02-22 20:59:41 +000046 }
bsalomon@google.com27847de2011-02-22 20:59:41 +000047}
48
joshualitt0acd0d32015-05-07 08:23:19 -070049static int32_t gNextID = 1;
50static int32_t next_id() {
51 int32_t id;
52 do {
53 id = sk_atomic_inc(&gNextID);
54 } while (id == SK_InvalidGenID);
55 return id;
56}
57
bsalomon682c2692015-05-22 14:01:46 -070058GrContext::GrContext() : fUniqueID(next_id()) {
halcanary96fcdcc2015-08-27 07:41:13 -070059 fGpu = nullptr;
60 fCaps = nullptr;
61 fResourceCache = nullptr;
62 fResourceProvider = nullptr;
63 fPathRendererChain = nullptr;
64 fSoftwarePathRenderer = nullptr;
65 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) {
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 }
bsalomon33435572014-11-05 14:47:41 -080077 this->initCommon();
78 return true;
79}
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000080
bsalomon33435572014-11-05 14:47:41 -080081void GrContext::initCommon() {
bsalomon76228632015-05-29 08:02:10 -070082 fCaps = SkRef(fGpu->caps());
halcanary385fe4d2015-08-26 13:07:48 -070083 fResourceCache = new GrResourceCache(fCaps);
bsalomon0ea80f42015-02-11 10:49:59 -080084 fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
halcanary385fe4d2015-08-26 13:07:48 -070085 fResourceProvider = new GrResourceProvider(fGpu, fResourceCache);
commit-bot@chromium.org1836d332013-07-16 22:55:03 +000086
halcanary385fe4d2015-08-26 13:07:48 -070087 fLayerCache.reset(new GrLayerCache(this));
robertphillips@google.come930a072014-04-03 00:34:27 +000088
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000089 fDidTestPMConversions = false;
90
robertphillips77a2e522015-10-17 07:43:27 -070091 fDrawingManager.reset(new GrDrawingManager(this));
joshualitt7c3a2f82015-03-31 13:32:05 -070092
93 // GrBatchFontCache will eventually replace GrFontCache
halcanary385fe4d2015-08-26 13:07:48 -070094 fBatchFontCache = new GrBatchFontCache(this);
joshualittb7133be2015-04-08 09:08:31 -070095
halcanary385fe4d2015-08-26 13:07:48 -070096 fTextBlobCache.reset(new GrTextBlobCache(TextBlobCacheOverBudgetCB, this));
bsalomon@google.comc0af3172012-06-15 14:10:09 +000097}
98
bsalomon@google.com27847de2011-02-22 20:59:41 +000099GrContext::~GrContext() {
robertphillipsea461502015-05-26 11:38:03 -0700100 if (!fGpu) {
bsalomon76228632015-05-29 08:02:10 -0700101 SkASSERT(!fCaps);
bsalomon@google.com733c0622013-04-24 17:59:32 +0000102 return;
103 }
104
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000105 this->flush();
robertphillips@google.com5acc0e32012-05-17 12:01:02 +0000106
robertphillips77a2e522015-10-17 07:43:27 -0700107 fDrawingManager->cleanup();
robertphillips2334fb62015-06-17 05:43:33 -0700108
robertphillips@google.com950b1b02013-10-21 17:37:28 +0000109 for (int i = 0; i < fCleanUpData.count(); ++i) {
110 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
111 }
112
halcanary385fe4d2015-08-26 13:07:48 -0700113 delete fResourceProvider;
114 delete fResourceCache;
115 delete fBatchFontCache;
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000116
bsalomon@google.com205d4602011-04-25 12:43:45 +0000117 fGpu->unref();
bsalomon76228632015-05-29 08:02:10 -0700118 fCaps->unref();
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000119 SkSafeUnref(fPathRendererChain);
120 SkSafeUnref(fSoftwarePathRenderer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000121}
122
bsalomon2354f842014-07-28 13:48:36 -0700123void GrContext::abandonContext() {
bsalomond309e7a2015-04-30 14:18:54 -0700124 fResourceProvider->abandon();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000125 // abandon first to so destructors
126 // don't try to free the resources in the API.
bsalomon0ea80f42015-02-11 10:49:59 -0800127 fResourceCache->abandonAll();
bsalomonc8dc1f72014-08-21 13:02:13 -0700128
robertphillipse3371302014-09-17 06:01:06 -0700129 fGpu->contextAbandoned();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000130
bsalomon@google.com30085192011-08-19 15:42:31 +0000131 // a path renderer may be holding onto resources that
132 // are now unusable
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000133 SkSafeSetNull(fPathRendererChain);
134 SkSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com30085192011-08-19 15:42:31 +0000135
robertphillips77a2e522015-10-17 07:43:27 -0700136 fDrawingManager->abandon();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000137
joshualitt7c3a2f82015-03-31 13:32:05 -0700138 fBatchFontCache->freeAll();
robertphillips@google.come930a072014-04-03 00:34:27 +0000139 fLayerCache->freeAll();
joshualitt26ffc002015-04-16 11:24:04 -0700140 fTextBlobCache->freeAll();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000141}
142
bsalomon@google.com0a208a12013-06-28 18:57:35 +0000143void GrContext::resetContext(uint32_t state) {
144 fGpu->markContextDirty(state);
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000145}
146
147void GrContext::freeGpuResources() {
148 this->flush();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000149
joshualitt7c3a2f82015-03-31 13:32:05 -0700150 fBatchFontCache->freeAll();
robertphillips@google.come930a072014-04-03 00:34:27 +0000151 fLayerCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000152 // a path renderer may be holding onto resources
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000153 SkSafeSetNull(fPathRendererChain);
154 SkSafeSetNull(fSoftwarePathRenderer);
bsalomon3033b9f2015-04-13 11:09:56 -0700155
156 fResourceCache->purgeAllUnlocked();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000157}
158
commit-bot@chromium.org95c20032014-05-09 14:29:32 +0000159void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
bsalomon71cb0c22014-11-14 12:10:14 -0800160 if (resourceCount) {
bsalomon0ea80f42015-02-11 10:49:59 -0800161 *resourceCount = fResourceCache->getBudgetedResourceCount();
bsalomon71cb0c22014-11-14 12:10:14 -0800162 }
163 if (resourceBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -0800164 *resourceBytes = fResourceCache->getBudgetedResourceBytes();
bsalomon71cb0c22014-11-14 12:10:14 -0800165 }
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000166}
167
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000168////////////////////////////////////////////////////////////////////////////////
169
bsalomon71cb0c22014-11-14 12:10:14 -0800170void GrContext::OverBudgetCB(void* data) {
bsalomon66a450f2014-11-13 13:19:10 -0800171 SkASSERT(data);
bsalomonf21dab92014-11-13 13:33:28 -0800172
bsalomon66a450f2014-11-13 13:19:10 -0800173 GrContext* context = reinterpret_cast<GrContext*>(data);
bsalomonf21dab92014-11-13 13:33:28 -0800174
joshualittb542bae2015-07-28 09:58:39 -0700175 // Flush the GrBufferedDrawTarget to possibly free up some textures
bsalomonf21dab92014-11-13 13:33:28 -0800176 context->fFlushToReduceCacheSize = true;
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000177}
178
joshualitt0db6dfa2015-04-10 07:01:30 -0700179void GrContext::TextBlobCacheOverBudgetCB(void* data) {
180 SkASSERT(data);
181
182 // Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level, therefore they
183 // cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush. The solution is to move
184 // drawText calls to below the GrContext level, but this is not trivial because they call
185 // drawPath on SkGpuDevice
186 GrContext* context = reinterpret_cast<GrContext*>(data);
187 context->flush();
188}
189
bsalomon@google.com27847de2011-02-22 20:59:41 +0000190////////////////////////////////////////////////////////////////////////////////
191
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000192void GrContext::flush(int flagsBitfield) {
robertphillipsea461502015-05-26 11:38:03 -0700193 RETURN_IF_ABANDONED
robertphillips@google.come7db8d62013-07-04 11:48:52 +0000194
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000195 if (kDiscard_FlushBit & flagsBitfield) {
robertphillips77a2e522015-10-17 07:43:27 -0700196 fDrawingManager->reset();
bsalomon@google.coma7f84e12011-03-10 14:13:19 +0000197 } else {
robertphillips77a2e522015-10-17 07:43:27 -0700198 fDrawingManager->flush();
junov@google.com53a55842011-06-08 22:55:10 +0000199 }
bsalomon3f324322015-04-08 11:01:54 -0700200 fResourceCache->notifyFlushOccurred();
bsalomonf21dab92014-11-13 13:33:28 -0800201 fFlushToReduceCacheSize = false;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000202}
203
bsalomon81beccc2014-10-13 12:32:55 -0700204bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
205 const void* inPixels, size_t outRowBytes, void* outPixels) {
206 SkSrcPixelInfo srcPI;
halcanary96fcdcc2015-08-27 07:41:13 -0700207 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, nullptr)) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000208 return false;
209 }
bsalomon81beccc2014-10-13 12:32:55 -0700210 srcPI.fAlphaType = kUnpremul_SkAlphaType;
211 srcPI.fPixels = inPixels;
212 srcPI.fRowBytes = inRowBytes;
213
214 SkDstPixelInfo dstPI;
215 dstPI.fColorType = srcPI.fColorType;
216 dstPI.fAlphaType = kPremul_SkAlphaType;
217 dstPI.fPixels = outPixels;
218 dstPI.fRowBytes = outRowBytes;
219
220 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.com669fdc42011-04-05 17:08:27 +0000221}
222
bsalomon81beccc2014-10-13 12:32:55 -0700223bool GrContext::writeSurfacePixels(GrSurface* surface,
224 int left, int top, int width, int height,
225 GrPixelConfig srcConfig, const void* buffer, size_t rowBytes,
226 uint32_t pixelOpsFlags) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800227 RETURN_FALSE_IF_ABANDONED
bsalomon6c6f6582015-09-10 08:12:46 -0700228 ASSERT_OWNED_RESOURCE(surface);
229 SkASSERT(surface);
230
231 this->testPMConversionsIfNecessary(pixelOpsFlags);
bsalomon81beccc2014-10-13 12:32:55 -0700232
bsalomone8d21e82015-07-16 08:23:13 -0700233 // 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 -0700234 // necessary and because GrGpu::getWritePixelsInfo requires it.
bsalomone8d21e82015-07-16 08:23:13 -0700235 if (!GrSurfacePriv::AdjustWritePixelParams(surface->width(), surface->height(),
236 GrBytesPerPixel(srcConfig), &left, &top, &width,
237 &height, &buffer, &rowBytes)) {
238 return false;
239 }
240
bsalomonf0674512015-07-28 13:26:15 -0700241 bool applyPremulToSrc = false;
bsalomon81beccc2014-10-13 12:32:55 -0700242 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) {
243 if (!GrPixelConfigIs8888(srcConfig)) {
244 return false;
245 }
bsalomonf0674512015-07-28 13:26:15 -0700246 applyPremulToSrc = true;
247 }
bsalomon636e8022015-07-29 06:08:46 -0700248
249 GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
250 // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
251 // we've already determined that there isn't a roundtrip preserving conversion processor pair.
252 if (applyPremulToSrc && !this->didFailPMUPMConversionTest()) {
253 drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference;
254 }
255
bsalomonf0674512015-07-28 13:26:15 -0700256 GrGpu::WritePixelTempDrawInfo tempDrawInfo;
257 if (!fGpu->getWritePixelsInfo(surface, width, height, rowBytes, srcConfig, &drawPreference,
258 &tempDrawInfo)) {
259 return false;
260 }
261
262 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) && surface->surfacePriv().hasPendingIO()) {
263 this->flush();
264 }
265
266 SkAutoTUnref<GrTexture> tempTexture;
267 if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
bsalomoneae62002015-07-31 13:59:30 -0700268 tempTexture.reset(
269 this->textureProvider()->createApproxTexture(tempDrawInfo.fTempSurfaceDesc));
bsalomonf0674512015-07-28 13:26:15 -0700270 if (!tempTexture && GrGpu::kRequireDraw_DrawPreference == drawPreference) {
271 return false;
272 }
273 }
274
275 // temp buffer for doing sw premul conversion, if needed.
benjaminwagner7d974f52015-10-19 13:55:55 -0700276#if defined(GOOGLE3)
277 // Stack frame size is limited in GOOGLE3.
278 SkAutoSTMalloc<48 * 48, uint32_t> tmpPixels(0);
279#else
bsalomonf0674512015-07-28 13:26:15 -0700280 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
benjaminwagner7d974f52015-10-19 13:55:55 -0700281#endif
bsalomonf0674512015-07-28 13:26:15 -0700282 if (tempTexture) {
283 SkAutoTUnref<const GrFragmentProcessor> fp;
284 SkMatrix textureMatrix;
285 textureMatrix.setIDiv(tempTexture->width(), tempTexture->height());
286 GrPaint paint;
287 if (applyPremulToSrc) {
bsalomon4a339522015-10-06 08:40:50 -0700288 fp.reset(this->createUPMToPMEffect(tempTexture, tempDrawInfo.fSwapRAndB,
289 textureMatrix));
bsalomonf0674512015-07-28 13:26:15 -0700290 // If premultiplying was the only reason for the draw, fall back to a straight write.
291 if (!fp) {
292 if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
halcanary96fcdcc2015-08-27 07:41:13 -0700293 tempTexture.reset(nullptr);
bsalomonf0674512015-07-28 13:26:15 -0700294 }
295 } else {
296 applyPremulToSrc = false;
297 }
298 }
299 if (tempTexture) {
300 if (!fp) {
bsalomon4a339522015-10-06 08:40:50 -0700301 fp.reset(GrConfigConversionEffect::Create(tempTexture, tempDrawInfo.fSwapRAndB,
bsalomonf0674512015-07-28 13:26:15 -0700302 GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
303 if (!fp) {
304 return false;
305 }
306 }
307 GrRenderTarget* renderTarget = surface->asRenderTarget();
308 SkASSERT(renderTarget);
309 if (tempTexture->surfacePriv().hasPendingIO()) {
310 this->flush();
311 }
312 if (applyPremulToSrc) {
313 size_t tmpRowBytes = 4 * width;
314 tmpPixels.reset(width * height);
315 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
316 tmpPixels.get())) {
317 return false;
318 }
319 rowBytes = tmpRowBytes;
320 buffer = tmpPixels.get();
321 applyPremulToSrc = false;
322 }
bsalomon6cb3cbe2015-07-30 07:34:27 -0700323 if (!fGpu->writePixels(tempTexture, 0, 0, width, height,
324 tempDrawInfo.fTempSurfaceDesc.fConfig, buffer,
325 rowBytes)) {
bsalomonf0674512015-07-28 13:26:15 -0700326 return false;
327 }
328 SkMatrix matrix;
329 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
robertphillips2e1e51f2015-10-15 08:01:48 -0700330 SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(renderTarget));
bsalomonf0674512015-07-28 13:26:15 -0700331 if (!drawContext) {
332 return false;
333 }
bsalomonac856c92015-08-27 06:30:17 -0700334 paint.addColorFragmentProcessor(fp);
bsalomonf0674512015-07-28 13:26:15 -0700335 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
robertphillips2e1e51f2015-10-15 08:01:48 -0700336 drawContext->drawRect(GrClip::WideOpen(), paint, matrix, rect, nullptr);
bsalomonf0674512015-07-28 13:26:15 -0700337
338 if (kFlushWrites_PixelOp & pixelOpsFlags) {
339 this->flushSurfaceWrites(surface);
340 }
341 }
342 }
343 if (!tempTexture) {
bsalomonf0674512015-07-28 13:26:15 -0700344 if (applyPremulToSrc) {
bsalomon81beccc2014-10-13 12:32:55 -0700345 size_t tmpRowBytes = 4 * width;
346 tmpPixels.reset(width * height);
347 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
348 tmpPixels.get())) {
349 return false;
350 }
351 rowBytes = tmpRowBytes;
352 buffer = tmpPixels.get();
bsalomonf0674512015-07-28 13:26:15 -0700353 applyPremulToSrc = false;
bsalomon81beccc2014-10-13 12:32:55 -0700354 }
bsalomon6cb3cbe2015-07-30 07:34:27 -0700355 return fGpu->writePixels(surface, left, top, width, height, srcConfig, buffer, rowBytes);
bsalomon81beccc2014-10-13 12:32:55 -0700356 }
bsalomon81beccc2014-10-13 12:32:55 -0700357 return true;
358}
bsalomon@google.coma91e9232012-02-23 15:39:54 +0000359
bsalomone8d21e82015-07-16 08:23:13 -0700360bool GrContext::readSurfacePixels(GrSurface* src,
361 int left, int top, int width, int height,
362 GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
363 uint32_t flags) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800364 RETURN_FALSE_IF_ABANDONED
bsalomone8d21e82015-07-16 08:23:13 -0700365 ASSERT_OWNED_RESOURCE(src);
366 SkASSERT(src);
bsalomon32ab2602015-09-09 18:57:49 -0700367
bsalomon6c6f6582015-09-10 08:12:46 -0700368 this->testPMConversionsIfNecessary(flags);
369 SkAutoMutexAcquire ama(fReadPixelsMutex);
370
bsalomone8d21e82015-07-16 08:23:13 -0700371 // Adjust the params so that if we wind up using an intermediate surface we've already done
372 // all the trimming and the temporary can be the min size required.
373 if (!GrSurfacePriv::AdjustReadPixelParams(src->width(), src->height(),
374 GrBytesPerPixel(dstConfig), &left,
375 &top, &width, &height, &buffer, &rowBytes)) {
376 return false;
377 }
378
379 if (!(kDontFlush_PixelOpsFlag & flags) && src->surfacePriv().hasPendingWrite()) {
bsalomon@google.com6f379512011-11-16 20:36:03 +0000380 this->flush();
381 }
bsalomon@google.comc4364992011-11-07 15:54:49 +0000382
bsalomone8d21e82015-07-16 08:23:13 -0700383 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
bsalomon@google.com9c680582013-02-06 18:17:50 +0000384 if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
bsalomon39826022015-07-23 08:07:21 -0700385 // The unpremul flag is only allowed for 8888 configs.
bsalomon@google.com0a97be22011-11-08 19:20:57 +0000386 return false;
387 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000388
bsalomon636e8022015-07-29 06:08:46 -0700389 GrGpu::DrawPreference drawPreference = GrGpu::kNoDraw_DrawPreference;
390 // Don't prefer to draw for the conversion (and thereby access a texture from the cache) when
391 // we've already determined that there isn't a roundtrip preserving conversion processor pair.
392 if (unpremul && !this->didFailPMUPMConversionTest()) {
393 drawPreference = GrGpu::kCallerPrefersDraw_DrawPreference;
394 }
395
bsalomon39826022015-07-23 08:07:21 -0700396 GrGpu::ReadPixelTempDrawInfo tempDrawInfo;
397 if (!fGpu->getReadPixelsInfo(src, width, height, rowBytes, dstConfig, &drawPreference,
398 &tempDrawInfo)) {
399 return false;
400 }
bsalomon191bcc02014-11-14 11:31:13 -0800401
bsalomon6cb3cbe2015-07-30 07:34:27 -0700402 SkAutoTUnref<GrSurface> surfaceToRead(SkRef(src));
bsalomon39826022015-07-23 08:07:21 -0700403 bool didTempDraw = false;
404 if (GrGpu::kNoDraw_DrawPreference != drawPreference) {
bsalomon39826022015-07-23 08:07:21 -0700405 if (tempDrawInfo.fUseExactScratch) {
406 // We only respect this when the entire src is being read. Otherwise we can trigger too
407 // many odd ball texture sizes and trash the cache.
bsalomoneae62002015-07-31 13:59:30 -0700408 if (width != src->width() || height != src->height()) {
409 tempDrawInfo.fUseExactScratch = false;
bsalomon39826022015-07-23 08:07:21 -0700410 }
bsalomon@google.com56d11e02011-11-30 19:59:08 +0000411 }
bsalomon39826022015-07-23 08:07:21 -0700412 SkAutoTUnref<GrTexture> temp;
bsalomoneae62002015-07-31 13:59:30 -0700413 if (tempDrawInfo.fUseExactScratch) {
414 temp.reset(this->textureProvider()->createTexture(tempDrawInfo.fTempSurfaceDesc, true));
415 } else {
416 temp.reset(this->textureProvider()->createApproxTexture(tempDrawInfo.fTempSurfaceDesc));
417 }
bsalomon39826022015-07-23 08:07:21 -0700418 if (temp) {
bsalomon@google.comb9086a02012-11-01 18:02:54 +0000419 SkMatrix textureMatrix;
bsalomon39826022015-07-23 08:07:21 -0700420 textureMatrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000421 textureMatrix.postIDiv(src->width(), src->height());
joshualitt5f10b5c2015-07-09 10:24:35 -0700422 GrPaint paint;
joshualittb0a8a372014-09-23 09:50:21 -0700423 SkAutoTUnref<const GrFragmentProcessor> fp;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000424 if (unpremul) {
bsalomon4a339522015-10-06 08:40:50 -0700425 fp.reset(this->createPMToUPMEffect(src->asTexture(), tempDrawInfo.fSwapRAndB,
bsalomon39826022015-07-23 08:07:21 -0700426 textureMatrix));
joshualittb0a8a372014-09-23 09:50:21 -0700427 if (fp) {
bsalomon@google.com9c680582013-02-06 18:17:50 +0000428 unpremul = false; // we no longer need to do this on CPU after the read back.
bsalomon39826022015-07-23 08:07:21 -0700429 } else if (GrGpu::kCallerPrefersDraw_DrawPreference == drawPreference) {
430 // We only wanted to do the draw in order to perform the unpremul so don't
431 // bother.
halcanary96fcdcc2015-08-27 07:41:13 -0700432 temp.reset(nullptr);
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000433 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000434 }
bsalomon39826022015-07-23 08:07:21 -0700435 if (!fp && temp) {
bsalomon4a339522015-10-06 08:40:50 -0700436 fp.reset(GrConfigConversionEffect::Create(src->asTexture(), tempDrawInfo.fSwapRAndB,
bsalomon39826022015-07-23 08:07:21 -0700437 GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
438 }
439 if (fp) {
bsalomonac856c92015-08-27 06:30:17 -0700440 paint.addColorFragmentProcessor(fp);
bsalomon39826022015-07-23 08:07:21 -0700441 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
robertphillips2e1e51f2015-10-15 08:01:48 -0700442 SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(temp->asRenderTarget()));
443 drawContext->drawRect(GrClip::WideOpen(), paint, SkMatrix::I(), rect, nullptr);
bsalomon6cb3cbe2015-07-30 07:34:27 -0700444 surfaceToRead.reset(SkRef(temp.get()));
bsalomon39826022015-07-23 08:07:21 -0700445 left = 0;
446 top = 0;
447 didTempDraw = true;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000448 }
bsalomon@google.com0342a852012-08-20 19:22:38 +0000449 }
bsalomon@google.comc4364992011-11-07 15:54:49 +0000450 }
joshualitt5c55fef2014-10-31 14:04:35 -0700451
bsalomon39826022015-07-23 08:07:21 -0700452 if (GrGpu::kRequireDraw_DrawPreference == drawPreference && !didTempDraw) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000453 return false;
454 }
bsalomon39826022015-07-23 08:07:21 -0700455 GrPixelConfig configToRead = dstConfig;
456 if (didTempDraw) {
bsalomon6cb3cbe2015-07-30 07:34:27 -0700457 this->flushSurfaceWrites(surfaceToRead);
bsalomon39826022015-07-23 08:07:21 -0700458 // We swapped R and B while doing the temp draw. Swap back on the read.
459 if (tempDrawInfo.fSwapRAndB) {
460 configToRead = GrPixelConfigSwapRAndB(dstConfig);
461 }
462 }
bsalomon6cb3cbe2015-07-30 07:34:27 -0700463 if (!fGpu->readPixels(surfaceToRead, left, top, width, height, configToRead, buffer,
464 rowBytes)) {
bsalomon39826022015-07-23 08:07:21 -0700465 return false;
466 }
467
468 // Perform umpremul conversion if we weren't able to perform it as a draw.
469 if (unpremul) {
reed@google.com7111d462014-03-25 16:20:24 +0000470 SkDstPixelInfo dstPI;
halcanary96fcdcc2015-08-27 07:41:13 -0700471 if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, nullptr)) {
reed@google.com7111d462014-03-25 16:20:24 +0000472 return false;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000473 }
reed@google.com7111d462014-03-25 16:20:24 +0000474 dstPI.fAlphaType = kUnpremul_SkAlphaType;
475 dstPI.fPixels = buffer;
476 dstPI.fRowBytes = rowBytes;
477
478 SkSrcPixelInfo srcPI;
bsalomon39826022015-07-23 08:07:21 -0700479 srcPI.fColorType = dstPI.fColorType;
reed@google.com7111d462014-03-25 16:20:24 +0000480 srcPI.fAlphaType = kPremul_SkAlphaType;
481 srcPI.fPixels = buffer;
482 srcPI.fRowBytes = rowBytes;
483
484 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000485 }
486 return true;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000487}
488
bsalomonc49e8682015-06-30 11:37:35 -0700489void GrContext::prepareSurfaceForExternalIO(GrSurface* surface) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800490 RETURN_IF_ABANDONED
bsalomon87a94eb2014-11-03 14:28:32 -0800491 SkASSERT(surface);
492 ASSERT_OWNED_RESOURCE(surface);
493 if (surface->surfacePriv().hasPendingIO()) {
494 this->flush();
495 }
496 GrRenderTarget* rt = surface->asRenderTarget();
497 if (fGpu && rt) {
498 fGpu->resolveRenderTarget(rt);
bsalomon41ebbdd2014-08-04 08:31:39 -0700499 }
bsalomon@google.com75f9f252012-01-31 13:35:56 +0000500}
501
bsalomonf80bfed2014-10-07 05:56:02 -0700502void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
503 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800504 RETURN_IF_ABANDONED
robertphillipsea461502015-05-26 11:38:03 -0700505 if (!src || !dst) {
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000506 return;
507 }
bsalomone3d4bf22014-09-23 09:15:03 -0700508 ASSERT_OWNED_RESOURCE(src);
junov2bb52102014-09-29 10:18:59 -0700509 ASSERT_OWNED_RESOURCE(dst);
Brian Salomon34a98952014-09-24 11:41:24 -0400510
bsalomonf80bfed2014-10-07 05:56:02 -0700511 // Since we're going to the draw target and not GPU, no need to check kNoFlush
512 // here.
robertphillipsea461502015-05-26 11:38:03 -0700513 if (!dst->asRenderTarget()) {
junov96c118e2014-09-26 13:09:47 -0700514 return;
515 }
robertphillipsea461502015-05-26 11:38:03 -0700516
robertphillips2e1e51f2015-10-15 08:01:48 -0700517 SkAutoTUnref<GrDrawContext> drawContext(this->drawContext(dst->asRenderTarget()));
robertphillipsea461502015-05-26 11:38:03 -0700518 if (!drawContext) {
519 return;
520 }
521
robertphillips2e1e51f2015-10-15 08:01:48 -0700522 drawContext->copySurface(src, srcRect, dstPoint);
bsalomonf80bfed2014-10-07 05:56:02 -0700523
524 if (kFlushWrites_PixelOp & pixelOpsFlags) {
525 this->flush();
526 }
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +0000527}
528
bsalomonf80bfed2014-10-07 05:56:02 -0700529void GrContext::flushSurfaceWrites(GrSurface* surface) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800530 RETURN_IF_ABANDONED
bsalomonf80bfed2014-10-07 05:56:02 -0700531 if (surface->surfacePriv().hasPendingWrite()) {
532 this->flush();
533 }
534}
535
robertphillips@google.com72176b22012-05-23 13:19:12 +0000536/*
537 * This method finds a path renderer that can draw the specified path on
538 * the provided target.
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000539 * Due to its expense, the software path renderer has split out so it can
robertphillips@google.com72176b22012-05-23 13:19:12 +0000540 * can be individually allowed/disallowed via the "allowSW" boolean.
541 */
joshualitt9853cce2014-11-17 14:22:48 -0800542GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800543 const GrPipelineBuilder* pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -0800544 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800545 const SkPath& path,
kkinnunen18996512015-04-26 23:18:49 -0700546 const GrStrokeInfo& stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000547 bool allowSW,
548 GrPathRendererChain::DrawType drawType,
549 GrPathRendererChain::StencilSupport* stencilSupport) {
550
robertphillipsea461502015-05-26 11:38:03 -0700551 if (!fPathRendererChain) {
halcanary385fe4d2015-08-26 13:07:48 -0700552 fPathRendererChain = new GrPathRendererChain(this);
bsalomon@google.com30085192011-08-19 15:42:31 +0000553 }
robertphillips@google.com72176b22012-05-23 13:19:12 +0000554
joshualitt9853cce2014-11-17 14:22:48 -0800555 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target,
egdaniel8dd688b2015-01-22 10:16:09 -0800556 pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -0800557 viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800558 path,
sugoi@google.com12b4e272012-12-06 20:13:11 +0000559 stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +0000560 drawType,
561 stencilSupport);
robertphillips@google.com72176b22012-05-23 13:19:12 +0000562
robertphillipsea461502015-05-26 11:38:03 -0700563 if (!pr && allowSW) {
564 if (!fSoftwarePathRenderer) {
halcanary385fe4d2015-08-26 13:07:48 -0700565 fSoftwarePathRenderer = new GrSoftwarePathRenderer(this);
robertphillips@google.com72176b22012-05-23 13:19:12 +0000566 }
robertphillips@google.com72176b22012-05-23 13:19:12 +0000567 pr = fSoftwarePathRenderer;
568 }
569
570 return pr;
bsalomon@google.com30085192011-08-19 15:42:31 +0000571}
572
bsalomon@google.com27847de2011-02-22 20:59:41 +0000573////////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000574int GrContext::getRecommendedSampleCount(GrPixelConfig config,
575 SkScalar dpi) const {
bsalomon76228632015-05-29 08:02:10 -0700576 if (!this->caps()->isConfigRenderable(config, true)) {
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000577 return 0;
578 }
579 int chosenSampleCount = 0;
jvanverthe9c0fc62015-04-29 11:18:05 -0700580 if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) {
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +0000581 if (dpi >= 250.0f) {
582 chosenSampleCount = 4;
583 } else {
584 chosenSampleCount = 16;
585 }
586 }
587 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ?
588 chosenSampleCount : 0;
589}
590
robertphillips77a2e522015-10-17 07:43:27 -0700591
592GrDrawContext* GrContext::drawContext(GrRenderTarget* rt, const SkSurfaceProps* surfaceProps) {
593 return fDrawingManager->drawContext(rt, surfaceProps);
594}
595
596bool GrContext::abandoned() const {
597 return fDrawingManager->abandoned();
598}
599
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000600namespace {
601void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
602 GrConfigConversionEffect::PMConversion pmToUPM;
603 GrConfigConversionEffect::PMConversion upmToPM;
604 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
605 *pmToUPMValue = pmToUPM;
606 *upmToPMValue = upmToPM;
607}
608}
609
bsalomon6c6f6582015-09-10 08:12:46 -0700610void GrContext::testPMConversionsIfNecessary(uint32_t flags) {
611 if (SkToBool(kUnpremul_PixelOpsFlag & flags)) {
612 SkAutoMutexAcquire ama(fTestPMConversionsMutex);
613 if (!fDidTestPMConversions) {
614 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
615 fDidTestPMConversions = true;
616 }
617 }
618}
619
bsalomon4a339522015-10-06 08:40:50 -0700620const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
joshualittb0a8a372014-09-23 09:50:21 -0700621 bool swapRAndB,
bsalomon6c6f6582015-09-10 08:12:46 -0700622 const SkMatrix& matrix) const {
623 // We should have already called this->testPMConversionsIfNecessary().
624 SkASSERT(fDidTestPMConversions);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000625 GrConfigConversionEffect::PMConversion pmToUPM =
626 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
627 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
bsalomon4a339522015-10-06 08:40:50 -0700628 return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000629 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700630 return nullptr;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000631 }
632}
633
bsalomon4a339522015-10-06 08:40:50 -0700634const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
joshualittb0a8a372014-09-23 09:50:21 -0700635 bool swapRAndB,
bsalomon6c6f6582015-09-10 08:12:46 -0700636 const SkMatrix& matrix) const {
637 // We should have already called this->testPMConversionsIfNecessary().
638 SkASSERT(fDidTestPMConversions);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000639 GrConfigConversionEffect::PMConversion upmToPM =
640 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
641 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
bsalomon4a339522015-10-06 08:40:50 -0700642 return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000643 } else {
halcanary96fcdcc2015-08-27 07:41:13 -0700644 return nullptr;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +0000645 }
646}
647
bsalomon636e8022015-07-29 06:08:46 -0700648bool GrContext::didFailPMUPMConversionTest() const {
bsalomon6c6f6582015-09-10 08:12:46 -0700649 // We should have already called this->testPMConversionsIfNecessary().
650 SkASSERT(fDidTestPMConversions);
bsalomon636e8022015-07-29 06:08:46 -0700651 // The PM<->UPM tests fail or succeed together so we only need to check one.
bsalomon6c6f6582015-09-10 08:12:46 -0700652 return GrConfigConversionEffect::kNone_PMConversion == fPMToUPMConversion;
bsalomon636e8022015-07-29 06:08:46 -0700653}
654
bsalomon37f9a262015-02-02 13:00:10 -0800655//////////////////////////////////////////////////////////////////////////////
656
657void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
658 if (maxTextures) {
bsalomon0ea80f42015-02-11 10:49:59 -0800659 *maxTextures = fResourceCache->getMaxResourceCount();
bsalomon37f9a262015-02-02 13:00:10 -0800660 }
661 if (maxTextureBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -0800662 *maxTextureBytes = fResourceCache->getMaxResourceBytes();
bsalomon37f9a262015-02-02 13:00:10 -0800663 }
664}
665
666void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -0800667 fResourceCache->setLimits(maxTextures, maxTextureBytes);
bsalomon37f9a262015-02-02 13:00:10 -0800668}
669
ericrk0a5fa482015-09-15 14:16:10 -0700670//////////////////////////////////////////////////////////////////////////////
671
672void GrContext::dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const {
673 fResourceCache->dumpMemoryStatistics(traceMemoryDump);
674}