blob: 48e50b7717065f9b8b105549d14b2c746b34ec03 [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"
10
jvanverth@google.combfe2b9d2013-09-06 16:57:29 +000011#include "GrAARectRenderer.h"
joshualitt1d89e8d2015-04-01 12:40:54 -070012#include "GrAtlasTextContext.h"
joshualitt0823bfa2015-02-27 10:06:15 -080013#include "GrBatch.h"
joshualitt7c3a2f82015-03-31 13:32:05 -070014#include "GrBatchFontCache.h"
joshualitt0823bfa2015-02-27 10:06:15 -080015#include "GrBatchTarget.h"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000016#include "GrBufferAllocPool.h"
joshualitt5478d422014-11-14 16:00:38 -080017#include "GrDefaultGeoProcFactory.h"
jvanverth787cdf92014-12-04 10:46:50 -080018#include "GrFontCache.h"
bsalomon453cf402014-11-11 14:15:57 -080019#include "GrGpuResource.h"
bsalomon3582d3e2015-02-13 14:20:05 -080020#include "GrGpuResourcePriv.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070021#include "GrDistanceFieldTextContext.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000022#include "GrDrawTargetCaps.h"
joshualitt5478d422014-11-14 16:00:38 -080023#include "GrGpu.h"
commit-bot@chromium.orgdcb8ef92014-03-27 11:26:10 +000024#include "GrIndexBuffer.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000025#include "GrInOrderDrawBuffer.h"
robertphillips@google.come930a072014-04-03 00:34:27 +000026#include "GrLayerCache.h"
commit-bot@chromium.org81312832013-03-22 18:34:09 +000027#include "GrOvalRenderer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000028#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000029#include "GrPathUtils.h"
bsalomon6bc1b5f2015-02-23 09:06:38 -080030#include "GrRenderTargetPriv.h"
bsalomon0ea80f42015-02-11 10:49:59 -080031#include "GrResourceCache.h"
robertphillips@google.com72176b22012-05-23 13:19:12 +000032#include "GrSoftwarePathRenderer.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070033#include "GrStencilAndCoverTextContext.h"
egdanield58a0ba2014-06-11 10:30:05 -070034#include "GrStrokeInfo.h"
bsalomonafbf2d62014-09-30 12:18:44 -070035#include "GrSurfacePriv.h"
joshualittb7133be2015-04-08 09:08:31 -070036#include "GrTextBlobCache.h"
bsalomonafbf2d62014-09-30 12:18:44 -070037#include "GrTexturePriv.h"
egdanielbbcb38d2014-06-19 10:19:29 -070038#include "GrTraceMarker.h"
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +000039#include "GrTracing.h"
egdanield58a0ba2014-06-11 10:30:05 -070040#include "SkDashPathPriv.h"
bsalomon81beccc2014-10-13 12:32:55 -070041#include "SkConfig8888.h"
reed@google.com7111d462014-03-25 16:20:24 +000042#include "SkGr.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000043#include "SkRRect.h"
sugoi@google.com5f74cf82012-12-17 21:16:45 +000044#include "SkStrokeRec.h"
commit-bot@chromium.orgdcb8ef92014-03-27 11:26:10 +000045#include "SkTLazy.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000046#include "SkTLS.h"
commit-bot@chromium.org933e65d2014-03-20 20:00:24 +000047#include "SkTraceEvent.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000048
joshualitt5478d422014-11-14 16:00:38 -080049#include "effects/GrConfigConversionEffect.h"
50#include "effects/GrDashingEffect.h"
51#include "effects/GrSingleTextureEffect.h"
52
bsalomon@google.com60361492012-03-15 17:47:06 +000053static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000054static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
55
bsalomon@google.com1d4edd32012-08-16 18:36:06 +000056static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11;
57static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4;
bsalomon@google.com27847de2011-02-22 20:59:41 +000058
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000059#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
joshualitt5f5a8d72015-02-25 14:09:45 -080060#define RETURN_IF_ABANDONED if (!fDrawBuffer) { return; }
61#define RETURN_FALSE_IF_ABANDONED if (!fDrawBuffer) { return false; }
62#define RETURN_NULL_IF_ABANDONED if (!fDrawBuffer) { return NULL; }
bsalomon@google.combc4b6542011-11-19 13:56:11 +000063
bsalomonf21dab92014-11-13 13:33:28 -080064class GrContext::AutoCheckFlush {
65public:
66 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
67
68 ~AutoCheckFlush() {
69 if (fContext->fFlushToReduceCacheSize) {
70 fContext->flush();
71 }
72 }
73
74private:
75 GrContext* fContext;
76};
77
krajcevski9c6d4d72014-08-12 07:26:25 -070078GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
79 const Options* opts) {
80 GrContext* context;
81 if (NULL == opts) {
82 context = SkNEW_ARGS(GrContext, (Options()));
83 } else {
84 context = SkNEW_ARGS(GrContext, (*opts));
85 }
86
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000087 if (context->init(backend, backendContext)) {
88 return context;
89 } else {
90 context->unref();
91 return NULL;
bsalomon@google.com27847de2011-02-22 20:59:41 +000092 }
bsalomon@google.com27847de2011-02-22 20:59:41 +000093}
94
krajcevski9c6d4d72014-08-12 07:26:25 -070095GrContext::GrContext(const Options& opts) : fOptions(opts) {
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000096 fGpu = NULL;
97 fPathRendererChain = NULL;
98 fSoftwarePathRenderer = NULL;
bsalomon0ea80f42015-02-11 10:49:59 -080099 fResourceCache = NULL;
joshualitt7c3a2f82015-03-31 13:32:05 -0700100 fBatchFontCache = NULL;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000101 fFontCache = NULL;
102 fDrawBuffer = NULL;
103 fDrawBufferVBAllocPool = NULL;
104 fDrawBufferIBAllocPool = NULL;
bsalomonf21dab92014-11-13 13:33:28 -0800105 fFlushToReduceCacheSize = false;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000106 fAARectRenderer = NULL;
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000107 fOvalRenderer = NULL;
robertphillips@google.com44a91dc2013-07-25 15:32:06 +0000108 fMaxTextureSizeOverride = 1 << 20;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000109}
110
111bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000112 SkASSERT(NULL == fGpu);
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000113
114 fGpu = GrGpu::Create(backend, backendContext, this);
115 if (NULL == fGpu) {
116 return false;
117 }
bsalomon33435572014-11-05 14:47:41 -0800118 this->initCommon();
119 return true;
120}
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000121
bsalomon33435572014-11-05 14:47:41 -0800122void GrContext::initCommon() {
bsalomon0ea80f42015-02-11 10:49:59 -0800123 fResourceCache = SkNEW(GrResourceCache);
124 fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
commit-bot@chromium.org1836d332013-07-16 22:55:03 +0000125
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000126 fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
127
robertphillips4ec84da2014-06-24 13:10:43 -0700128 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this)));
robertphillips@google.come930a072014-04-03 00:34:27 +0000129
joshualittb44293e2014-10-28 08:12:18 -0700130 fAARectRenderer = SkNEW_ARGS(GrAARectRenderer, (fGpu));
joshualitt5531d512014-12-17 15:50:11 -0800131 fOvalRenderer = SkNEW_ARGS(GrOvalRenderer, (fGpu));
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000132
133 fDidTestPMConversions = false;
134
135 this->setupDrawBuffer();
joshualitt7c3a2f82015-03-31 13:32:05 -0700136
137 // GrBatchFontCache will eventually replace GrFontCache
138 fBatchFontCache = SkNEW(GrBatchFontCache);
139 fBatchFontCache->init(this);
joshualittb7133be2015-04-08 09:08:31 -0700140
141 fTextBlobCache.reset(SkNEW(GrTextBlobCache));
bsalomon@google.comc0af3172012-06-15 14:10:09 +0000142}
143
bsalomon@google.com27847de2011-02-22 20:59:41 +0000144GrContext::~GrContext() {
bsalomon@google.com733c0622013-04-24 17:59:32 +0000145 if (NULL == fGpu) {
146 return;
147 }
148
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000149 this->flush();
robertphillips@google.com5acc0e32012-05-17 12:01:02 +0000150
robertphillips@google.com950b1b02013-10-21 17:37:28 +0000151 for (int i = 0; i < fCleanUpData.count(); ++i) {
152 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
153 }
154
bsalomon0ea80f42015-02-11 10:49:59 -0800155 SkDELETE(fResourceCache);
joshualitt7c3a2f82015-03-31 13:32:05 -0700156 SkDELETE(fBatchFontCache);
bsalomon33435572014-11-05 14:47:41 -0800157 SkDELETE(fFontCache);
158 SkDELETE(fDrawBuffer);
159 SkDELETE(fDrawBufferVBAllocPool);
160 SkDELETE(fDrawBufferIBAllocPool);
bsalomon@google.com30085192011-08-19 15:42:31 +0000161
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000162 fAARectRenderer->unref();
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000163 fOvalRenderer->unref();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000164
bsalomon@google.com205d4602011-04-25 12:43:45 +0000165 fGpu->unref();
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000166 SkSafeUnref(fPathRendererChain);
167 SkSafeUnref(fSoftwarePathRenderer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000168}
169
bsalomon2354f842014-07-28 13:48:36 -0700170void GrContext::abandonContext() {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000171 // abandon first to so destructors
172 // don't try to free the resources in the API.
bsalomon0ea80f42015-02-11 10:49:59 -0800173 fResourceCache->abandonAll();
bsalomonc8dc1f72014-08-21 13:02:13 -0700174
robertphillipse3371302014-09-17 06:01:06 -0700175 fGpu->contextAbandoned();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000176
bsalomon@google.com30085192011-08-19 15:42:31 +0000177 // a path renderer may be holding onto resources that
178 // are now unusable
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000179 SkSafeSetNull(fPathRendererChain);
180 SkSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com30085192011-08-19 15:42:31 +0000181
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000182 delete fDrawBuffer;
183 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000184
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000185 delete fDrawBufferVBAllocPool;
186 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000187
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000188 delete fDrawBufferIBAllocPool;
189 fDrawBufferIBAllocPool = NULL;
190
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000191 fAARectRenderer->reset();
commit-bot@chromium.orgef284a82013-07-11 22:29:29 +0000192 fOvalRenderer->reset();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000193
joshualitt7c3a2f82015-03-31 13:32:05 -0700194 fBatchFontCache->freeAll();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000195 fFontCache->freeAll();
robertphillips@google.come930a072014-04-03 00:34:27 +0000196 fLayerCache->freeAll();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000197}
198
bsalomon@google.com0a208a12013-06-28 18:57:35 +0000199void GrContext::resetContext(uint32_t state) {
200 fGpu->markContextDirty(state);
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000201}
202
203void GrContext::freeGpuResources() {
204 this->flush();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000205
bsalomon49f085d2014-09-05 13:34:00 -0700206 if (fDrawBuffer) {
bsalomonc8dc1f72014-08-21 13:02:13 -0700207 fDrawBuffer->purgeResources();
208 }
robertphillips@google.comff175842012-05-14 19:31:39 +0000209
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000210 fAARectRenderer->reset();
commit-bot@chromium.orgef284a82013-07-11 22:29:29 +0000211 fOvalRenderer->reset();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000212
joshualitt7c3a2f82015-03-31 13:32:05 -0700213 fBatchFontCache->freeAll();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000214 fFontCache->freeAll();
robertphillips@google.come930a072014-04-03 00:34:27 +0000215 fLayerCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000216 // a path renderer may be holding onto resources
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000217 SkSafeSetNull(fPathRendererChain);
218 SkSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000219}
220
commit-bot@chromium.org95c20032014-05-09 14:29:32 +0000221void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
bsalomon71cb0c22014-11-14 12:10:14 -0800222 if (resourceCount) {
bsalomon0ea80f42015-02-11 10:49:59 -0800223 *resourceCount = fResourceCache->getBudgetedResourceCount();
bsalomon71cb0c22014-11-14 12:10:14 -0800224 }
225 if (resourceBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -0800226 *resourceBytes = fResourceCache->getBudgetedResourceBytes();
bsalomon71cb0c22014-11-14 12:10:14 -0800227 }
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000228}
229
kkinnunenc6cb56f2014-06-24 00:12:27 -0700230GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
joshualitt6e8cd962015-03-20 10:30:14 -0700231 SkGpuDevice* gpuDevice,
kkinnunenc6cb56f2014-06-24 00:12:27 -0700232 const SkDeviceProperties&
233 leakyProperties,
234 bool enableDistanceFieldFonts) {
bsalomon6bc1b5f2015-02-23 09:06:38 -0800235 if (fGpu->caps()->pathRenderingSupport() && renderTarget->isMultisampled()) {
236 GrStencilBuffer* sb = renderTarget->renderTargetPriv().attachStencilBuffer();
237 if (sb) {
joshualitt6e8cd962015-03-20 10:30:14 -0700238 return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyProperties);
bsalomon6bc1b5f2015-02-23 09:06:38 -0800239 }
jvanverth8c27a182014-10-14 08:45:50 -0700240 }
241
joshualitt7c3a2f82015-03-31 13:32:05 -0700242#ifdef USE_BITMAP_TEXTBLOBS
joshualittdbd35932015-04-02 09:19:04 -0700243 return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties);
joshualitt7c3a2f82015-03-31 13:32:05 -0700244#else
joshualitt6e8cd962015-03-20 10:30:14 -0700245 return GrDistanceFieldTextContext::Create(this, gpuDevice, leakyProperties,
246 enableDistanceFieldFonts);
joshualitt7c3a2f82015-03-31 13:32:05 -0700247#endif
kkinnunenc6cb56f2014-06-24 00:12:27 -0700248}
249
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000250////////////////////////////////////////////////////////////////////////////////
bsalomond0423582015-02-06 08:49:24 -0800251enum ScratchTextureFlags {
252 kExact_ScratchTextureFlag = 0x1,
253 kNoPendingIO_ScratchTextureFlag = 0x2,
254 kNoCreate_ScratchTextureFlag = 0x4,
255};
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000256
bsalomond2a6f4e2015-02-04 10:55:54 -0800257bool GrContext::isConfigTexturable(GrPixelConfig config) const {
258 return fGpu->caps()->isConfigTexturable(config);
259}
260
261bool GrContext::npotTextureTileSupport() const {
262 return fGpu->caps()->npotTextureTileSupport();
263}
264
bsalomond0423582015-02-06 08:49:24 -0800265GrTexture* GrContext::createTexture(const GrSurfaceDesc& desc, bool budgeted, const void* srcData,
bsalomon37f9a262015-02-02 13:00:10 -0800266 size_t rowBytes) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800267 RETURN_NULL_IF_ABANDONED
bsalomond0423582015-02-06 08:49:24 -0800268 if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) &&
269 !this->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
bsalomond2a6f4e2015-02-04 10:55:54 -0800270 return NULL;
271 }
bsalomond0423582015-02-06 08:49:24 -0800272 if (!GrPixelConfigIsCompressed(desc.fConfig)) {
273 static const uint32_t kFlags = kExact_ScratchTextureFlag |
274 kNoCreate_ScratchTextureFlag;
275 if (GrTexture* texture = this->internalRefScratchTexture(desc, kFlags)) {
276 if (!srcData || texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
277 srcData, rowBytes)) {
278 if (!budgeted) {
bsalomon3582d3e2015-02-13 14:20:05 -0800279 texture->resourcePriv().makeUnbudgeted();
bsalomond0423582015-02-06 08:49:24 -0800280 }
281 return texture;
282 }
283 texture->unref();
284 }
285 }
286 return fGpu->createTexture(desc, budgeted, srcData, rowBytes);
287}
bsalomond2a6f4e2015-02-04 10:55:54 -0800288
bsalomond0423582015-02-06 08:49:24 -0800289GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& desc, ScratchTexMatch match,
290 bool calledDuringFlush) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800291 RETURN_NULL_IF_ABANDONED
bsalomond0423582015-02-06 08:49:24 -0800292 // Currently we don't recycle compressed textures as scratch.
293 if (GrPixelConfigIsCompressed(desc.fConfig)) {
294 return NULL;
295 } else {
296 uint32_t flags = 0;
297 if (kExact_ScratchTexMatch == match) {
298 flags |= kExact_ScratchTextureFlag;
299 }
300 if (calledDuringFlush) {
301 flags |= kNoPendingIO_ScratchTextureFlag;
302 }
303 return this->internalRefScratchTexture(desc, flags);
304 }
305}
306
307GrTexture* GrContext::internalRefScratchTexture(const GrSurfaceDesc& inDesc, uint32_t flags) {
308 SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig));
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000309
bsalomonf2703d82014-10-28 14:33:06 -0700310 SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc);
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000311
bsalomonf2703d82014-10-28 14:33:06 -0700312 if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
bsalomond0423582015-02-06 08:49:24 -0800313 if (!(kExact_ScratchTextureFlag & flags)) {
bsalomonbcf0a522014-10-08 08:40:09 -0700314 // bin by pow2 with a reasonable min
315 static const int MIN_SIZE = 16;
bsalomonf2703d82014-10-28 14:33:06 -0700316 GrSurfaceDesc* wdesc = desc.writable();
bsalomonbcf0a522014-10-08 08:40:09 -0700317 wdesc->fWidth = SkTMax(MIN_SIZE, GrNextPow2(desc->fWidth));
318 wdesc->fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc->fHeight));
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000319 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000320
bsalomon6bc1b5f2015-02-23 09:06:38 -0800321 GrScratchKey key;
322 GrTexturePriv::ComputeScratchKey(*desc, &key);
323 uint32_t scratchFlags = 0;
324 if (kNoPendingIO_ScratchTextureFlag & flags) {
325 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
326 } else if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
327 // If it is not a render target then it will most likely be populated by
328 // writePixels() which will trigger a flush if the texture has pending IO.
329 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
330 }
331 GrGpuResource* resource = fResourceCache->findAndRefScratchResource(key, scratchFlags);
332 if (resource) {
333 GrSurface* surface = static_cast<GrSurface*>(resource);
334 GrRenderTarget* rt = surface->asRenderTarget();
335 if (rt && fGpu->caps()->discardRenderTargetSupport()) {
336 rt->discard();
bsalomon000f8292014-10-15 19:04:14 -0700337 }
bsalomon6bc1b5f2015-02-23 09:06:38 -0800338 return surface->asTexture();
339 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000340 }
341
bsalomond0423582015-02-06 08:49:24 -0800342 if (!(kNoCreate_ScratchTextureFlag & flags)) {
bsalomon3582d3e2015-02-13 14:20:05 -0800343 return fGpu->createTexture(*desc, true, NULL, 0);
bsalomone167f962015-01-27 09:56:04 -0800344 }
bsalomond0423582015-02-06 08:49:24 -0800345
346 return NULL;
Brian Salomon9323b8b2014-10-07 15:07:38 -0400347}
348
bsalomon71cb0c22014-11-14 12:10:14 -0800349void GrContext::OverBudgetCB(void* data) {
bsalomon66a450f2014-11-13 13:19:10 -0800350 SkASSERT(data);
bsalomonf21dab92014-11-13 13:33:28 -0800351
bsalomon66a450f2014-11-13 13:19:10 -0800352 GrContext* context = reinterpret_cast<GrContext*>(data);
bsalomonf21dab92014-11-13 13:33:28 -0800353
354 // Flush the InOrderDrawBuffer to possibly free up some textures
355 context->fFlushToReduceCacheSize = true;
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000356}
357
bsalomon@google.com91958362011-06-13 17:58:13 +0000358int GrContext::getMaxTextureSize() const {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000359 return SkTMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride);
bsalomon@google.com91958362011-06-13 17:58:13 +0000360}
361
362int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.combcce8922013-03-25 15:38:39 +0000363 return fGpu->caps()->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000364}
365
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000366int GrContext::getMaxSampleCount() const {
bsalomon@google.combcce8922013-03-25 15:38:39 +0000367 return fGpu->caps()->maxSampleCount();
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000368}
369
bsalomon@google.com27847de2011-02-22 20:59:41 +0000370///////////////////////////////////////////////////////////////////////////////
371
bsalomon@google.com16e3dde2012-10-25 18:43:28 +0000372GrTexture* GrContext::wrapBackendTexture(const GrBackendTextureDesc& desc) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800373 RETURN_NULL_IF_ABANDONED
bsalomon@google.com16e3dde2012-10-25 18:43:28 +0000374 return fGpu->wrapBackendTexture(desc);
bsalomon@google.come269f212011-11-07 13:29:52 +0000375}
376
bsalomon@google.com16e3dde2012-10-25 18:43:28 +0000377GrRenderTarget* GrContext::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800378 RETURN_NULL_IF_ABANDONED
bsalomon@google.com16e3dde2012-10-25 18:43:28 +0000379 return fGpu->wrapBackendRenderTarget(desc);
bsalomon@google.come269f212011-11-07 13:29:52 +0000380}
381
bsalomon@google.com27847de2011-02-22 20:59:41 +0000382////////////////////////////////////////////////////////////////////////////////
383
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000384void GrContext::clear(const SkIRect* rect,
bsalomon@google.com07ea2db2012-08-17 14:06:49 +0000385 const GrColor color,
robertphillips@google.com56ce48a2013-10-31 21:44:25 +0000386 bool canIgnoreRect,
bsalomon41ebbdd2014-08-04 08:31:39 -0700387 GrRenderTarget* renderTarget) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800388 RETURN_IF_ABANDONED
bsalomon41ebbdd2014-08-04 08:31:39 -0700389 ASSERT_OWNED_RESOURCE(renderTarget);
bsalomon89c62982014-11-03 12:08:42 -0800390 SkASSERT(renderTarget);
391
bsalomonf21dab92014-11-13 13:33:28 -0800392 AutoCheckFlush acf(this);
egdanield78a1682014-07-09 10:41:26 -0700393 GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::clear", this);
joshualitt570d2f82015-02-25 13:19:48 -0800394 GrDrawTarget* target = this->prepareToDraw();
bsalomon41ebbdd2014-08-04 08:31:39 -0700395 if (NULL == target) {
396 return;
397 }
398 target->clear(rect, color, canIgnoreRect, renderTarget);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000399}
400
joshualitt25d9c152015-02-18 12:29:52 -0800401void GrContext::drawPaint(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800402 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800403 const GrPaint& origPaint,
404 const SkMatrix& viewMatrix) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800405 RETURN_IF_ABANDONED
bsalomon@google.com27847de2011-02-22 20:59:41 +0000406 // set rect to be big enough to fill the space, but not super-huge, so we
407 // don't overflow fixed-point implementations
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000408 SkRect r;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000409 r.setLTRB(0, 0,
joshualitt25d9c152015-02-18 12:29:52 -0800410 SkIntToScalar(rt->width()),
411 SkIntToScalar(rt->height()));
bsalomon@google.com5dc26b92012-10-11 19:32:32 +0000412 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
joshualitt8fc6c2d2014-12-22 15:27:05 -0800413
414 // by definition this fills the entire clip, no need for AA
415 if (paint->isAntiAlias()) {
416 paint.writable()->setAntiAlias(false);
417 }
418
419 bool isPerspective = viewMatrix.hasPerspective();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000420
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000421 // We attempt to map r by the inverse matrix and draw that. mapRect will
422 // map the four corners and bound them with a new rect. This will not
423 // produce a correct result for some perspective matrices.
joshualitt8fc6c2d2014-12-22 15:27:05 -0800424 if (!isPerspective) {
joshualitt5531d512014-12-17 15:50:11 -0800425 SkMatrix inverse;
426 if (!viewMatrix.invert(&inverse)) {
tfarina38406c82014-10-31 07:11:12 -0700427 SkDebugf("Could not invert matrix\n");
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000428 return;
429 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000430 inverse.mapRect(&r);
joshualitt570d2f82015-02-25 13:19:48 -0800431 this->drawRect(rt, clip, *paint, viewMatrix, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000432 } else {
joshualitt8fc6c2d2014-12-22 15:27:05 -0800433 SkMatrix localMatrix;
434 if (!viewMatrix.invert(&localMatrix)) {
tfarina38406c82014-10-31 07:11:12 -0700435 SkDebugf("Could not invert matrix\n");
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000436 return;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000437 }
joshualitt8fc6c2d2014-12-22 15:27:05 -0800438
439 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800440 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800441 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, paint, &acf);
joshualitt8fc6c2d2014-12-22 15:27:05 -0800442 if (NULL == target) {
443 return;
444 }
445
446 GR_CREATE_TRACE_MARKER("GrContext::drawPaintWithPerspective", target);
joshualitt44701df2015-02-23 14:44:57 -0800447 target->drawRect(&pipelineBuilder,
448 paint->getColor(),
449 SkMatrix::I(),
450 r,
451 NULL,
452 &localMatrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000453 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000454}
455
commit-bot@chromium.org03e3e892013-10-02 18:19:17 +0000456#ifdef SK_DEVELOPER
457void GrContext::dumpFontCache() const {
458 fFontCache->dump();
459}
460#endif
461
bsalomon@google.com205d4602011-04-25 12:43:45 +0000462////////////////////////////////////////////////////////////////////////////////
463
bsalomonc30aaa02014-08-13 07:15:29 -0700464static inline bool is_irect(const SkRect& r) {
tfarina38406c82014-10-31 07:11:12 -0700465 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) &&
466 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
bsalomonc30aaa02014-08-13 07:15:29 -0700467}
468
bsalomon@google.com205d4602011-04-25 12:43:45 +0000469static bool apply_aa_to_rect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800470 GrPipelineBuilder* pipelineBuilder,
joshualitt9853cce2014-11-17 14:22:48 -0800471 SkRect* devBoundRect,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000472 const SkRect& rect,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000473 SkScalar strokeWidth,
joshualitt2e3b3e32014-12-09 13:31:14 -0800474 const SkMatrix& combinedMatrix,
475 GrColor color) {
egdaniel8dd688b2015-01-22 10:16:09 -0800476 if (pipelineBuilder->getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000477 return false;
478 }
479
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000480#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000481 if (strokeWidth >= 0) {
482#endif
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000483 if (!combinedMatrix.preservesAxisAlignment()) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000484 return false;
485 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000486
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000487#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000488 } else {
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000489 if (!combinedMatrix.preservesRightAngles()) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000490 return false;
491 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000492 }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000493#endif
bsalomon@google.com205d4602011-04-25 12:43:45 +0000494
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000495 combinedMatrix.mapRect(devBoundRect, rect);
derekfe638d1c2014-12-02 13:51:29 -0800496 if (!combinedMatrix.rectStaysRect()) {
497 return true;
498 }
499
bsalomonc30aaa02014-08-13 07:15:29 -0700500 if (strokeWidth < 0) {
501 return !is_irect(*devBoundRect);
502 }
robertphillips@google.com28ac96e2013-05-13 13:38:35 +0000503
bsalomon9c0822a2014-08-11 11:07:48 -0700504 return true;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000505}
506
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000507static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
508 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
509 point.fY >= rect.fTop && point.fY <= rect.fBottom;
510}
511
joshualitt0823bfa2015-02-27 10:06:15 -0800512class StrokeRectBatch : public GrBatch {
513public:
514 struct Geometry {
515 GrColor fColor;
516 SkMatrix fViewMatrix;
517 SkRect fRect;
518 SkScalar fStrokeWidth;
519 };
520
521 static GrBatch* Create(const Geometry& geometry) {
522 return SkNEW_ARGS(StrokeRectBatch, (geometry));
523 }
524
mtklein36352bf2015-03-25 18:17:31 -0700525 const char* name() const override { return "StrokeRectBatch"; }
joshualitt0823bfa2015-02-27 10:06:15 -0800526
mtklein36352bf2015-03-25 18:17:31 -0700527 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
joshualitt0823bfa2015-02-27 10:06:15 -0800528 // When this is called on a batch, there is only one geometry bundle
529 out->setKnownFourComponents(fGeoData[0].fColor);
530 }
531
mtklein36352bf2015-03-25 18:17:31 -0700532 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
joshualitt0823bfa2015-02-27 10:06:15 -0800533 out->setKnownSingleComponent(0xff);
534 }
535
mtklein36352bf2015-03-25 18:17:31 -0700536 void initBatchTracker(const GrPipelineInfo& init) override {
joshualitt0823bfa2015-02-27 10:06:15 -0800537 // Handle any color overrides
538 if (init.fColorIgnored) {
539 fGeoData[0].fColor = GrColor_ILLEGAL;
540 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
541 fGeoData[0].fColor = init.fOverrideColor;
542 }
543
544 // setup batch properties
545 fBatch.fColorIgnored = init.fColorIgnored;
546 fBatch.fColor = fGeoData[0].fColor;
547 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
548 fBatch.fCoverageIgnored = init.fCoverageIgnored;
549 }
550
mtklein36352bf2015-03-25 18:17:31 -0700551 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
joshualitt0823bfa2015-02-27 10:06:15 -0800552 SkAutoTUnref<const GrGeometryProcessor> gp(
553 GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType,
554 this->color(),
555 this->viewMatrix(),
556 SkMatrix::I()));
557
558 batchTarget->initDraw(gp, pipeline);
559
560 // TODO this is hacky, but the only way we have to initialize the GP is to use the
561 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
562 // everywhere we can remove this nastiness
563 GrPipelineInfo init;
564 init.fColorIgnored = fBatch.fColorIgnored;
565 init.fOverrideColor = GrColor_ILLEGAL;
566 init.fCoverageIgnored = fBatch.fCoverageIgnored;
567 init.fUsesLocalCoords = this->usesLocalCoords();
568 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
569
570 size_t vertexStride = gp->getVertexStride();
571
572 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr));
573
574 Geometry& args = fGeoData[0];
575
576 int vertexCount = kVertsPerHairlineRect;
577 if (args.fStrokeWidth > 0) {
578 vertexCount = kVertsPerStrokeRect;
579 }
580
581 const GrVertexBuffer* vertexBuffer;
582 int firstVertex;
583
584 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
585 vertexCount,
586 &vertexBuffer,
587 &firstVertex);
588
joshualitt4b31de82015-03-05 14:33:41 -0800589 if (!vertices) {
590 SkDebugf("Could not allocate vertices\n");
591 return;
592 }
593
joshualitt0823bfa2015-02-27 10:06:15 -0800594 SkPoint* vertex = reinterpret_cast<SkPoint*>(vertices);
595
596 GrPrimitiveType primType;
597
598 if (args.fStrokeWidth > 0) {;
599 primType = kTriangleStrip_GrPrimitiveType;
600 args.fRect.sort();
601 this->setStrokeRectStrip(vertex, args.fRect, args.fStrokeWidth);
602 } else {
603 // hairline
604 primType = kLineStrip_GrPrimitiveType;
605 vertex[0].set(args.fRect.fLeft, args.fRect.fTop);
606 vertex[1].set(args.fRect.fRight, args.fRect.fTop);
607 vertex[2].set(args.fRect.fRight, args.fRect.fBottom);
608 vertex[3].set(args.fRect.fLeft, args.fRect.fBottom);
609 vertex[4].set(args.fRect.fLeft, args.fRect.fTop);
610 }
611
612 GrDrawTarget::DrawInfo drawInfo;
613 drawInfo.setPrimitiveType(primType);
614 drawInfo.setVertexBuffer(vertexBuffer);
615 drawInfo.setStartVertex(firstVertex);
616 drawInfo.setVertexCount(vertexCount);
617 drawInfo.setStartIndex(0);
618 drawInfo.setIndexCount(0);
619 drawInfo.setInstanceCount(0);
620 drawInfo.setVerticesPerInstance(0);
621 drawInfo.setIndicesPerInstance(0);
622 batchTarget->draw(drawInfo);
623 }
624
625 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
626
627private:
628 StrokeRectBatch(const Geometry& geometry) {
629 this->initClassID<StrokeRectBatch>();
630
631 fBatch.fHairline = geometry.fStrokeWidth == 0;
632
633 fGeoData.push_back(geometry);
634 }
635
636 /* create a triangle strip that strokes the specified rect. There are 8
637 unique vertices, but we repeat the last 2 to close up. Alternatively we
638 could use an indices array, and then only send 8 verts, but not sure that
639 would be faster.
640 */
641 void setStrokeRectStrip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
642 const SkScalar rad = SkScalarHalf(width);
643 // TODO we should be able to enable this assert, but we'd have to filter these draws
644 // this is a bug
645 //SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2);
646
647 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
648 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
649 verts[2].set(rect.fRight - rad, rect.fTop + rad);
650 verts[3].set(rect.fRight + rad, rect.fTop - rad);
651 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
652 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
653 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
654 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
655 verts[8] = verts[0];
656 verts[9] = verts[1];
657 }
658
659
660 GrColor color() const { return fBatch.fColor; }
661 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
662 bool colorIgnored() const { return fBatch.fColorIgnored; }
663 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
664 bool hairline() const { return fBatch.fHairline; }
665
mtklein36352bf2015-03-25 18:17:31 -0700666 bool onCombineIfPossible(GrBatch* t) override {
joshualitt0823bfa2015-02-27 10:06:15 -0800667 // StrokeRectBatch* that = t->cast<StrokeRectBatch>();
668
669 // NonAA stroke rects cannot batch right now
670 // TODO make these batchable
671 return false;
672 }
673
674 struct BatchTracker {
675 GrColor fColor;
676 bool fUsesLocalCoords;
677 bool fColorIgnored;
678 bool fCoverageIgnored;
679 bool fHairline;
680 };
681
682 const static int kVertsPerHairlineRect = 5;
683 const static int kVertsPerStrokeRect = 10;
684
685 BatchTracker fBatch;
686 SkSTArray<1, Geometry, true> fGeoData;
687};
688
joshualitt25d9c152015-02-18 12:29:52 -0800689void GrContext::drawRect(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800690 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800691 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -0800692 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000693 const SkRect& rect,
bsalomon01c8da12014-08-04 09:21:30 -0700694 const GrStrokeInfo* strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800695 RETURN_IF_ABANDONED
bsalomon49f085d2014-09-05 13:34:00 -0700696 if (strokeInfo && strokeInfo->isDashed()) {
egdanield58a0ba2014-06-11 10:30:05 -0700697 SkPath path;
698 path.addRect(rect);
joshualitt570d2f82015-02-25 13:19:48 -0800699 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -0700700 return;
701 }
702
bsalomonf21dab92014-11-13 13:33:28 -0800703 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800704 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800705 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -0700706 if (NULL == target) {
707 return;
708 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000709
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +0000710 GR_CREATE_TRACE_MARKER("GrContext::drawRect", target);
egdanield58a0ba2014-06-11 10:30:05 -0700711 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getStrokeRec().getWidth();
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000712
713 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
714 // cases where the RT is fully inside a stroke.
715 if (width < 0) {
716 SkRect rtRect;
egdaniel8dd688b2015-01-22 10:16:09 -0800717 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000718 SkRect clipSpaceRTRect = rtRect;
joshualitt570d2f82015-02-25 13:19:48 -0800719 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
joshualitt44701df2015-02-23 14:44:57 -0800720 if (checkClip) {
joshualitt570d2f82015-02-25 13:19:48 -0800721 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
722 SkIntToScalar(clip.origin().fY));
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000723 }
724 // Does the clip contain the entire RT?
joshualitt570d2f82015-02-25 13:19:48 -0800725 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000726 SkMatrix invM;
joshualitt8059eb92014-12-29 15:10:07 -0800727 if (!viewMatrix.invert(&invM)) {
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000728 return;
729 }
730 // Does the rect bound the RT?
731 SkPoint srcSpaceRTQuad[4];
732 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
733 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
734 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
735 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
736 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
737 // Will it blend?
738 GrColor clearColor;
739 if (paint.isOpaqueAndConstantColor(&clearColor)) {
joshualitt25d9c152015-02-18 12:29:52 -0800740 target->clear(NULL, clearColor, true, rt);
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000741 return;
742 }
743 }
744 }
745 }
746
joshualitt2e3b3e32014-12-09 13:31:14 -0800747 GrColor color = paint.getColor();
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000748 SkRect devBoundRect;
egdaniel8dd688b2015-01-22 10:16:09 -0800749 bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isMultisampled();
750 bool doAA = needAA && apply_aa_to_rect(target, &pipelineBuilder, &devBoundRect, rect, width,
joshualitt8059eb92014-12-29 15:10:07 -0800751 viewMatrix, color);
egdanield58a0ba2014-06-11 10:30:05 -0700752
bsalomon@google.com205d4602011-04-25 12:43:45 +0000753 if (doAA) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000754 if (width >= 0) {
bsalomon395ef052014-11-12 11:35:22 -0800755 const SkStrokeRec& strokeRec = strokeInfo->getStrokeRec();
joshualitt9853cce2014-11-17 14:22:48 -0800756 fAARectRenderer->strokeAARect(target,
egdaniel8dd688b2015-01-22 10:16:09 -0800757 &pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800758 color,
joshualitt8059eb92014-12-29 15:10:07 -0800759 viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800760 rect,
joshualitt9853cce2014-11-17 14:22:48 -0800761 devBoundRect,
762 strokeRec);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000763 } else {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000764 // filled AA rect
joshualitt8059eb92014-12-29 15:10:07 -0800765 fAARectRenderer->fillAARect(target,
egdaniel8dd688b2015-01-22 10:16:09 -0800766 &pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -0800767 color,
768 viewMatrix,
769 rect,
joshualittd27f73e2014-12-29 07:43:36 -0800770 devBoundRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000771 }
772 return;
773 }
774
bsalomon@google.com27847de2011-02-22 20:59:41 +0000775 if (width >= 0) {
joshualitt0823bfa2015-02-27 10:06:15 -0800776 StrokeRectBatch::Geometry geometry;
777 geometry.fViewMatrix = viewMatrix;
778 geometry.fColor = color;
779 geometry.fRect = rect;
780 geometry.fStrokeWidth = width;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000781
joshualitt0823bfa2015-02-27 10:06:15 -0800782 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000783
joshualitt0823bfa2015-02-27 10:06:15 -0800784 SkRect bounds = rect;
785 SkScalar rad = SkScalarHalf(width);
786 bounds.outset(rad, rad);
787 viewMatrix.mapRect(&bounds);
788 target->drawBatch(&pipelineBuilder, batch, &bounds);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000789 } else {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000790 // filled BW rect
egdaniel8dd688b2015-01-22 10:16:09 -0800791 target->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000792 }
793}
794
joshualitt25d9c152015-02-18 12:29:52 -0800795void GrContext::drawNonAARectToRect(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800796 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800797 const GrPaint& paint,
joshualitt16b27892014-12-18 07:47:16 -0800798 const SkMatrix& viewMatrix,
799 const SkRect& rectToDraw,
800 const SkRect& localRect,
801 const SkMatrix* localMatrix) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800802 RETURN_IF_ABANDONED
bsalomonf21dab92014-11-13 13:33:28 -0800803 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800804 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800805 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -0700806 if (NULL == target) {
807 return;
808 }
bsalomon@google.com64386952013-02-08 21:22:44 +0000809
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +0000810 GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target);
811
joshualitt44701df2015-02-23 14:44:57 -0800812 target->drawRect(&pipelineBuilder,
813 paint.getColor(),
814 viewMatrix,
815 rectToDraw,
816 &localRect,
egdaniel8dd688b2015-01-22 10:16:09 -0800817 localMatrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000818}
819
joshualitt0823bfa2015-02-27 10:06:15 -0800820static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
821 bool hasColors,
joshualitt56995b52014-12-11 15:44:02 -0800822 int* colorOffset,
823 int* texOffset,
joshualitt8059eb92014-12-29 15:10:07 -0800824 GrColor color,
825 const SkMatrix& viewMatrix) {
robertphillips@google.com42903302013-04-20 12:26:07 +0000826 *texOffset = -1;
827 *colorOffset = -1;
joshualitt5478d422014-11-14 16:00:38 -0800828 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType;
joshualitt0823bfa2015-02-27 10:06:15 -0800829 if (hasLocalCoords && hasColors) {
joshualitt5478d422014-11-14 16:00:38 -0800830 *colorOffset = sizeof(SkPoint);
831 *texOffset = sizeof(SkPoint) + sizeof(GrColor);
832 flags |= GrDefaultGeoProcFactory::kColor_GPType |
833 GrDefaultGeoProcFactory::kLocalCoord_GPType;
joshualitt0823bfa2015-02-27 10:06:15 -0800834 } else if (hasLocalCoords) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000835 *texOffset = sizeof(SkPoint);
joshualitt5478d422014-11-14 16:00:38 -0800836 flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType;
joshualitt0823bfa2015-02-27 10:06:15 -0800837 } else if (hasColors) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000838 *colorOffset = sizeof(SkPoint);
joshualitt5478d422014-11-14 16:00:38 -0800839 flags |= GrDefaultGeoProcFactory::kColor_GPType;
robertphillips@google.com42903302013-04-20 12:26:07 +0000840 }
joshualitt8059eb92014-12-29 15:10:07 -0800841 return GrDefaultGeoProcFactory::Create(flags, color, viewMatrix, SkMatrix::I());
robertphillips@google.com42903302013-04-20 12:26:07 +0000842}
843
joshualitt0823bfa2015-02-27 10:06:15 -0800844class DrawVerticesBatch : public GrBatch {
845public:
846 struct Geometry {
847 GrColor fColor;
848 SkTDArray<SkPoint> fPositions;
849 SkTDArray<uint16_t> fIndices;
850 SkTDArray<GrColor> fColors;
851 SkTDArray<SkPoint> fLocalCoords;
852 };
853
854 static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveType,
855 const SkMatrix& viewMatrix,
856 const SkPoint* positions, int vertexCount,
857 const uint16_t* indices, int indexCount,
858 const GrColor* colors, const SkPoint* localCoords) {
859 return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatrix, positions,
860 vertexCount, indices, indexCount, colors,
861 localCoords));
862 }
863
mtklein36352bf2015-03-25 18:17:31 -0700864 const char* name() const override { return "DrawVerticesBatch"; }
joshualitt0823bfa2015-02-27 10:06:15 -0800865
mtklein36352bf2015-03-25 18:17:31 -0700866 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
joshualitt0823bfa2015-02-27 10:06:15 -0800867 // When this is called on a batch, there is only one geometry bundle
868 if (this->hasColors()) {
869 out->setUnknownFourComponents();
870 } else {
871 out->setKnownFourComponents(fGeoData[0].fColor);
872 }
873 }
874
mtklein36352bf2015-03-25 18:17:31 -0700875 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
joshualittd4c7d552015-02-27 13:00:56 -0800876 out->setKnownSingleComponent(0xff);
joshualitt0823bfa2015-02-27 10:06:15 -0800877 }
878
mtklein36352bf2015-03-25 18:17:31 -0700879 void initBatchTracker(const GrPipelineInfo& init) override {
joshualitt0823bfa2015-02-27 10:06:15 -0800880 // Handle any color overrides
881 if (init.fColorIgnored) {
882 fGeoData[0].fColor = GrColor_ILLEGAL;
883 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
884 fGeoData[0].fColor = init.fOverrideColor;
885 }
886
887 // setup batch properties
888 fBatch.fColorIgnored = init.fColorIgnored;
889 fBatch.fColor = fGeoData[0].fColor;
890 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
891 fBatch.fCoverageIgnored = init.fCoverageIgnored;
892 }
893
mtklein36352bf2015-03-25 18:17:31 -0700894 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
joshualitt0823bfa2015-02-27 10:06:15 -0800895 int colorOffset = -1, texOffset = -1;
896 SkAutoTUnref<const GrGeometryProcessor> gp(
897 set_vertex_attributes(this->hasLocalCoords(), this->hasColors(), &colorOffset,
898 &texOffset, this->color(), this->viewMatrix()));
899
900 batchTarget->initDraw(gp, pipeline);
901
902 // TODO this is hacky, but the only way we have to initialize the GP is to use the
903 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
904 // everywhere we can remove this nastiness
905 GrPipelineInfo init;
906 init.fColorIgnored = fBatch.fColorIgnored;
907 init.fOverrideColor = GrColor_ILLEGAL;
908 init.fCoverageIgnored = fBatch.fCoverageIgnored;
909 init.fUsesLocalCoords = this->usesLocalCoords();
910 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
911
912 size_t vertexStride = gp->getVertexStride();
913
914 SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? sizeof(SkPoint) : 0)
915 + (this->hasColors() ? sizeof(GrColor) : 0));
916
917 int instanceCount = fGeoData.count();
918
919 const GrVertexBuffer* vertexBuffer;
920 int firstVertex;
921
922 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
923 this->vertexCount(),
924 &vertexBuffer,
925 &firstVertex);
926
joshualitt4b31de82015-03-05 14:33:41 -0800927 if (!vertices) {
928 SkDebugf("Could not allocate vertices\n");
929 return;
930 }
931
joshualitt0823bfa2015-02-27 10:06:15 -0800932 const GrIndexBuffer* indexBuffer;
933 int firstIndex;
934
935 void* indices = NULL;
936 if (this->hasIndices()) {
937 indices = batchTarget->indexPool()->makeSpace(this->indexCount(),
938 &indexBuffer,
939 &firstIndex);
joshualitt4b31de82015-03-05 14:33:41 -0800940
941 if (!indices) {
942 SkDebugf("Could not allocate indices\n");
943 return;
944 }
joshualitt0823bfa2015-02-27 10:06:15 -0800945 }
946
947 int indexOffset = 0;
948 int vertexOffset = 0;
949 for (int i = 0; i < instanceCount; i++) {
950 const Geometry& args = fGeoData[i];
951
952 // TODO we can actually cache this interleaved and then just memcopy
953 if (this->hasIndices()) {
954 for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
955 *((uint16_t*)indices + indexOffset) = args.fIndices[j] + vertexOffset;
956 }
957 }
958
959 for (int j = 0; j < args.fPositions.count(); ++j) {
960 *((SkPoint*)vertices) = args.fPositions[j];
961 if (this->hasColors()) {
962 *(GrColor*)((intptr_t)vertices + colorOffset) = args.fColors[j];
963 }
964 if (this->hasLocalCoords()) {
965 *(SkPoint*)((intptr_t)vertices + texOffset) = args.fLocalCoords[j];
966 }
967 vertices = (void*)((intptr_t)vertices + vertexStride);
968 vertexOffset++;
969 }
970 }
971
972 GrDrawTarget::DrawInfo drawInfo;
973 drawInfo.setPrimitiveType(this->primitiveType());
974 drawInfo.setVertexBuffer(vertexBuffer);
975 drawInfo.setStartVertex(firstVertex);
976 drawInfo.setVertexCount(this->vertexCount());
977 if (this->hasIndices()) {
978 drawInfo.setIndexBuffer(indexBuffer);
979 drawInfo.setStartIndex(firstIndex);
980 drawInfo.setIndexCount(this->indexCount());
981 } else {
982 drawInfo.setStartIndex(0);
983 drawInfo.setIndexCount(0);
984 }
985 batchTarget->draw(drawInfo);
986 }
987
988 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
989
990private:
991 DrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
992 const SkMatrix& viewMatrix,
993 const SkPoint* positions, int vertexCount,
994 const uint16_t* indices, int indexCount,
995 const GrColor* colors, const SkPoint* localCoords) {
996 this->initClassID<DrawVerticesBatch>();
997 SkASSERT(positions);
998
999 fBatch.fViewMatrix = viewMatrix;
1000 Geometry& installedGeo = fGeoData.push_back(geometry);
1001
1002 installedGeo.fPositions.append(vertexCount, positions);
1003 if (indices) {
1004 installedGeo.fIndices.append(indexCount, indices);
1005 fBatch.fHasIndices = true;
1006 } else {
1007 fBatch.fHasIndices = false;
1008 }
1009
1010 if (colors) {
1011 installedGeo.fColors.append(vertexCount, colors);
1012 fBatch.fHasColors = true;
1013 } else {
1014 fBatch.fHasColors = false;
1015 }
1016
1017 if (localCoords) {
1018 installedGeo.fLocalCoords.append(vertexCount, localCoords);
1019 fBatch.fHasLocalCoords = true;
1020 } else {
1021 fBatch.fHasLocalCoords = false;
1022 }
1023 fBatch.fVertexCount = vertexCount;
1024 fBatch.fIndexCount = indexCount;
1025 fBatch.fPrimitiveType = primitiveType;
1026 }
1027
1028 GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; }
1029 bool batchablePrimitiveType() const {
1030 return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType ||
1031 kLines_GrPrimitiveType == fBatch.fPrimitiveType ||
1032 kPoints_GrPrimitiveType == fBatch.fPrimitiveType;
1033 }
1034 GrColor color() const { return fBatch.fColor; }
1035 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1036 bool colorIgnored() const { return fBatch.fColorIgnored; }
1037 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
1038 bool hasColors() const { return fBatch.fHasColors; }
1039 bool hasIndices() const { return fBatch.fHasIndices; }
1040 bool hasLocalCoords() const { return fBatch.fHasLocalCoords; }
1041 int vertexCount() const { return fBatch.fVertexCount; }
1042 int indexCount() const { return fBatch.fIndexCount; }
1043
mtklein36352bf2015-03-25 18:17:31 -07001044 bool onCombineIfPossible(GrBatch* t) override {
joshualitt0823bfa2015-02-27 10:06:15 -08001045 DrawVerticesBatch* that = t->cast<DrawVerticesBatch>();
1046
1047 if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
1048 return false;
1049 }
1050
1051 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1052
1053 // We currently use a uniform viewmatrix for this batch
1054 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1055 return false;
1056 }
1057
1058 if (this->hasColors() != that->hasColors()) {
1059 return false;
1060 }
1061
1062 if (this->hasIndices() != that->hasIndices()) {
1063 return false;
1064 }
1065
1066 if (this->hasLocalCoords() != that->hasLocalCoords()) {
1067 return false;
1068 }
1069
1070 if (!this->hasColors() && this->color() != that->color()) {
1071 return false;
1072 }
1073
1074 if (this->color() != that->color()) {
1075 fBatch.fColor = GrColor_ILLEGAL;
1076 }
1077 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
1078 fBatch.fVertexCount += that->vertexCount();
1079 fBatch.fIndexCount += that->indexCount();
1080 return true;
1081 }
1082
1083 struct BatchTracker {
1084 GrPrimitiveType fPrimitiveType;
1085 SkMatrix fViewMatrix;
1086 GrColor fColor;
1087 bool fUsesLocalCoords;
1088 bool fColorIgnored;
1089 bool fCoverageIgnored;
1090 bool fHasColors;
1091 bool fHasIndices;
1092 bool fHasLocalCoords;
1093 int fVertexCount;
1094 int fIndexCount;
1095 };
1096
1097 BatchTracker fBatch;
1098 SkSTArray<1, Geometry, true> fGeoData;
1099};
1100
joshualitt25d9c152015-02-18 12:29:52 -08001101void GrContext::drawVertices(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -08001102 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -08001103 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -08001104 const SkMatrix& viewMatrix,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001105 GrPrimitiveType primitiveType,
1106 int vertexCount,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +00001107 const SkPoint positions[],
1108 const SkPoint texCoords[],
bsalomon@google.com27847de2011-02-22 20:59:41 +00001109 const GrColor colors[],
1110 const uint16_t indices[],
1111 int indexCount) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001112 RETURN_IF_ABANDONED
bsalomonf21dab92014-11-13 13:33:28 -08001113 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -08001114 GrPipelineBuilder pipelineBuilder;
bsalomonf21dab92014-11-13 13:33:28 -08001115 GrDrawTarget::AutoReleaseGeometry geo; // must be inside AutoCheckFlush scope
commit-bot@chromium.org5a567932014-01-08 21:26:09 +00001116
joshualitt570d2f82015-02-25 13:19:48 -08001117 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -07001118 if (NULL == target) {
1119 return;
1120 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001121
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +00001122 GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target);
1123
joshualitt0823bfa2015-02-27 10:06:15 -08001124 DrawVerticesBatch::Geometry geometry;
1125 geometry.fColor = paint.getColor();
jvanverth@google.com9b855c72013-03-01 18:21:22 +00001126
joshualitt0823bfa2015-02-27 10:06:15 -08001127 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
1128 positions, vertexCount, indices,
1129 indexCount,colors, texCoords));
bsalomon@google.com27847de2011-02-22 20:59:41 +00001130
joshualitt0823bfa2015-02-27 10:06:15 -08001131 // TODO figure out bounds
1132 target->drawBatch(&pipelineBuilder, batch, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001133}
1134
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001135///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com93c96602012-04-27 13:05:21 +00001136
joshualitt25d9c152015-02-18 12:29:52 -08001137void GrContext::drawRRect(GrRenderTarget*rt,
joshualitt570d2f82015-02-25 13:19:48 -08001138 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -08001139 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -08001140 const SkMatrix& viewMatrix,
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001141 const SkRRect& rrect,
egdanield58a0ba2014-06-11 10:30:05 -07001142 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001143 RETURN_IF_ABANDONED
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001144 if (rrect.isEmpty()) {
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +00001145 return;
1146 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001147
egdanield58a0ba2014-06-11 10:30:05 -07001148 if (strokeInfo.isDashed()) {
1149 SkPath path;
1150 path.addRRect(rrect);
joshualitt570d2f82015-02-25 13:19:48 -08001151 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -07001152 return;
1153 }
1154
bsalomonf21dab92014-11-13 13:33:28 -08001155 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -08001156 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -08001157 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -07001158 if (NULL == target) {
1159 return;
1160 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001161
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +00001162 GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target);
1163
egdanield58a0ba2014-06-11 10:30:05 -07001164 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1165
joshualitt2e3b3e32014-12-09 13:31:14 -08001166 GrColor color = paint.getColor();
joshualitt44701df2015-02-23 14:44:57 -08001167 if (!fOvalRenderer->drawRRect(target,
1168 &pipelineBuilder,
1169 color,
1170 viewMatrix,
1171 paint.isAntiAlias(),
1172 rrect,
1173 strokeRec)) {
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001174 SkPath path;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001175 path.addRRect(rrect);
egdaniel8dd688b2015-01-22 10:16:09 -08001176 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1177 path, strokeInfo);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001178 }
1179}
1180
1181///////////////////////////////////////////////////////////////////////////////
1182
joshualitt25d9c152015-02-18 12:29:52 -08001183void GrContext::drawDRRect(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -08001184 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -08001185 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -08001186 const SkMatrix& viewMatrix,
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001187 const SkRRect& outer,
1188 const SkRRect& inner) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001189 RETURN_IF_ABANDONED
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001190 if (outer.isEmpty()) {
1191 return;
1192 }
1193
bsalomonf21dab92014-11-13 13:33:28 -08001194 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -08001195 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -08001196 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001197
1198 GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
1199
joshualitt2e3b3e32014-12-09 13:31:14 -08001200 GrColor color = paint.getColor();
joshualitt44701df2015-02-23 14:44:57 -08001201 if (!fOvalRenderer->drawDRRect(target,
1202 &pipelineBuilder,
1203 color,
1204 viewMatrix,
1205 paint.isAntiAlias(),
1206 outer,
1207 inner)) {
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001208 SkPath path;
1209 path.addRRect(inner);
1210 path.addRRect(outer);
1211 path.setFillType(SkPath::kEvenOdd_FillType);
1212
egdanield58a0ba2014-06-11 10:30:05 -07001213 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
egdaniel8dd688b2015-01-22 10:16:09 -08001214 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1215 path, fillRec);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001216 }
1217}
1218
1219///////////////////////////////////////////////////////////////////////////////
1220
joshualitt570d2f82015-02-25 13:19:48 -08001221void GrContext::drawOval(GrRenderTarget* rt,
1222 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -08001223 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -08001224 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +00001225 const SkRect& oval,
egdanield58a0ba2014-06-11 10:30:05 -07001226 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001227 RETURN_IF_ABANDONED
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +00001228 if (oval.isEmpty()) {
1229 return;
1230 }
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001231
egdanield58a0ba2014-06-11 10:30:05 -07001232 if (strokeInfo.isDashed()) {
1233 SkPath path;
1234 path.addOval(oval);
joshualitt570d2f82015-02-25 13:19:48 -08001235 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -07001236 return;
1237 }
1238
bsalomonf21dab92014-11-13 13:33:28 -08001239 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -08001240 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -08001241 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -07001242 if (NULL == target) {
1243 return;
1244 }
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001245
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +00001246 GR_CREATE_TRACE_MARKER("GrContext::drawOval", target);
1247
egdanield58a0ba2014-06-11 10:30:05 -07001248 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1249
joshualitt2e3b3e32014-12-09 13:31:14 -08001250 GrColor color = paint.getColor();
joshualitt44701df2015-02-23 14:44:57 -08001251 if (!fOvalRenderer->drawOval(target,
1252 &pipelineBuilder,
1253 color,
1254 viewMatrix,
1255 paint.isAntiAlias(),
1256 oval,
1257 strokeRec)) {
bsalomon@google.com93c96602012-04-27 13:05:21 +00001258 SkPath path;
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001259 path.addOval(oval);
egdaniel8dd688b2015-01-22 10:16:09 -08001260 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1261 path, strokeInfo);
skia.committer@gmail.com98ded842013-01-23 07:06:17 +00001262 }
bsalomon@google.com150d2842012-01-12 20:19:56 +00001263}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001264
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001265// Can 'path' be drawn as a pair of filled nested rectangles?
1266static bool is_nested_rects(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -08001267 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -08001268 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -08001269 const SkMatrix& viewMatrix,
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001270 const SkPath& path,
1271 const SkStrokeRec& stroke,
bsalomon9c0822a2014-08-11 11:07:48 -07001272 SkRect rects[2]) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001273 SkASSERT(stroke.isFillStyle());
1274
1275 if (path.isInverseFillType()) {
1276 return false;
1277 }
1278
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001279 // TODO: this restriction could be lifted if we were willing to apply
1280 // the matrix to all the points individually rather than just to the rect
joshualitt8059eb92014-12-29 15:10:07 -08001281 if (!viewMatrix.preservesAxisAlignment()) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001282 return false;
1283 }
1284
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001285 SkPath::Direction dirs[2];
caryclark95bc5f32015-04-08 08:34:15 -07001286 if (!path.isNestedFillRects(rects, dirs)) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001287 return false;
1288 }
1289
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001290 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001291 // The two rects need to be wound opposite to each other
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001292 return false;
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001293 }
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001294
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001295 // Right now, nested rects where the margin is not the same width
1296 // all around do not render correctly
1297 const SkScalar* outer = rects[0].asScalars();
1298 const SkScalar* inner = rects[1].asScalars();
1299
robertphillips183e9852014-10-21 11:25:37 -07001300 bool allEq = true;
1301
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001302 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
robertphillips183e9852014-10-21 11:25:37 -07001303 bool allGoE1 = margin >= SK_Scalar1;
1304
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001305 for (int i = 1; i < 4; ++i) {
1306 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
robertphillips183e9852014-10-21 11:25:37 -07001307 if (temp < SK_Scalar1) {
1308 allGoE1 = false;
1309 }
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001310 if (!SkScalarNearlyEqual(margin, temp)) {
robertphillips183e9852014-10-21 11:25:37 -07001311 allEq = false;
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001312 }
1313 }
1314
robertphillips183e9852014-10-21 11:25:37 -07001315 return allEq || allGoE1;
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001316}
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001317
joshualitt25d9c152015-02-18 12:29:52 -08001318void GrContext::drawPath(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -08001319 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -08001320 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -08001321 const SkMatrix& viewMatrix,
1322 const SkPath& path,
1323 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001324 RETURN_IF_ABANDONED
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001325 if (path.isEmpty()) {
sugoi@google.com12b4e272012-12-06 20:13:11 +00001326 if (path.isInverseFillType()) {
joshualitt570d2f82015-02-25 13:19:48 -08001327 this->drawPaint(rt, clip, paint, viewMatrix);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001328 }
1329 return;
1330 }
1331
joshualitt2e3b3e32014-12-09 13:31:14 -08001332 GrColor color = paint.getColor();
egdanield58a0ba2014-06-11 10:30:05 -07001333 if (strokeInfo.isDashed()) {
egdaniele61c4112014-06-12 10:24:21 -07001334 SkPoint pts[2];
1335 if (path.isLine(pts)) {
bsalomonf21dab92014-11-13 13:33:28 -08001336 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -08001337 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -08001338 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -07001339 if (NULL == target) {
1340 return;
joshualittd27f73e2014-12-29 07:43:36 -08001341 }
egdaniele61c4112014-06-12 10:24:21 -07001342
egdaniel8dd688b2015-01-22 10:16:09 -08001343 if (GrDashingEffect::DrawDashLine(fGpu, target, &pipelineBuilder, color, viewMatrix,
1344 pts, paint, strokeInfo)) {
joshualittd27f73e2014-12-29 07:43:36 -08001345 return;
egdaniele61c4112014-06-12 10:24:21 -07001346 }
1347 }
1348
1349 // Filter dashed path into new path with the dashing applied
egdanield58a0ba2014-06-11 10:30:05 -07001350 const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo();
1351 SkTLazy<SkPath> effectPath;
1352 GrStrokeInfo newStrokeInfo(strokeInfo, false);
1353 SkStrokeRec* stroke = newStrokeInfo.getStrokeRecPtr();
1354 if (SkDashPath::FilterDashPath(effectPath.init(), path, stroke, NULL, info)) {
joshualitt570d2f82015-02-25 13:19:48 -08001355 this->drawPath(rt, clip, paint, viewMatrix, *effectPath.get(), newStrokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -07001356 return;
1357 }
1358
joshualitt570d2f82015-02-25 13:19:48 -08001359 this->drawPath(rt, clip, paint, viewMatrix, path, newStrokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -07001360 return;
1361 }
1362
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001363 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001364 // Scratch textures can be recycled after they are returned to the texture
1365 // cache. This presents a potential hazard for buffered drawing. However,
1366 // the writePixels that uploads to the scratch will perform a flush so we're
1367 // OK.
bsalomonf21dab92014-11-13 13:33:28 -08001368 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -08001369 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -08001370 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -07001371 if (NULL == target) {
1372 return;
1373 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001374
egdaniel93a37bc2014-07-21 13:47:57 -07001375 GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isConvex());
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +00001376
egdanield58a0ba2014-06-11 10:30:05 -07001377 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1378
egdaniel8dd688b2015-01-22 10:16:09 -08001379 bool useCoverageAA = paint.isAntiAlias() &&
1380 !pipelineBuilder.getRenderTarget()->isMultisampled();
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001381
egdanield58a0ba2014-06-11 10:30:05 -07001382 if (useCoverageAA && strokeRec.getWidth() < 0 && !path.isConvex()) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001383 // Concave AA paths are expensive - try to avoid them for special cases
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001384 SkRect rects[2];
1385
egdaniel8dd688b2015-01-22 10:16:09 -08001386 if (is_nested_rects(target, &pipelineBuilder, color, viewMatrix, path, strokeRec, rects)) {
joshualitt44701df2015-02-23 14:44:57 -08001387 fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, color, viewMatrix, rects);
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001388 return;
1389 }
1390 }
1391
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001392 SkRect ovalRect;
1393 bool isOval = path.isOval(&ovalRect);
1394
joshualitt8059eb92014-12-29 15:10:07 -08001395 if (!isOval || path.isInverseFillType() ||
joshualitt44701df2015-02-23 14:44:57 -08001396 !fOvalRenderer->drawOval(target,
1397 &pipelineBuilder,
1398 color,
1399 viewMatrix,
1400 paint.isAntiAlias(),
1401 ovalRect,
1402 strokeRec)) {
egdaniel8dd688b2015-01-22 10:16:09 -08001403 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1404 path, strokeInfo);
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001405 }
1406}
1407
joshualitt9853cce2014-11-17 14:22:48 -08001408void GrContext::internalDrawPath(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -08001409 GrPipelineBuilder* pipelineBuilder,
joshualitt5531d512014-12-17 15:50:11 -08001410 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -08001411 GrColor color,
joshualitt9853cce2014-11-17 14:22:48 -08001412 bool useAA,
1413 const SkPath& path,
egdanield58a0ba2014-06-11 10:30:05 -07001414 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001415 RETURN_IF_ABANDONED
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +00001416 SkASSERT(!path.isEmpty());
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001417
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +00001418 GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target);
1419
1420
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001421 // An Assumption here is that path renderer would use some form of tweaking
1422 // the src color (either the input alpha or in the frag shader) to implement
1423 // aa. If we have some future driver-mojo path AA that can do the right
1424 // thing WRT to the blend then we'll need some query on the PR.
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001425 bool useCoverageAA = useAA &&
egdaniel0bdeec92015-02-23 12:12:54 -08001426 !pipelineBuilder->getRenderTarget()->isMultisampled();
bsalomon@google.com289533a2011-10-27 12:34:25 +00001427
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001428
1429 GrPathRendererChain::DrawType type =
1430 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
joshualitt9853cce2014-11-17 14:22:48 -08001431 GrPathRendererChain::kColor_DrawType;
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001432
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001433 const SkPath* pathPtr = &path;
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +00001434 SkTLazy<SkPath> tmpPath;
egdanield58a0ba2014-06-11 10:30:05 -07001435 SkTCopyOnFirstWrite<SkStrokeRec> stroke(strokeInfo.getStrokeRec());
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001436
1437 // Try a 1st time without stroking the path and without allowing the SW renderer
egdaniel8dd688b2015-01-22 10:16:09 -08001438 GrPathRenderer* pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
1439 *stroke, false, type);
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001440
robertphillips@google.come79f3202014-02-11 16:30:21 +00001441 if (NULL == pr) {
joshualitt5531d512014-12-17 15:50:11 -08001442 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, NULL)) {
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001443 // It didn't work the 1st time, so try again with the stroked path
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +00001444 if (stroke->applyToPath(tmpPath.init(), *pathPtr)) {
1445 pathPtr = tmpPath.get();
1446 stroke.writable()->setFillStyle();
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001447 if (pathPtr->isEmpty()) {
1448 return;
1449 }
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001450 }
1451 }
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +00001452
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001453 // This time, allow SW renderer
egdaniel8dd688b2015-01-22 10:16:09 -08001454 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *stroke, true,
1455 type);
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001456 }
1457
robertphillips@google.come79f3202014-02-11 16:30:21 +00001458 if (NULL == pr) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +00001459#ifdef SK_DEBUG
tfarina38406c82014-10-31 07:11:12 -07001460 SkDebugf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001461#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001462 return;
1463 }
1464
egdaniel8dd688b2015-01-22 10:16:09 -08001465 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *stroke, useCoverageAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001466}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001467
bsalomon@google.com27847de2011-02-22 20:59:41 +00001468////////////////////////////////////////////////////////////////////////////////
1469
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001470void GrContext::flush(int flagsBitfield) {
robertphillips@google.come7db8d62013-07-04 11:48:52 +00001471 if (NULL == fDrawBuffer) {
1472 return;
1473 }
1474
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001475 if (kDiscard_FlushBit & flagsBitfield) {
1476 fDrawBuffer->reset();
1477 } else {
bsalomon@google.com6e4e6502013-02-25 20:12:45 +00001478 fDrawBuffer->flush();
junov@google.com53a55842011-06-08 22:55:10 +00001479 }
bsalomon3f324322015-04-08 11:01:54 -07001480 fResourceCache->notifyFlushOccurred();
bsalomonf21dab92014-11-13 13:33:28 -08001481 fFlushToReduceCacheSize = false;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001482}
1483
bsalomon81beccc2014-10-13 12:32:55 -07001484bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
1485 const void* inPixels, size_t outRowBytes, void* outPixels) {
1486 SkSrcPixelInfo srcPI;
jvanverthfa1e8a72014-12-22 08:31:49 -08001487 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL)) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001488 return false;
1489 }
bsalomon81beccc2014-10-13 12:32:55 -07001490 srcPI.fAlphaType = kUnpremul_SkAlphaType;
1491 srcPI.fPixels = inPixels;
1492 srcPI.fRowBytes = inRowBytes;
1493
1494 SkDstPixelInfo dstPI;
1495 dstPI.fColorType = srcPI.fColorType;
1496 dstPI.fAlphaType = kPremul_SkAlphaType;
1497 dstPI.fPixels = outPixels;
1498 dstPI.fRowBytes = outRowBytes;
1499
1500 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001501}
1502
bsalomon81beccc2014-10-13 12:32:55 -07001503bool GrContext::writeSurfacePixels(GrSurface* surface,
1504 int left, int top, int width, int height,
1505 GrPixelConfig srcConfig, const void* buffer, size_t rowBytes,
1506 uint32_t pixelOpsFlags) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001507 RETURN_FALSE_IF_ABANDONED
bsalomon81beccc2014-10-13 12:32:55 -07001508 {
1509 GrTexture* texture = NULL;
1510 if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asTexture()) &&
1511 fGpu->canWriteTexturePixels(texture, srcConfig)) {
1512
1513 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) &&
1514 surface->surfacePriv().hasPendingIO()) {
1515 this->flush();
1516 }
1517 return fGpu->writeTexturePixels(texture, left, top, width, height,
1518 srcConfig, buffer, rowBytes);
1519 // Don't need to check kFlushWrites_PixelOp here, we just did a direct write so the
1520 // upload is already flushed.
1521 }
1522 }
1523
1524 // If we didn't do a direct texture write then we upload the pixels to a texture and draw.
1525 GrRenderTarget* renderTarget = surface->asRenderTarget();
1526 if (NULL == renderTarget) {
1527 return false;
1528 }
1529
1530 // We ignore the preferred config unless it is a R/B swap of the src config. In that case
1531 // we will upload the original src data to a scratch texture but we will spoof it as the swapped
1532 // config. This scratch will then have R and B swapped. We correct for this by swapping again
1533 // when drawing the scratch to the dst using a conversion effect.
1534 bool swapRAndB = false;
1535 GrPixelConfig writeConfig = srcConfig;
1536 if (GrPixelConfigSwapRAndB(srcConfig) ==
1537 fGpu->preferredWritePixelsConfig(srcConfig, renderTarget->config())) {
1538 writeConfig = GrPixelConfigSwapRAndB(srcConfig);
1539 swapRAndB = true;
1540 }
1541
bsalomonf2703d82014-10-28 14:33:06 -07001542 GrSurfaceDesc desc;
bsalomon81beccc2014-10-13 12:32:55 -07001543 desc.fWidth = width;
1544 desc.fHeight = height;
1545 desc.fConfig = writeConfig;
bsalomone3059732014-10-14 11:47:22 -07001546 SkAutoTUnref<GrTexture> texture(this->refScratchTexture(desc, kApprox_ScratchTexMatch));
1547 if (!texture) {
bsalomon81beccc2014-10-13 12:32:55 -07001548 return false;
1549 }
1550
1551 SkAutoTUnref<const GrFragmentProcessor> fp;
1552 SkMatrix textureMatrix;
1553 textureMatrix.setIDiv(texture->width(), texture->height());
1554
1555 // allocate a tmp buffer and sw convert the pixels to premul
1556 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
1557
1558 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) {
1559 if (!GrPixelConfigIs8888(srcConfig)) {
1560 return false;
1561 }
1562 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix));
1563 // handle the unpremul step on the CPU if we couldn't create an effect to do it.
1564 if (NULL == fp) {
1565 size_t tmpRowBytes = 4 * width;
1566 tmpPixels.reset(width * height);
1567 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
1568 tmpPixels.get())) {
1569 return false;
1570 }
1571 rowBytes = tmpRowBytes;
1572 buffer = tmpPixels.get();
1573 }
1574 }
1575 if (NULL == fp) {
1576 fp.reset(GrConfigConversionEffect::Create(texture,
1577 swapRAndB,
1578 GrConfigConversionEffect::kNone_PMConversion,
1579 textureMatrix));
1580 }
1581
1582 // Even if the client told us not to flush, we still flush here. The client may have known that
1583 // writes to the original surface caused no data hazards, but they can't know that the scratch
1584 // we just got is safe.
1585 if (texture->surfacePriv().hasPendingIO()) {
1586 this->flush();
1587 }
1588 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height,
1589 writeConfig, buffer, rowBytes)) {
1590 return false;
1591 }
1592
1593 SkMatrix matrix;
1594 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
1595
1596 // This function can be called in the midst of drawing another object (e.g., when uploading a
1597 // SW-rasterized clip while issuing a draw). So we push the current geometry state before
1598 // drawing a rect to the render target.
1599 // The bracket ensures we pop the stack if we wind up flushing below.
1600 {
joshualitt570d2f82015-02-25 13:19:48 -08001601 GrDrawTarget* drawTarget = this->prepareToDraw();
1602 if (!drawTarget) {
1603 return false;
1604 }
joshualitt9853cce2014-11-17 14:22:48 -08001605 GrDrawTarget::AutoGeometryPush agp(drawTarget);
1606
egdaniel8dd688b2015-01-22 10:16:09 -08001607 GrPipelineBuilder pipelineBuilder;
1608 pipelineBuilder.addColorProcessor(fp);
1609 pipelineBuilder.setRenderTarget(renderTarget);
joshualitt44701df2015-02-23 14:44:57 -08001610 drawTarget->drawSimpleRect(&pipelineBuilder,
1611 GrColor_WHITE,
1612 matrix,
joshualitt8059eb92014-12-29 15:10:07 -08001613 SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)));
bsalomon81beccc2014-10-13 12:32:55 -07001614 }
1615
1616 if (kFlushWrites_PixelOp & pixelOpsFlags) {
1617 this->flushSurfaceWrites(surface);
1618 }
1619
1620 return true;
1621}
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001622
reed@google.com7111d462014-03-25 16:20:24 +00001623// toggles between RGBA and BGRA
1624static SkColorType toggle_colortype32(SkColorType ct) {
1625 if (kRGBA_8888_SkColorType == ct) {
1626 return kBGRA_8888_SkColorType;
1627 } else {
1628 SkASSERT(kBGRA_8888_SkColorType == ct);
1629 return kRGBA_8888_SkColorType;
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001630 }
1631}
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001632
bsalomon@google.com0342a852012-08-20 19:22:38 +00001633bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1634 int left, int top, int width, int height,
bsalomon@google.com9c680582013-02-06 18:17:50 +00001635 GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
bsalomon@google.com0342a852012-08-20 19:22:38 +00001636 uint32_t flags) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001637 RETURN_FALSE_IF_ABANDONED
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001638 ASSERT_OWNED_RESOURCE(target);
bsalomon89c62982014-11-03 12:08:42 -08001639 SkASSERT(target);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001640
bsalomonafbf2d62014-09-30 12:18:44 -07001641 if (!(kDontFlush_PixelOpsFlag & flags) && target->surfacePriv().hasPendingWrite()) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001642 this->flush();
1643 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001644
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001645 // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
bsalomon@google.com0342a852012-08-20 19:22:38 +00001646
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001647 // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down. We'll
1648 // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read.
1649 bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top,
bsalomon@google.com9c680582013-02-06 18:17:50 +00001650 width, height, dstConfig,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001651 rowBytes);
bsalomon@google.com9c680582013-02-06 18:17:50 +00001652 // We ignore the preferred config if it is different than our config unless it is an R/B swap.
1653 // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
1654 // config. Then we will call readPixels on the scratch with the swapped config. The swaps during
1655 // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
1656 // dstConfig.
1657 GrPixelConfig readConfig = dstConfig;
1658 bool swapRAndB = false;
commit-bot@chromium.org5d1d79a2013-05-24 18:52:52 +00001659 if (GrPixelConfigSwapRAndB(dstConfig) ==
1660 fGpu->preferredReadPixelsConfig(dstConfig, target->config())) {
bsalomon@google.com9c680582013-02-06 18:17:50 +00001661 readConfig = GrPixelConfigSwapRAndB(readConfig);
1662 swapRAndB = true;
1663 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001664
bsalomon@google.com0342a852012-08-20 19:22:38 +00001665 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001666
bsalomon@google.com9c680582013-02-06 18:17:50 +00001667 if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001668 // The unpremul flag is only allowed for these two configs.
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001669 return false;
1670 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001671
bsalomon191bcc02014-11-14 11:31:13 -08001672 SkAutoTUnref<GrTexture> tempTexture;
1673
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001674 // If the src is a texture and we would have to do conversions after read pixels, we instead
1675 // do the conversions by drawing the src to a scratch texture. If we handle any of the
1676 // conversions in the draw we set the corresponding bool to false so that we don't reapply it
1677 // on the read back pixels.
1678 GrTexture* src = target->asTexture();
bsalomon49f085d2014-09-05 13:34:00 -07001679 if (src && (swapRAndB || unpremul || flipY)) {
bsalomon81beccc2014-10-13 12:32:55 -07001680 // Make the scratch a render so we can read its pixels.
bsalomonf2703d82014-10-28 14:33:06 -07001681 GrSurfaceDesc desc;
1682 desc.fFlags = kRenderTarget_GrSurfaceFlag;
robertphillips@google.com75b3c962012-06-07 12:08:45 +00001683 desc.fWidth = width;
1684 desc.fHeight = height;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001685 desc.fConfig = readConfig;
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001686 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001687
bsalomon@google.com9c680582013-02-06 18:17:50 +00001688 // When a full read back is faster than a partial we could always make the scratch exactly
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001689 // match the passed rect. However, if we see many different size rectangles we will trash
1690 // our texture cache and pay the cost of creating and destroying many textures. So, we only
1691 // request an exact match when the caller is reading an entire RT.
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001692 ScratchTexMatch match = kApprox_ScratchTexMatch;
1693 if (0 == left &&
1694 0 == top &&
1695 target->width() == width &&
1696 target->height() == height &&
1697 fGpu->fullReadPixelsIsFasterThanPartial()) {
1698 match = kExact_ScratchTexMatch;
1699 }
bsalomon191bcc02014-11-14 11:31:13 -08001700 tempTexture.reset(this->refScratchTexture(desc, match));
1701 if (tempTexture) {
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001702 // compute a matrix to perform the draw
bsalomon@google.comb9086a02012-11-01 18:02:54 +00001703 SkMatrix textureMatrix;
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001704 textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001705 textureMatrix.postIDiv(src->width(), src->height());
1706
joshualittb0a8a372014-09-23 09:50:21 -07001707 SkAutoTUnref<const GrFragmentProcessor> fp;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001708 if (unpremul) {
joshualittb0a8a372014-09-23 09:50:21 -07001709 fp.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix));
1710 if (fp) {
bsalomon@google.com9c680582013-02-06 18:17:50 +00001711 unpremul = false; // we no longer need to do this on CPU after the read back.
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001712 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001713 }
1714 // If we failed to create a PM->UPM effect and have no other conversions to perform then
1715 // there is no longer any point to using the scratch.
joshualittb0a8a372014-09-23 09:50:21 -07001716 if (fp || flipY || swapRAndB) {
1717 if (!fp) {
1718 fp.reset(GrConfigConversionEffect::Create(
1719 src, swapRAndB, GrConfigConversionEffect::kNone_PMConversion,
1720 textureMatrix));
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001721 }
1722 swapRAndB = false; // we will handle the swap in the draw.
bsalomon@google.comc4364992011-11-07 15:54:49 +00001723
robertphillips@google.com13f181f2013-03-02 12:02:08 +00001724 // We protect the existing geometry here since it may not be
1725 // clear to the caller that a draw operation (i.e., drawSimpleRect)
1726 // can be invoked in this method
joshualitt5c55fef2014-10-31 14:04:35 -07001727 {
joshualitt9853cce2014-11-17 14:22:48 -08001728 GrDrawTarget::AutoGeometryPush agp(fDrawBuffer);
egdaniel8dd688b2015-01-22 10:16:09 -08001729 GrPipelineBuilder pipelineBuilder;
joshualitt5c55fef2014-10-31 14:04:35 -07001730 SkASSERT(fp);
egdaniel8dd688b2015-01-22 10:16:09 -08001731 pipelineBuilder.addColorProcessor(fp);
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001732
egdaniel8dd688b2015-01-22 10:16:09 -08001733 pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget());
joshualitt5c55fef2014-10-31 14:04:35 -07001734 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
joshualitt44701df2015-02-23 14:44:57 -08001735 fDrawBuffer->drawSimpleRect(&pipelineBuilder,
1736 GrColor_WHITE,
1737 SkMatrix::I(),
egdaniel8dd688b2015-01-22 10:16:09 -08001738 rect);
joshualitt5c55fef2014-10-31 14:04:35 -07001739 // we want to read back from the scratch's origin
1740 left = 0;
1741 top = 0;
bsalomon191bcc02014-11-14 11:31:13 -08001742 target = tempTexture->asRenderTarget();
joshualitt5c55fef2014-10-31 14:04:35 -07001743 }
1744 this->flushSurfaceWrites(target);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001745 }
bsalomon@google.com0342a852012-08-20 19:22:38 +00001746 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001747 }
joshualitt5c55fef2014-10-31 14:04:35 -07001748
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001749 if (!fGpu->readPixels(target,
1750 left, top, width, height,
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001751 readConfig, buffer, rowBytes)) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001752 return false;
1753 }
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001754 // Perform any conversions we weren't able to perform using a scratch texture.
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001755 if (unpremul || swapRAndB) {
reed@google.com7111d462014-03-25 16:20:24 +00001756 SkDstPixelInfo dstPI;
jvanverthfa1e8a72014-12-22 08:31:49 -08001757 if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, NULL)) {
reed@google.com7111d462014-03-25 16:20:24 +00001758 return false;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001759 }
reed@google.com7111d462014-03-25 16:20:24 +00001760 dstPI.fAlphaType = kUnpremul_SkAlphaType;
1761 dstPI.fPixels = buffer;
1762 dstPI.fRowBytes = rowBytes;
1763
1764 SkSrcPixelInfo srcPI;
1765 srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : dstPI.fColorType;
1766 srcPI.fAlphaType = kPremul_SkAlphaType;
1767 srcPI.fPixels = buffer;
1768 srcPI.fRowBytes = rowBytes;
1769
1770 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001771 }
1772 return true;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001773}
1774
bsalomon87a94eb2014-11-03 14:28:32 -08001775void GrContext::prepareSurfaceForExternalRead(GrSurface* surface) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001776 RETURN_IF_ABANDONED
bsalomon87a94eb2014-11-03 14:28:32 -08001777 SkASSERT(surface);
1778 ASSERT_OWNED_RESOURCE(surface);
1779 if (surface->surfacePriv().hasPendingIO()) {
1780 this->flush();
1781 }
1782 GrRenderTarget* rt = surface->asRenderTarget();
1783 if (fGpu && rt) {
1784 fGpu->resolveRenderTarget(rt);
bsalomon41ebbdd2014-08-04 08:31:39 -07001785 }
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001786}
1787
bsalomon41ebbdd2014-08-04 08:31:39 -07001788void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001789 RETURN_IF_ABANDONED
bsalomon41ebbdd2014-08-04 08:31:39 -07001790 SkASSERT(renderTarget);
1791 ASSERT_OWNED_RESOURCE(renderTarget);
bsalomonf21dab92014-11-13 13:33:28 -08001792 AutoCheckFlush acf(this);
joshualitt570d2f82015-02-25 13:19:48 -08001793 GrDrawTarget* target = this->prepareToDraw();
bsalomon41ebbdd2014-08-04 08:31:39 -07001794 if (NULL == target) {
1795 return;
1796 }
1797 target->discard(renderTarget);
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001798}
1799
bsalomonf80bfed2014-10-07 05:56:02 -07001800void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
1801 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001802 RETURN_IF_ABANDONED
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001803 if (NULL == src || NULL == dst) {
1804 return;
1805 }
bsalomone3d4bf22014-09-23 09:15:03 -07001806 ASSERT_OWNED_RESOURCE(src);
junov2bb52102014-09-29 10:18:59 -07001807 ASSERT_OWNED_RESOURCE(dst);
Brian Salomon34a98952014-09-24 11:41:24 -04001808
bsalomonf80bfed2014-10-07 05:56:02 -07001809 // Since we're going to the draw target and not GPU, no need to check kNoFlush
1810 // here.
junov96c118e2014-09-26 13:09:47 -07001811
joshualitt570d2f82015-02-25 13:19:48 -08001812 GrDrawTarget* target = this->prepareToDraw();
junov96c118e2014-09-26 13:09:47 -07001813 if (NULL == target) {
1814 return;
1815 }
junov96c118e2014-09-26 13:09:47 -07001816 target->copySurface(dst, src, srcRect, dstPoint);
bsalomonf80bfed2014-10-07 05:56:02 -07001817
1818 if (kFlushWrites_PixelOp & pixelOpsFlags) {
1819 this->flush();
1820 }
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001821}
1822
bsalomonf80bfed2014-10-07 05:56:02 -07001823void GrContext::flushSurfaceWrites(GrSurface* surface) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001824 RETURN_IF_ABANDONED
bsalomonf80bfed2014-10-07 05:56:02 -07001825 if (surface->surfacePriv().hasPendingWrite()) {
1826 this->flush();
1827 }
1828}
1829
egdaniel8dd688b2015-01-22 10:16:09 -08001830GrDrawTarget* GrContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder,
joshualitt25d9c152015-02-18 12:29:52 -08001831 GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -08001832 const GrClip& clip,
joshualitt9853cce2014-11-17 14:22:48 -08001833 const GrPaint* paint,
1834 const AutoCheckFlush* acf) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001835 if (NULL == fGpu || NULL == fDrawBuffer) {
bsalomon41ebbdd2014-08-04 08:31:39 -07001836 return NULL;
1837 }
1838
joshualitt570d2f82015-02-25 13:19:48 -08001839 ASSERT_OWNED_RESOURCE(rt);
1840 SkASSERT(rt && paint && acf);
1841 pipelineBuilder->setFromPaint(*paint, rt, clip);
1842 return fDrawBuffer;
1843}
1844
1845GrDrawTarget* GrContext::prepareToDraw() {
1846 if (NULL == fGpu) {
1847 return NULL;
bsalomon@google.com07ea2db2012-08-17 14:06:49 +00001848 }
joshualitt5c55fef2014-10-31 14:04:35 -07001849 return fDrawBuffer;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001850}
1851
robertphillips@google.com72176b22012-05-23 13:19:12 +00001852/*
1853 * This method finds a path renderer that can draw the specified path on
1854 * the provided target.
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001855 * Due to its expense, the software path renderer has split out so it can
robertphillips@google.com72176b22012-05-23 13:19:12 +00001856 * can be individually allowed/disallowed via the "allowSW" boolean.
1857 */
joshualitt9853cce2014-11-17 14:22:48 -08001858GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -08001859 const GrPipelineBuilder* pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -08001860 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -08001861 const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +00001862 const SkStrokeRec& stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001863 bool allowSW,
1864 GrPathRendererChain::DrawType drawType,
1865 GrPathRendererChain::StencilSupport* stencilSupport) {
1866
bsalomon@google.com30085192011-08-19 15:42:31 +00001867 if (NULL == fPathRendererChain) {
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001868 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
bsalomon@google.com30085192011-08-19 15:42:31 +00001869 }
robertphillips@google.com72176b22012-05-23 13:19:12 +00001870
joshualitt9853cce2014-11-17 14:22:48 -08001871 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target,
egdaniel8dd688b2015-01-22 10:16:09 -08001872 pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -08001873 viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -08001874 path,
sugoi@google.com12b4e272012-12-06 20:13:11 +00001875 stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001876 drawType,
1877 stencilSupport);
robertphillips@google.com72176b22012-05-23 13:19:12 +00001878
1879 if (NULL == pr && allowSW) {
1880 if (NULL == fSoftwarePathRenderer) {
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001881 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
robertphillips@google.com72176b22012-05-23 13:19:12 +00001882 }
robertphillips@google.com72176b22012-05-23 13:19:12 +00001883 pr = fSoftwarePathRenderer;
1884 }
1885
1886 return pr;
bsalomon@google.com30085192011-08-19 15:42:31 +00001887}
1888
bsalomon@google.com27847de2011-02-22 20:59:41 +00001889////////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org6b7938f2013-10-15 14:18:16 +00001890bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const {
1891 return fGpu->caps()->isConfigRenderable(config, withMSAA);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001892}
1893
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +00001894int GrContext::getRecommendedSampleCount(GrPixelConfig config,
1895 SkScalar dpi) const {
1896 if (!this->isConfigRenderable(config, true)) {
1897 return 0;
1898 }
1899 int chosenSampleCount = 0;
1900 if (fGpu->caps()->pathRenderingSupport()) {
1901 if (dpi >= 250.0f) {
1902 chosenSampleCount = 4;
1903 } else {
1904 chosenSampleCount = 16;
1905 }
1906 }
1907 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ?
1908 chosenSampleCount : 0;
1909}
1910
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001911void GrContext::setupDrawBuffer() {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +00001912 SkASSERT(NULL == fDrawBuffer);
1913 SkASSERT(NULL == fDrawBufferVBAllocPool);
1914 SkASSERT(NULL == fDrawBufferIBAllocPool);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001915
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001916 fDrawBufferVBAllocPool =
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001917 SkNEW_ARGS(GrVertexBufferAllocPool, (fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001918 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001919 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS));
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001920 fDrawBufferIBAllocPool =
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001921 SkNEW_ARGS(GrIndexBufferAllocPool, (fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001922 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001923 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS));
bsalomon@google.com27847de2011-02-22 20:59:41 +00001924
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001925 fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (fGpu,
bsalomon@google.com6e4e6502013-02-25 20:12:45 +00001926 fDrawBufferVBAllocPool,
1927 fDrawBufferIBAllocPool));
bsalomon@google.com27847de2011-02-22 20:59:41 +00001928}
1929
bsalomon@google.com21c10c52013-06-13 17:44:07 +00001930GrDrawTarget* GrContext::getTextTarget() {
joshualitt570d2f82015-02-25 13:19:48 -08001931 return this->prepareToDraw();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001932}
1933
1934const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1935 return fGpu->getQuadIndexBuffer();
1936}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001937
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001938namespace {
1939void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
1940 GrConfigConversionEffect::PMConversion pmToUPM;
1941 GrConfigConversionEffect::PMConversion upmToPM;
1942 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
1943 *pmToUPMValue = pmToUPM;
1944 *upmToPMValue = upmToPM;
1945}
1946}
1947
joshualittb0a8a372014-09-23 09:50:21 -07001948const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
1949 bool swapRAndB,
1950 const SkMatrix& matrix) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001951 if (!fDidTestPMConversions) {
1952 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
bsalomon@google.comd0f3f682012-08-28 13:08:14 +00001953 fDidTestPMConversions = true;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001954 }
1955 GrConfigConversionEffect::PMConversion pmToUPM =
1956 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
1957 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001958 return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001959 } else {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001960 return NULL;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001961 }
1962}
1963
joshualittb0a8a372014-09-23 09:50:21 -07001964const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
1965 bool swapRAndB,
1966 const SkMatrix& matrix) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001967 if (!fDidTestPMConversions) {
1968 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
bsalomon@google.comd0f3f682012-08-28 13:08:14 +00001969 fDidTestPMConversions = true;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001970 }
1971 GrConfigConversionEffect::PMConversion upmToPM =
1972 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
1973 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001974 return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001975 } else {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001976 return NULL;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001977 }
1978}
1979
bsalomon37f9a262015-02-02 13:00:10 -08001980//////////////////////////////////////////////////////////////////////////////
1981
1982void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
1983 if (maxTextures) {
bsalomon0ea80f42015-02-11 10:49:59 -08001984 *maxTextures = fResourceCache->getMaxResourceCount();
bsalomon37f9a262015-02-02 13:00:10 -08001985 }
1986 if (maxTextureBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -08001987 *maxTextureBytes = fResourceCache->getMaxResourceBytes();
bsalomon37f9a262015-02-02 13:00:10 -08001988 }
1989}
1990
1991void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -08001992 fResourceCache->setLimits(maxTextures, maxTextureBytes);
bsalomon37f9a262015-02-02 13:00:10 -08001993}
1994
bsalomonf99e9612015-02-19 08:24:16 -08001995void GrContext::addResourceToCache(const GrUniqueKey& key, GrGpuResource* resource) {
bsalomon37f9a262015-02-02 13:00:10 -08001996 ASSERT_OWNED_RESOURCE(resource);
bsalomonf99e9612015-02-19 08:24:16 -08001997 if (!resource) {
1998 return;
bsalomon37f9a262015-02-02 13:00:10 -08001999 }
bsalomonf99e9612015-02-19 08:24:16 -08002000 resource->resourcePriv().setUniqueKey(key);
bsalomon37f9a262015-02-02 13:00:10 -08002001}
2002
bsalomon8718aaf2015-02-19 07:24:21 -08002003bool GrContext::isResourceInCache(const GrUniqueKey& key) const {
2004 return fResourceCache->hasUniqueKey(key);
commit-bot@chromium.org95a2b0e2014-05-05 19:21:16 +00002005}
2006
bsalomon8718aaf2015-02-19 07:24:21 -08002007GrGpuResource* GrContext::findAndRefCachedResource(const GrUniqueKey& key) {
2008 return fResourceCache->findAndRefUniqueResource(key);
commit-bot@chromium.org95a2b0e2014-05-05 19:21:16 +00002009}
2010
bsalomon37f9a262015-02-02 13:00:10 -08002011//////////////////////////////////////////////////////////////////////////////
2012
egdanielbbcb38d2014-06-19 10:19:29 -07002013void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
2014 fGpu->addGpuTraceMarker(marker);
bsalomon49f085d2014-09-05 13:34:00 -07002015 if (fDrawBuffer) {
egdanielbbcb38d2014-06-19 10:19:29 -07002016 fDrawBuffer->addGpuTraceMarker(marker);
2017 }
2018}
2019
2020void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
2021 fGpu->removeGpuTraceMarker(marker);
bsalomon49f085d2014-09-05 13:34:00 -07002022 if (fDrawBuffer) {
egdanielbbcb38d2014-06-19 10:19:29 -07002023 fDrawBuffer->removeGpuTraceMarker(marker);
2024 }
2025}
2026