blob: 85ea9cab28780978486f62233ed460a5a799b2ab [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"
tomhudson@google.com278cbb42011-06-30 19:37:01 +000012#include "GrBufferAllocPool.h"
joshualitt5478d422014-11-14 16:00:38 -080013#include "GrDefaultGeoProcFactory.h"
jvanverth787cdf92014-12-04 10:46:50 -080014#include "GrFontCache.h"
bsalomon453cf402014-11-11 14:15:57 -080015#include "GrGpuResource.h"
bsalomon3582d3e2015-02-13 14:20:05 -080016#include "GrGpuResourcePriv.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070017#include "GrDistanceFieldTextContext.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000018#include "GrDrawTargetCaps.h"
joshualitt5478d422014-11-14 16:00:38 -080019#include "GrGpu.h"
commit-bot@chromium.orgdcb8ef92014-03-27 11:26:10 +000020#include "GrIndexBuffer.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000021#include "GrInOrderDrawBuffer.h"
robertphillips@google.come930a072014-04-03 00:34:27 +000022#include "GrLayerCache.h"
commit-bot@chromium.org81312832013-03-22 18:34:09 +000023#include "GrOvalRenderer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000024#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000025#include "GrPathUtils.h"
bsalomon6bc1b5f2015-02-23 09:06:38 -080026#include "GrRenderTargetPriv.h"
bsalomon0ea80f42015-02-11 10:49:59 -080027#include "GrResourceCache.h"
robertphillips@google.com72176b22012-05-23 13:19:12 +000028#include "GrSoftwarePathRenderer.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070029#include "GrStencilAndCoverTextContext.h"
egdanield58a0ba2014-06-11 10:30:05 -070030#include "GrStrokeInfo.h"
bsalomonafbf2d62014-09-30 12:18:44 -070031#include "GrSurfacePriv.h"
bsalomonafbf2d62014-09-30 12:18:44 -070032#include "GrTexturePriv.h"
egdanielbbcb38d2014-06-19 10:19:29 -070033#include "GrTraceMarker.h"
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +000034#include "GrTracing.h"
egdanield58a0ba2014-06-11 10:30:05 -070035#include "SkDashPathPriv.h"
bsalomon81beccc2014-10-13 12:32:55 -070036#include "SkConfig8888.h"
reed@google.com7111d462014-03-25 16:20:24 +000037#include "SkGr.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000038#include "SkRRect.h"
sugoi@google.com5f74cf82012-12-17 21:16:45 +000039#include "SkStrokeRec.h"
commit-bot@chromium.orgdcb8ef92014-03-27 11:26:10 +000040#include "SkTLazy.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000041#include "SkTLS.h"
commit-bot@chromium.org933e65d2014-03-20 20:00:24 +000042#include "SkTraceEvent.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000043
joshualitt5478d422014-11-14 16:00:38 -080044#include "effects/GrConfigConversionEffect.h"
45#include "effects/GrDashingEffect.h"
46#include "effects/GrSingleTextureEffect.h"
47
bsalomon@google.com60361492012-03-15 17:47:06 +000048static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000049static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
50
bsalomon@google.com1d4edd32012-08-16 18:36:06 +000051static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11;
52static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4;
bsalomon@google.com27847de2011-02-22 20:59:41 +000053
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000054#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
joshualitt5f5a8d72015-02-25 14:09:45 -080055#define RETURN_IF_ABANDONED if (!fDrawBuffer) { return; }
56#define RETURN_FALSE_IF_ABANDONED if (!fDrawBuffer) { return false; }
57#define RETURN_NULL_IF_ABANDONED if (!fDrawBuffer) { return NULL; }
bsalomon@google.combc4b6542011-11-19 13:56:11 +000058
bsalomonf21dab92014-11-13 13:33:28 -080059class GrContext::AutoCheckFlush {
60public:
61 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
62
63 ~AutoCheckFlush() {
64 if (fContext->fFlushToReduceCacheSize) {
65 fContext->flush();
66 }
67 }
68
69private:
70 GrContext* fContext;
71};
72
krajcevski9c6d4d72014-08-12 07:26:25 -070073GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
74 const Options* opts) {
75 GrContext* context;
76 if (NULL == opts) {
77 context = SkNEW_ARGS(GrContext, (Options()));
78 } else {
79 context = SkNEW_ARGS(GrContext, (*opts));
80 }
81
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000082 if (context->init(backend, backendContext)) {
83 return context;
84 } else {
85 context->unref();
86 return NULL;
bsalomon@google.com27847de2011-02-22 20:59:41 +000087 }
bsalomon@google.com27847de2011-02-22 20:59:41 +000088}
89
krajcevski9c6d4d72014-08-12 07:26:25 -070090GrContext::GrContext(const Options& opts) : fOptions(opts) {
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000091 fGpu = NULL;
92 fPathRendererChain = NULL;
93 fSoftwarePathRenderer = NULL;
bsalomon0ea80f42015-02-11 10:49:59 -080094 fResourceCache = NULL;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000095 fFontCache = NULL;
96 fDrawBuffer = NULL;
97 fDrawBufferVBAllocPool = NULL;
98 fDrawBufferIBAllocPool = NULL;
bsalomonf21dab92014-11-13 13:33:28 -080099 fFlushToReduceCacheSize = false;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000100 fAARectRenderer = NULL;
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000101 fOvalRenderer = NULL;
robertphillips@google.com44a91dc2013-07-25 15:32:06 +0000102 fMaxTextureSizeOverride = 1 << 20;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000103}
104
105bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000106 SkASSERT(NULL == fGpu);
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000107
108 fGpu = GrGpu::Create(backend, backendContext, this);
109 if (NULL == fGpu) {
110 return false;
111 }
bsalomon33435572014-11-05 14:47:41 -0800112 this->initCommon();
113 return true;
114}
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000115
bsalomon33435572014-11-05 14:47:41 -0800116void GrContext::initCommon() {
bsalomon0ea80f42015-02-11 10:49:59 -0800117 fResourceCache = SkNEW(GrResourceCache);
118 fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
commit-bot@chromium.org1836d332013-07-16 22:55:03 +0000119
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000120 fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
121
robertphillips4ec84da2014-06-24 13:10:43 -0700122 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this)));
robertphillips@google.come930a072014-04-03 00:34:27 +0000123
joshualittb44293e2014-10-28 08:12:18 -0700124 fAARectRenderer = SkNEW_ARGS(GrAARectRenderer, (fGpu));
joshualitt5531d512014-12-17 15:50:11 -0800125 fOvalRenderer = SkNEW_ARGS(GrOvalRenderer, (fGpu));
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000126
127 fDidTestPMConversions = false;
128
129 this->setupDrawBuffer();
bsalomon@google.comc0af3172012-06-15 14:10:09 +0000130}
131
bsalomon@google.com27847de2011-02-22 20:59:41 +0000132GrContext::~GrContext() {
bsalomon@google.com733c0622013-04-24 17:59:32 +0000133 if (NULL == fGpu) {
134 return;
135 }
136
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000137 this->flush();
robertphillips@google.com5acc0e32012-05-17 12:01:02 +0000138
robertphillips@google.com950b1b02013-10-21 17:37:28 +0000139 for (int i = 0; i < fCleanUpData.count(); ++i) {
140 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
141 }
142
bsalomon0ea80f42015-02-11 10:49:59 -0800143 SkDELETE(fResourceCache);
bsalomon33435572014-11-05 14:47:41 -0800144 SkDELETE(fFontCache);
145 SkDELETE(fDrawBuffer);
146 SkDELETE(fDrawBufferVBAllocPool);
147 SkDELETE(fDrawBufferIBAllocPool);
bsalomon@google.com30085192011-08-19 15:42:31 +0000148
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000149 fAARectRenderer->unref();
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000150 fOvalRenderer->unref();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000151
bsalomon@google.com205d4602011-04-25 12:43:45 +0000152 fGpu->unref();
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000153 SkSafeUnref(fPathRendererChain);
154 SkSafeUnref(fSoftwarePathRenderer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000155}
156
bsalomon2354f842014-07-28 13:48:36 -0700157void GrContext::abandonContext() {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000158 // abandon first to so destructors
159 // don't try to free the resources in the API.
bsalomon0ea80f42015-02-11 10:49:59 -0800160 fResourceCache->abandonAll();
bsalomonc8dc1f72014-08-21 13:02:13 -0700161
robertphillipse3371302014-09-17 06:01:06 -0700162 fGpu->contextAbandoned();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000163
bsalomon@google.com30085192011-08-19 15:42:31 +0000164 // a path renderer may be holding onto resources that
165 // are now unusable
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000166 SkSafeSetNull(fPathRendererChain);
167 SkSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com30085192011-08-19 15:42:31 +0000168
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000169 delete fDrawBuffer;
170 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000171
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000172 delete fDrawBufferVBAllocPool;
173 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000174
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000175 delete fDrawBufferIBAllocPool;
176 fDrawBufferIBAllocPool = NULL;
177
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000178 fAARectRenderer->reset();
commit-bot@chromium.orgef284a82013-07-11 22:29:29 +0000179 fOvalRenderer->reset();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000180
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000181 fFontCache->freeAll();
robertphillips@google.come930a072014-04-03 00:34:27 +0000182 fLayerCache->freeAll();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000183}
184
bsalomon@google.com0a208a12013-06-28 18:57:35 +0000185void GrContext::resetContext(uint32_t state) {
186 fGpu->markContextDirty(state);
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000187}
188
189void GrContext::freeGpuResources() {
190 this->flush();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000191
bsalomon49f085d2014-09-05 13:34:00 -0700192 if (fDrawBuffer) {
bsalomonc8dc1f72014-08-21 13:02:13 -0700193 fDrawBuffer->purgeResources();
194 }
robertphillips@google.comff175842012-05-14 19:31:39 +0000195
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000196 fAARectRenderer->reset();
commit-bot@chromium.orgef284a82013-07-11 22:29:29 +0000197 fOvalRenderer->reset();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000198
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000199 fFontCache->freeAll();
robertphillips@google.come930a072014-04-03 00:34:27 +0000200 fLayerCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000201 // a path renderer may be holding onto resources
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000202 SkSafeSetNull(fPathRendererChain);
203 SkSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000204}
205
commit-bot@chromium.org95c20032014-05-09 14:29:32 +0000206void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
bsalomon71cb0c22014-11-14 12:10:14 -0800207 if (resourceCount) {
bsalomon0ea80f42015-02-11 10:49:59 -0800208 *resourceCount = fResourceCache->getBudgetedResourceCount();
bsalomon71cb0c22014-11-14 12:10:14 -0800209 }
210 if (resourceBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -0800211 *resourceBytes = fResourceCache->getBudgetedResourceBytes();
bsalomon71cb0c22014-11-14 12:10:14 -0800212 }
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000213}
214
kkinnunenc6cb56f2014-06-24 00:12:27 -0700215GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
216 const SkDeviceProperties&
217 leakyProperties,
218 bool enableDistanceFieldFonts) {
bsalomon6bc1b5f2015-02-23 09:06:38 -0800219 if (fGpu->caps()->pathRenderingSupport() && renderTarget->isMultisampled()) {
220 GrStencilBuffer* sb = renderTarget->renderTargetPriv().attachStencilBuffer();
221 if (sb) {
222 return GrStencilAndCoverTextContext::Create(this, leakyProperties);
223 }
jvanverth8c27a182014-10-14 08:45:50 -0700224 }
225
226 return GrDistanceFieldTextContext::Create(this, leakyProperties, enableDistanceFieldFonts);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700227}
228
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000229////////////////////////////////////////////////////////////////////////////////
bsalomond0423582015-02-06 08:49:24 -0800230enum ScratchTextureFlags {
231 kExact_ScratchTextureFlag = 0x1,
232 kNoPendingIO_ScratchTextureFlag = 0x2,
233 kNoCreate_ScratchTextureFlag = 0x4,
234};
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000235
bsalomond2a6f4e2015-02-04 10:55:54 -0800236bool GrContext::isConfigTexturable(GrPixelConfig config) const {
237 return fGpu->caps()->isConfigTexturable(config);
238}
239
240bool GrContext::npotTextureTileSupport() const {
241 return fGpu->caps()->npotTextureTileSupport();
242}
243
bsalomond0423582015-02-06 08:49:24 -0800244GrTexture* GrContext::createTexture(const GrSurfaceDesc& desc, bool budgeted, const void* srcData,
bsalomon37f9a262015-02-02 13:00:10 -0800245 size_t rowBytes) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800246 RETURN_NULL_IF_ABANDONED
bsalomond0423582015-02-06 08:49:24 -0800247 if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) &&
248 !this->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
bsalomond2a6f4e2015-02-04 10:55:54 -0800249 return NULL;
250 }
bsalomond0423582015-02-06 08:49:24 -0800251 if (!GrPixelConfigIsCompressed(desc.fConfig)) {
252 static const uint32_t kFlags = kExact_ScratchTextureFlag |
253 kNoCreate_ScratchTextureFlag;
254 if (GrTexture* texture = this->internalRefScratchTexture(desc, kFlags)) {
255 if (!srcData || texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
256 srcData, rowBytes)) {
257 if (!budgeted) {
bsalomon3582d3e2015-02-13 14:20:05 -0800258 texture->resourcePriv().makeUnbudgeted();
bsalomond0423582015-02-06 08:49:24 -0800259 }
260 return texture;
261 }
262 texture->unref();
263 }
264 }
265 return fGpu->createTexture(desc, budgeted, srcData, rowBytes);
266}
bsalomond2a6f4e2015-02-04 10:55:54 -0800267
bsalomond0423582015-02-06 08:49:24 -0800268GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& desc, ScratchTexMatch match,
269 bool calledDuringFlush) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800270 RETURN_NULL_IF_ABANDONED
bsalomond0423582015-02-06 08:49:24 -0800271 // Currently we don't recycle compressed textures as scratch.
272 if (GrPixelConfigIsCompressed(desc.fConfig)) {
273 return NULL;
274 } else {
275 uint32_t flags = 0;
276 if (kExact_ScratchTexMatch == match) {
277 flags |= kExact_ScratchTextureFlag;
278 }
279 if (calledDuringFlush) {
280 flags |= kNoPendingIO_ScratchTextureFlag;
281 }
282 return this->internalRefScratchTexture(desc, flags);
283 }
284}
285
286GrTexture* GrContext::internalRefScratchTexture(const GrSurfaceDesc& inDesc, uint32_t flags) {
287 SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig));
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000288
bsalomonf2703d82014-10-28 14:33:06 -0700289 SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc);
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000290
bsalomonf2703d82014-10-28 14:33:06 -0700291 if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
bsalomond0423582015-02-06 08:49:24 -0800292 if (!(kExact_ScratchTextureFlag & flags)) {
bsalomonbcf0a522014-10-08 08:40:09 -0700293 // bin by pow2 with a reasonable min
294 static const int MIN_SIZE = 16;
bsalomonf2703d82014-10-28 14:33:06 -0700295 GrSurfaceDesc* wdesc = desc.writable();
bsalomonbcf0a522014-10-08 08:40:09 -0700296 wdesc->fWidth = SkTMax(MIN_SIZE, GrNextPow2(desc->fWidth));
297 wdesc->fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc->fHeight));
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000298 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000299
bsalomon6bc1b5f2015-02-23 09:06:38 -0800300 GrScratchKey key;
301 GrTexturePriv::ComputeScratchKey(*desc, &key);
302 uint32_t scratchFlags = 0;
303 if (kNoPendingIO_ScratchTextureFlag & flags) {
304 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
305 } else if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
306 // If it is not a render target then it will most likely be populated by
307 // writePixels() which will trigger a flush if the texture has pending IO.
308 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
309 }
310 GrGpuResource* resource = fResourceCache->findAndRefScratchResource(key, scratchFlags);
311 if (resource) {
312 GrSurface* surface = static_cast<GrSurface*>(resource);
313 GrRenderTarget* rt = surface->asRenderTarget();
314 if (rt && fGpu->caps()->discardRenderTargetSupport()) {
315 rt->discard();
bsalomon000f8292014-10-15 19:04:14 -0700316 }
bsalomon6bc1b5f2015-02-23 09:06:38 -0800317 return surface->asTexture();
318 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000319 }
320
bsalomond0423582015-02-06 08:49:24 -0800321 if (!(kNoCreate_ScratchTextureFlag & flags)) {
bsalomon3582d3e2015-02-13 14:20:05 -0800322 return fGpu->createTexture(*desc, true, NULL, 0);
bsalomone167f962015-01-27 09:56:04 -0800323 }
bsalomond0423582015-02-06 08:49:24 -0800324
325 return NULL;
Brian Salomon9323b8b2014-10-07 15:07:38 -0400326}
327
bsalomon71cb0c22014-11-14 12:10:14 -0800328void GrContext::OverBudgetCB(void* data) {
bsalomon66a450f2014-11-13 13:19:10 -0800329 SkASSERT(data);
bsalomonf21dab92014-11-13 13:33:28 -0800330
bsalomon66a450f2014-11-13 13:19:10 -0800331 GrContext* context = reinterpret_cast<GrContext*>(data);
bsalomonf21dab92014-11-13 13:33:28 -0800332
333 // Flush the InOrderDrawBuffer to possibly free up some textures
334 context->fFlushToReduceCacheSize = true;
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000335}
336
bsalomon@google.com91958362011-06-13 17:58:13 +0000337int GrContext::getMaxTextureSize() const {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000338 return SkTMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride);
bsalomon@google.com91958362011-06-13 17:58:13 +0000339}
340
341int GrContext::getMaxRenderTargetSize() const {
bsalomon@google.combcce8922013-03-25 15:38:39 +0000342 return fGpu->caps()->maxRenderTargetSize();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000343}
344
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000345int GrContext::getMaxSampleCount() const {
bsalomon@google.combcce8922013-03-25 15:38:39 +0000346 return fGpu->caps()->maxSampleCount();
bsalomon@google.com8a70eef2013-03-19 13:58:55 +0000347}
348
bsalomon@google.com27847de2011-02-22 20:59:41 +0000349///////////////////////////////////////////////////////////////////////////////
350
bsalomon@google.com16e3dde2012-10-25 18:43:28 +0000351GrTexture* GrContext::wrapBackendTexture(const GrBackendTextureDesc& desc) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800352 RETURN_NULL_IF_ABANDONED
bsalomon@google.com16e3dde2012-10-25 18:43:28 +0000353 return fGpu->wrapBackendTexture(desc);
bsalomon@google.come269f212011-11-07 13:29:52 +0000354}
355
bsalomon@google.com16e3dde2012-10-25 18:43:28 +0000356GrRenderTarget* GrContext::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800357 RETURN_NULL_IF_ABANDONED
bsalomon@google.com16e3dde2012-10-25 18:43:28 +0000358 return fGpu->wrapBackendRenderTarget(desc);
bsalomon@google.come269f212011-11-07 13:29:52 +0000359}
360
bsalomon@google.com27847de2011-02-22 20:59:41 +0000361////////////////////////////////////////////////////////////////////////////////
362
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000363void GrContext::clear(const SkIRect* rect,
bsalomon@google.com07ea2db2012-08-17 14:06:49 +0000364 const GrColor color,
robertphillips@google.com56ce48a2013-10-31 21:44:25 +0000365 bool canIgnoreRect,
bsalomon41ebbdd2014-08-04 08:31:39 -0700366 GrRenderTarget* renderTarget) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800367 RETURN_IF_ABANDONED
bsalomon41ebbdd2014-08-04 08:31:39 -0700368 ASSERT_OWNED_RESOURCE(renderTarget);
bsalomon89c62982014-11-03 12:08:42 -0800369 SkASSERT(renderTarget);
370
bsalomonf21dab92014-11-13 13:33:28 -0800371 AutoCheckFlush acf(this);
egdanield78a1682014-07-09 10:41:26 -0700372 GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::clear", this);
joshualitt570d2f82015-02-25 13:19:48 -0800373 GrDrawTarget* target = this->prepareToDraw();
bsalomon41ebbdd2014-08-04 08:31:39 -0700374 if (NULL == target) {
375 return;
376 }
377 target->clear(rect, color, canIgnoreRect, renderTarget);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000378}
379
joshualitt25d9c152015-02-18 12:29:52 -0800380void GrContext::drawPaint(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800381 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800382 const GrPaint& origPaint,
383 const SkMatrix& viewMatrix) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800384 RETURN_IF_ABANDONED
bsalomon@google.com27847de2011-02-22 20:59:41 +0000385 // set rect to be big enough to fill the space, but not super-huge, so we
386 // don't overflow fixed-point implementations
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000387 SkRect r;
bsalomon@google.comd302f142011-03-03 13:54:13 +0000388 r.setLTRB(0, 0,
joshualitt25d9c152015-02-18 12:29:52 -0800389 SkIntToScalar(rt->width()),
390 SkIntToScalar(rt->height()));
bsalomon@google.com5dc26b92012-10-11 19:32:32 +0000391 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
joshualitt8fc6c2d2014-12-22 15:27:05 -0800392
393 // by definition this fills the entire clip, no need for AA
394 if (paint->isAntiAlias()) {
395 paint.writable()->setAntiAlias(false);
396 }
397
398 bool isPerspective = viewMatrix.hasPerspective();
bsalomon@google.com8f9cbd62011-12-09 15:55:34 +0000399
bsalomon@google.com4f83be82011-09-12 13:52:51 +0000400 // We attempt to map r by the inverse matrix and draw that. mapRect will
401 // map the four corners and bound them with a new rect. This will not
402 // produce a correct result for some perspective matrices.
joshualitt8fc6c2d2014-12-22 15:27:05 -0800403 if (!isPerspective) {
joshualitt5531d512014-12-17 15:50:11 -0800404 SkMatrix inverse;
405 if (!viewMatrix.invert(&inverse)) {
tfarina38406c82014-10-31 07:11:12 -0700406 SkDebugf("Could not invert matrix\n");
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000407 return;
408 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000409 inverse.mapRect(&r);
joshualitt570d2f82015-02-25 13:19:48 -0800410 this->drawRect(rt, clip, *paint, viewMatrix, r);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000411 } else {
joshualitt8fc6c2d2014-12-22 15:27:05 -0800412 SkMatrix localMatrix;
413 if (!viewMatrix.invert(&localMatrix)) {
tfarina38406c82014-10-31 07:11:12 -0700414 SkDebugf("Could not invert matrix\n");
bsalomon@google.com3cbaa2d2012-10-12 14:51:52 +0000415 return;
bsalomon@google.com8c2fe992011-09-13 15:27:18 +0000416 }
joshualitt8fc6c2d2014-12-22 15:27:05 -0800417
418 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800419 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800420 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, paint, &acf);
joshualitt8fc6c2d2014-12-22 15:27:05 -0800421 if (NULL == target) {
422 return;
423 }
424
425 GR_CREATE_TRACE_MARKER("GrContext::drawPaintWithPerspective", target);
joshualitt44701df2015-02-23 14:44:57 -0800426 target->drawRect(&pipelineBuilder,
427 paint->getColor(),
428 SkMatrix::I(),
429 r,
430 NULL,
431 &localMatrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000432 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000433}
434
commit-bot@chromium.org03e3e892013-10-02 18:19:17 +0000435#ifdef SK_DEVELOPER
436void GrContext::dumpFontCache() const {
437 fFontCache->dump();
438}
439#endif
440
bsalomon@google.com205d4602011-04-25 12:43:45 +0000441////////////////////////////////////////////////////////////////////////////////
442
bsalomon@google.com27847de2011-02-22 20:59:41 +0000443/* create a triangle strip that strokes the specified triangle. There are 8
444 unique vertices, but we repreat the last 2 to close up. Alternatively we
445 could use an indices array, and then only send 8 verts, but not sure that
446 would be faster.
447 */
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000448static void setStrokeRectStrip(SkPoint verts[10], SkRect rect,
bsalomon@google.com81712882012-11-01 17:12:34 +0000449 SkScalar width) {
450 const SkScalar rad = SkScalarHalf(width);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000451 rect.sort();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000452
453 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
454 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
455 verts[2].set(rect.fRight - rad, rect.fTop + rad);
456 verts[3].set(rect.fRight + rad, rect.fTop - rad);
457 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
458 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
459 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
460 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
461 verts[8] = verts[0];
462 verts[9] = verts[1];
463}
464
bsalomonc30aaa02014-08-13 07:15:29 -0700465static inline bool is_irect(const SkRect& r) {
tfarina38406c82014-10-31 07:11:12 -0700466 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) &&
467 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
bsalomonc30aaa02014-08-13 07:15:29 -0700468}
469
bsalomon@google.com205d4602011-04-25 12:43:45 +0000470static bool apply_aa_to_rect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800471 GrPipelineBuilder* pipelineBuilder,
joshualitt9853cce2014-11-17 14:22:48 -0800472 SkRect* devBoundRect,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000473 const SkRect& rect,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000474 SkScalar strokeWidth,
joshualitt2e3b3e32014-12-09 13:31:14 -0800475 const SkMatrix& combinedMatrix,
476 GrColor color) {
egdaniel8dd688b2015-01-22 10:16:09 -0800477 if (pipelineBuilder->getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000478 return false;
479 }
480
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000481#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000482 if (strokeWidth >= 0) {
483#endif
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000484 if (!combinedMatrix.preservesAxisAlignment()) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000485 return false;
486 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000487
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000488#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000489 } else {
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000490 if (!combinedMatrix.preservesRightAngles()) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000491 return false;
492 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000493 }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000494#endif
bsalomon@google.com205d4602011-04-25 12:43:45 +0000495
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000496 combinedMatrix.mapRect(devBoundRect, rect);
derekfe638d1c2014-12-02 13:51:29 -0800497 if (!combinedMatrix.rectStaysRect()) {
498 return true;
499 }
500
bsalomonc30aaa02014-08-13 07:15:29 -0700501 if (strokeWidth < 0) {
502 return !is_irect(*devBoundRect);
503 }
robertphillips@google.com28ac96e2013-05-13 13:38:35 +0000504
bsalomon9c0822a2014-08-11 11:07:48 -0700505 return true;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000506}
507
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000508static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
509 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
510 point.fY >= rect.fTop && point.fY <= rect.fBottom;
511}
512
joshualitt25d9c152015-02-18 12:29:52 -0800513void GrContext::drawRect(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800514 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800515 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -0800516 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000517 const SkRect& rect,
bsalomon01c8da12014-08-04 09:21:30 -0700518 const GrStrokeInfo* strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800519 RETURN_IF_ABANDONED
bsalomon49f085d2014-09-05 13:34:00 -0700520 if (strokeInfo && strokeInfo->isDashed()) {
egdanield58a0ba2014-06-11 10:30:05 -0700521 SkPath path;
522 path.addRect(rect);
joshualitt570d2f82015-02-25 13:19:48 -0800523 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -0700524 return;
525 }
526
bsalomonf21dab92014-11-13 13:33:28 -0800527 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800528 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800529 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -0700530 if (NULL == target) {
531 return;
532 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000533
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +0000534 GR_CREATE_TRACE_MARKER("GrContext::drawRect", target);
egdanield58a0ba2014-06-11 10:30:05 -0700535 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getStrokeRec().getWidth();
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000536
537 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
538 // cases where the RT is fully inside a stroke.
539 if (width < 0) {
540 SkRect rtRect;
egdaniel8dd688b2015-01-22 10:16:09 -0800541 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000542 SkRect clipSpaceRTRect = rtRect;
joshualitt570d2f82015-02-25 13:19:48 -0800543 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
joshualitt44701df2015-02-23 14:44:57 -0800544 if (checkClip) {
joshualitt570d2f82015-02-25 13:19:48 -0800545 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
546 SkIntToScalar(clip.origin().fY));
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000547 }
548 // Does the clip contain the entire RT?
joshualitt570d2f82015-02-25 13:19:48 -0800549 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000550 SkMatrix invM;
joshualitt8059eb92014-12-29 15:10:07 -0800551 if (!viewMatrix.invert(&invM)) {
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000552 return;
553 }
554 // Does the rect bound the RT?
555 SkPoint srcSpaceRTQuad[4];
556 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
557 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
558 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
559 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
560 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
561 // Will it blend?
562 GrColor clearColor;
563 if (paint.isOpaqueAndConstantColor(&clearColor)) {
joshualitt25d9c152015-02-18 12:29:52 -0800564 target->clear(NULL, clearColor, true, rt);
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000565 return;
566 }
567 }
568 }
569 }
570
joshualitt2e3b3e32014-12-09 13:31:14 -0800571 GrColor color = paint.getColor();
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000572 SkRect devBoundRect;
egdaniel8dd688b2015-01-22 10:16:09 -0800573 bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isMultisampled();
574 bool doAA = needAA && apply_aa_to_rect(target, &pipelineBuilder, &devBoundRect, rect, width,
joshualitt8059eb92014-12-29 15:10:07 -0800575 viewMatrix, color);
egdanield58a0ba2014-06-11 10:30:05 -0700576
bsalomon@google.com205d4602011-04-25 12:43:45 +0000577 if (doAA) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000578 if (width >= 0) {
bsalomon395ef052014-11-12 11:35:22 -0800579 const SkStrokeRec& strokeRec = strokeInfo->getStrokeRec();
joshualitt9853cce2014-11-17 14:22:48 -0800580 fAARectRenderer->strokeAARect(target,
egdaniel8dd688b2015-01-22 10:16:09 -0800581 &pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800582 color,
joshualitt8059eb92014-12-29 15:10:07 -0800583 viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800584 rect,
joshualitt9853cce2014-11-17 14:22:48 -0800585 devBoundRect,
586 strokeRec);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000587 } else {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000588 // filled AA rect
joshualitt8059eb92014-12-29 15:10:07 -0800589 fAARectRenderer->fillAARect(target,
egdaniel8dd688b2015-01-22 10:16:09 -0800590 &pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -0800591 color,
592 viewMatrix,
593 rect,
joshualittd27f73e2014-12-29 07:43:36 -0800594 devBoundRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000595 }
596 return;
597 }
598
bsalomon@google.com27847de2011-02-22 20:59:41 +0000599 if (width >= 0) {
600 // TODO: consider making static vertex buffers for these cases.
bsalomon@google.com64386952013-02-08 21:22:44 +0000601 // Hairline could be done by just adding closing vertex to
602 // unitSquareVertexBuffer()
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000603
bsalomon@google.com27847de2011-02-22 20:59:41 +0000604 static const int worstCaseVertCount = 10;
joshualitt8059eb92014-12-29 15:10:07 -0800605 SkAutoTUnref<const GrGeometryProcessor> gp(
606 GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType,
607 color,
608 viewMatrix,
609 SkMatrix::I()));
joshualitt9853cce2014-11-17 14:22:48 -0800610 GrDrawTarget::AutoReleaseGeometry geo(target,
611 worstCaseVertCount,
joshualitt2dd1ae02014-12-03 06:24:10 -0800612 gp->getVertexStride(),
joshualitt9853cce2014-11-17 14:22:48 -0800613 0);
joshualitt2dd1ae02014-12-03 06:24:10 -0800614 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000615
616 if (!geo.succeeded()) {
tfarina38406c82014-10-31 07:11:12 -0700617 SkDebugf("Failed to get space for vertices!\n");
bsalomon@google.com27847de2011-02-22 20:59:41 +0000618 return;
619 }
620
621 GrPrimitiveType primType;
622 int vertCount;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000623 SkPoint* vertex = geo.positions();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000624
625 if (width > 0) {
626 vertCount = 10;
bsalomon@google.com47059542012-06-06 20:51:20 +0000627 primType = kTriangleStrip_GrPrimitiveType;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000628 setStrokeRectStrip(vertex, rect, width);
629 } else {
630 // hairline
631 vertCount = 5;
bsalomon@google.com47059542012-06-06 20:51:20 +0000632 primType = kLineStrip_GrPrimitiveType;
bsalomon@google.com27847de2011-02-22 20:59:41 +0000633 vertex[0].set(rect.fLeft, rect.fTop);
634 vertex[1].set(rect.fRight, rect.fTop);
635 vertex[2].set(rect.fRight, rect.fBottom);
636 vertex[3].set(rect.fLeft, rect.fBottom);
637 vertex[4].set(rect.fLeft, rect.fTop);
638 }
639
egdaniel8dd688b2015-01-22 10:16:09 -0800640 target->drawNonIndexed(&pipelineBuilder, gp, primType, 0, vertCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000641 } else {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000642 // filled BW rect
egdaniel8dd688b2015-01-22 10:16:09 -0800643 target->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000644 }
645}
646
joshualitt25d9c152015-02-18 12:29:52 -0800647void GrContext::drawNonAARectToRect(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800648 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800649 const GrPaint& paint,
joshualitt16b27892014-12-18 07:47:16 -0800650 const SkMatrix& viewMatrix,
651 const SkRect& rectToDraw,
652 const SkRect& localRect,
653 const SkMatrix* localMatrix) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800654 RETURN_IF_ABANDONED
bsalomonf21dab92014-11-13 13:33:28 -0800655 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800656 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800657 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -0700658 if (NULL == target) {
659 return;
660 }
bsalomon@google.com64386952013-02-08 21:22:44 +0000661
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +0000662 GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target);
663
joshualitt44701df2015-02-23 14:44:57 -0800664 target->drawRect(&pipelineBuilder,
665 paint.getColor(),
666 viewMatrix,
667 rectToDraw,
668 &localRect,
egdaniel8dd688b2015-01-22 10:16:09 -0800669 localMatrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000670}
671
joshualitt56995b52014-12-11 15:44:02 -0800672static const GrGeometryProcessor* set_vertex_attributes(const SkPoint* texCoords,
673 const GrColor* colors,
674 int* colorOffset,
675 int* texOffset,
joshualitt8059eb92014-12-29 15:10:07 -0800676 GrColor color,
677 const SkMatrix& viewMatrix) {
robertphillips@google.com42903302013-04-20 12:26:07 +0000678 *texOffset = -1;
679 *colorOffset = -1;
joshualitt5478d422014-11-14 16:00:38 -0800680 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType;
bsalomon49f085d2014-09-05 13:34:00 -0700681 if (texCoords && colors) {
joshualitt5478d422014-11-14 16:00:38 -0800682 *colorOffset = sizeof(SkPoint);
683 *texOffset = sizeof(SkPoint) + sizeof(GrColor);
684 flags |= GrDefaultGeoProcFactory::kColor_GPType |
685 GrDefaultGeoProcFactory::kLocalCoord_GPType;
bsalomon49f085d2014-09-05 13:34:00 -0700686 } else if (texCoords) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000687 *texOffset = sizeof(SkPoint);
joshualitt5478d422014-11-14 16:00:38 -0800688 flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType;
bsalomon49f085d2014-09-05 13:34:00 -0700689 } else if (colors) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000690 *colorOffset = sizeof(SkPoint);
joshualitt5478d422014-11-14 16:00:38 -0800691 flags |= GrDefaultGeoProcFactory::kColor_GPType;
robertphillips@google.com42903302013-04-20 12:26:07 +0000692 }
joshualitt8059eb92014-12-29 15:10:07 -0800693 return GrDefaultGeoProcFactory::Create(flags, color, viewMatrix, SkMatrix::I());
robertphillips@google.com42903302013-04-20 12:26:07 +0000694}
695
joshualitt25d9c152015-02-18 12:29:52 -0800696void GrContext::drawVertices(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800697 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800698 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -0800699 const SkMatrix& viewMatrix,
bsalomon@google.com27847de2011-02-22 20:59:41 +0000700 GrPrimitiveType primitiveType,
701 int vertexCount,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000702 const SkPoint positions[],
703 const SkPoint texCoords[],
bsalomon@google.com27847de2011-02-22 20:59:41 +0000704 const GrColor colors[],
705 const uint16_t indices[],
706 int indexCount) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800707 RETURN_IF_ABANDONED
bsalomonf21dab92014-11-13 13:33:28 -0800708 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800709 GrPipelineBuilder pipelineBuilder;
bsalomonf21dab92014-11-13 13:33:28 -0800710 GrDrawTarget::AutoReleaseGeometry geo; // must be inside AutoCheckFlush scope
commit-bot@chromium.org5a567932014-01-08 21:26:09 +0000711
joshualitt570d2f82015-02-25 13:19:48 -0800712 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -0700713 if (NULL == target) {
714 return;
715 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000716
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +0000717 GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target);
718
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000719 int colorOffset = -1, texOffset = -1;
joshualitt56995b52014-12-11 15:44:02 -0800720 SkAutoTUnref<const GrGeometryProcessor> gp(
joshualitt8059eb92014-12-29 15:10:07 -0800721 set_vertex_attributes(texCoords, colors, &colorOffset, &texOffset,
722 paint.getColor(), viewMatrix));
jvanverth@google.com9b855c72013-03-01 18:21:22 +0000723
joshualitt56995b52014-12-11 15:44:02 -0800724 size_t vertexStride = gp->getVertexStride();
joshualitt2dd1ae02014-12-03 06:24:10 -0800725 SkASSERT(vertexStride == sizeof(SkPoint) + (SkToBool(texCoords) ? sizeof(SkPoint) : 0)
726 + (SkToBool(colors) ? sizeof(GrColor) : 0));
joshualitt9853cce2014-11-17 14:22:48 -0800727 if (!geo.set(target, vertexCount, vertexStride, indexCount)) {
joshualittd1aa8ff2014-11-04 07:47:55 -0800728 SkDebugf("Failed to get space for vertices!\n");
729 return;
730 }
731 void* curVertex = geo.vertices();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000732
joshualittd1aa8ff2014-11-04 07:47:55 -0800733 for (int i = 0; i < vertexCount; ++i) {
734 *((SkPoint*)curVertex) = positions[i];
bsalomon@google.com27847de2011-02-22 20:59:41 +0000735
joshualittd1aa8ff2014-11-04 07:47:55 -0800736 if (texOffset >= 0) {
737 *(SkPoint*)((intptr_t)curVertex + texOffset) = texCoords[i];
bsalomon@google.com27847de2011-02-22 20:59:41 +0000738 }
joshualittd1aa8ff2014-11-04 07:47:55 -0800739 if (colorOffset >= 0) {
740 *(GrColor*)((intptr_t)curVertex + colorOffset) = colors[i];
741 }
joshualitt9853cce2014-11-17 14:22:48 -0800742 curVertex = (void*)((intptr_t)curVertex + vertexStride);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000743 }
744
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000745 // we don't currently apply offscreen AA to this path. Need improved
bsalomon@google.com91958362011-06-13 17:58:13 +0000746 // management of GrDrawTarget's geometry to avoid copying points per-tile.
bsalomon49f085d2014-09-05 13:34:00 -0700747 if (indices) {
joshualittd1aa8ff2014-11-04 07:47:55 -0800748 uint16_t* curIndex = (uint16_t*)geo.indices();
749 for (int i = 0; i < indexCount; ++i) {
750 curIndex[i] = indices[i];
751 }
egdaniel8dd688b2015-01-22 10:16:09 -0800752 target->drawIndexed(&pipelineBuilder, gp, primitiveType, 0, 0, vertexCount, indexCount);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000753 } else {
egdaniel8dd688b2015-01-22 10:16:09 -0800754 target->drawNonIndexed(&pipelineBuilder, gp, primitiveType, 0, vertexCount);
bsalomon@google.com8295dc12011-05-02 12:53:34 +0000755 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000756}
757
bsalomon@google.com06afe7b2011-04-26 15:31:40 +0000758///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com93c96602012-04-27 13:05:21 +0000759
joshualitt25d9c152015-02-18 12:29:52 -0800760void GrContext::drawRRect(GrRenderTarget*rt,
joshualitt570d2f82015-02-25 13:19:48 -0800761 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800762 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -0800763 const SkMatrix& viewMatrix,
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000764 const SkRRect& rrect,
egdanield58a0ba2014-06-11 10:30:05 -0700765 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800766 RETURN_IF_ABANDONED
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000767 if (rrect.isEmpty()) {
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +0000768 return;
769 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +0000770
egdanield58a0ba2014-06-11 10:30:05 -0700771 if (strokeInfo.isDashed()) {
772 SkPath path;
773 path.addRRect(rrect);
joshualitt570d2f82015-02-25 13:19:48 -0800774 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -0700775 return;
776 }
777
bsalomonf21dab92014-11-13 13:33:28 -0800778 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800779 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800780 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -0700781 if (NULL == target) {
782 return;
783 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +0000784
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +0000785 GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target);
786
egdanield58a0ba2014-06-11 10:30:05 -0700787 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
788
joshualitt2e3b3e32014-12-09 13:31:14 -0800789 GrColor color = paint.getColor();
joshualitt44701df2015-02-23 14:44:57 -0800790 if (!fOvalRenderer->drawRRect(target,
791 &pipelineBuilder,
792 color,
793 viewMatrix,
794 paint.isAntiAlias(),
795 rrect,
796 strokeRec)) {
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +0000797 SkPath path;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000798 path.addRRect(rrect);
egdaniel8dd688b2015-01-22 10:16:09 -0800799 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
800 path, strokeInfo);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +0000801 }
802}
803
804///////////////////////////////////////////////////////////////////////////////
805
joshualitt25d9c152015-02-18 12:29:52 -0800806void GrContext::drawDRRect(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800807 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800808 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -0800809 const SkMatrix& viewMatrix,
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000810 const SkRRect& outer,
811 const SkRRect& inner) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800812 RETURN_IF_ABANDONED
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000813 if (outer.isEmpty()) {
814 return;
815 }
816
bsalomonf21dab92014-11-13 13:33:28 -0800817 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800818 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800819 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000820
821 GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
822
joshualitt2e3b3e32014-12-09 13:31:14 -0800823 GrColor color = paint.getColor();
joshualitt44701df2015-02-23 14:44:57 -0800824 if (!fOvalRenderer->drawDRRect(target,
825 &pipelineBuilder,
826 color,
827 viewMatrix,
828 paint.isAntiAlias(),
829 outer,
830 inner)) {
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000831 SkPath path;
832 path.addRRect(inner);
833 path.addRRect(outer);
834 path.setFillType(SkPath::kEvenOdd_FillType);
835
egdanield58a0ba2014-06-11 10:30:05 -0700836 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
egdaniel8dd688b2015-01-22 10:16:09 -0800837 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
838 path, fillRec);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +0000839 }
840}
841
842///////////////////////////////////////////////////////////////////////////////
843
joshualitt570d2f82015-02-25 13:19:48 -0800844void GrContext::drawOval(GrRenderTarget* rt,
845 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800846 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -0800847 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000848 const SkRect& oval,
egdanield58a0ba2014-06-11 10:30:05 -0700849 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800850 RETURN_IF_ABANDONED
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +0000851 if (oval.isEmpty()) {
852 return;
853 }
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000854
egdanield58a0ba2014-06-11 10:30:05 -0700855 if (strokeInfo.isDashed()) {
856 SkPath path;
857 path.addOval(oval);
joshualitt570d2f82015-02-25 13:19:48 -0800858 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -0700859 return;
860 }
861
bsalomonf21dab92014-11-13 13:33:28 -0800862 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800863 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800864 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -0700865 if (NULL == target) {
866 return;
867 }
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000868
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +0000869 GR_CREATE_TRACE_MARKER("GrContext::drawOval", target);
870
egdanield58a0ba2014-06-11 10:30:05 -0700871 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
872
joshualitt2e3b3e32014-12-09 13:31:14 -0800873 GrColor color = paint.getColor();
joshualitt44701df2015-02-23 14:44:57 -0800874 if (!fOvalRenderer->drawOval(target,
875 &pipelineBuilder,
876 color,
877 viewMatrix,
878 paint.isAntiAlias(),
879 oval,
880 strokeRec)) {
bsalomon@google.com93c96602012-04-27 13:05:21 +0000881 SkPath path;
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000882 path.addOval(oval);
egdaniel8dd688b2015-01-22 10:16:09 -0800883 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
884 path, strokeInfo);
skia.committer@gmail.com98ded842013-01-23 07:06:17 +0000885 }
bsalomon@google.com150d2842012-01-12 20:19:56 +0000886}
bsalomon@google.com27847de2011-02-22 20:59:41 +0000887
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000888// Can 'path' be drawn as a pair of filled nested rectangles?
889static bool is_nested_rects(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800890 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800891 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800892 const SkMatrix& viewMatrix,
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000893 const SkPath& path,
894 const SkStrokeRec& stroke,
bsalomon9c0822a2014-08-11 11:07:48 -0700895 SkRect rects[2]) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000896 SkASSERT(stroke.isFillStyle());
897
898 if (path.isInverseFillType()) {
899 return false;
900 }
901
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000902 // TODO: this restriction could be lifted if we were willing to apply
903 // the matrix to all the points individually rather than just to the rect
joshualitt8059eb92014-12-29 15:10:07 -0800904 if (!viewMatrix.preservesAxisAlignment()) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000905 return false;
906 }
907
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000908 SkPath::Direction dirs[2];
909 if (!path.isNestedRects(rects, dirs)) {
910 return false;
911 }
912
robertphillips@google.com8d3c6402013-08-20 12:11:31 +0000913 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000914 // The two rects need to be wound opposite to each other
robertphillips@google.com8d3c6402013-08-20 12:11:31 +0000915 return false;
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000916 }
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000917
robertphillips@google.com8d3c6402013-08-20 12:11:31 +0000918 // Right now, nested rects where the margin is not the same width
919 // all around do not render correctly
920 const SkScalar* outer = rects[0].asScalars();
921 const SkScalar* inner = rects[1].asScalars();
922
robertphillips183e9852014-10-21 11:25:37 -0700923 bool allEq = true;
924
robertphillips@google.com8d3c6402013-08-20 12:11:31 +0000925 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
robertphillips183e9852014-10-21 11:25:37 -0700926 bool allGoE1 = margin >= SK_Scalar1;
927
robertphillips@google.com8d3c6402013-08-20 12:11:31 +0000928 for (int i = 1; i < 4; ++i) {
929 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
robertphillips183e9852014-10-21 11:25:37 -0700930 if (temp < SK_Scalar1) {
931 allGoE1 = false;
932 }
robertphillips@google.com8d3c6402013-08-20 12:11:31 +0000933 if (!SkScalarNearlyEqual(margin, temp)) {
robertphillips183e9852014-10-21 11:25:37 -0700934 allEq = false;
robertphillips@google.com8d3c6402013-08-20 12:11:31 +0000935 }
936 }
937
robertphillips183e9852014-10-21 11:25:37 -0700938 return allEq || allGoE1;
robertphillips@google.com8d3c6402013-08-20 12:11:31 +0000939}
robertphillips@google.com83d1a682013-05-17 12:50:27 +0000940
joshualitt25d9c152015-02-18 12:29:52 -0800941void GrContext::drawPath(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800942 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800943 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -0800944 const SkMatrix& viewMatrix,
945 const SkPath& path,
946 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800947 RETURN_IF_ABANDONED
bsalomon@google.comfa6ac932011-10-05 19:57:55 +0000948 if (path.isEmpty()) {
sugoi@google.com12b4e272012-12-06 20:13:11 +0000949 if (path.isInverseFillType()) {
joshualitt570d2f82015-02-25 13:19:48 -0800950 this->drawPaint(rt, clip, paint, viewMatrix);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +0000951 }
952 return;
953 }
954
joshualitt2e3b3e32014-12-09 13:31:14 -0800955 GrColor color = paint.getColor();
egdanield58a0ba2014-06-11 10:30:05 -0700956 if (strokeInfo.isDashed()) {
egdaniele61c4112014-06-12 10:24:21 -0700957 SkPoint pts[2];
958 if (path.isLine(pts)) {
bsalomonf21dab92014-11-13 13:33:28 -0800959 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800960 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800961 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -0700962 if (NULL == target) {
963 return;
joshualittd27f73e2014-12-29 07:43:36 -0800964 }
egdaniele61c4112014-06-12 10:24:21 -0700965
egdaniel8dd688b2015-01-22 10:16:09 -0800966 if (GrDashingEffect::DrawDashLine(fGpu, target, &pipelineBuilder, color, viewMatrix,
967 pts, paint, strokeInfo)) {
joshualittd27f73e2014-12-29 07:43:36 -0800968 return;
egdaniele61c4112014-06-12 10:24:21 -0700969 }
970 }
971
972 // Filter dashed path into new path with the dashing applied
egdanield58a0ba2014-06-11 10:30:05 -0700973 const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo();
974 SkTLazy<SkPath> effectPath;
975 GrStrokeInfo newStrokeInfo(strokeInfo, false);
976 SkStrokeRec* stroke = newStrokeInfo.getStrokeRecPtr();
977 if (SkDashPath::FilterDashPath(effectPath.init(), path, stroke, NULL, info)) {
joshualitt570d2f82015-02-25 13:19:48 -0800978 this->drawPath(rt, clip, paint, viewMatrix, *effectPath.get(), newStrokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -0700979 return;
980 }
981
joshualitt570d2f82015-02-25 13:19:48 -0800982 this->drawPath(rt, clip, paint, viewMatrix, path, newStrokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -0700983 return;
984 }
985
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000986 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +0000987 // Scratch textures can be recycled after they are returned to the texture
988 // cache. This presents a potential hazard for buffered drawing. However,
989 // the writePixels that uploads to the scratch will perform a flush so we're
990 // OK.
bsalomonf21dab92014-11-13 13:33:28 -0800991 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800992 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800993 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -0700994 if (NULL == target) {
995 return;
996 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +0000997
egdaniel93a37bc2014-07-21 13:47:57 -0700998 GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isConvex());
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +0000999
egdanield58a0ba2014-06-11 10:30:05 -07001000 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1001
egdaniel8dd688b2015-01-22 10:16:09 -08001002 bool useCoverageAA = paint.isAntiAlias() &&
1003 !pipelineBuilder.getRenderTarget()->isMultisampled();
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001004
egdanield58a0ba2014-06-11 10:30:05 -07001005 if (useCoverageAA && strokeRec.getWidth() < 0 && !path.isConvex()) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001006 // Concave AA paths are expensive - try to avoid them for special cases
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001007 SkRect rects[2];
1008
egdaniel8dd688b2015-01-22 10:16:09 -08001009 if (is_nested_rects(target, &pipelineBuilder, color, viewMatrix, path, strokeRec, rects)) {
joshualitt44701df2015-02-23 14:44:57 -08001010 fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, color, viewMatrix, rects);
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001011 return;
1012 }
1013 }
1014
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001015 SkRect ovalRect;
1016 bool isOval = path.isOval(&ovalRect);
1017
joshualitt8059eb92014-12-29 15:10:07 -08001018 if (!isOval || path.isInverseFillType() ||
joshualitt44701df2015-02-23 14:44:57 -08001019 !fOvalRenderer->drawOval(target,
1020 &pipelineBuilder,
1021 color,
1022 viewMatrix,
1023 paint.isAntiAlias(),
1024 ovalRect,
1025 strokeRec)) {
egdaniel8dd688b2015-01-22 10:16:09 -08001026 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1027 path, strokeInfo);
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001028 }
1029}
1030
joshualitt9853cce2014-11-17 14:22:48 -08001031void GrContext::internalDrawPath(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -08001032 GrPipelineBuilder* pipelineBuilder,
joshualitt5531d512014-12-17 15:50:11 -08001033 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -08001034 GrColor color,
joshualitt9853cce2014-11-17 14:22:48 -08001035 bool useAA,
1036 const SkPath& path,
egdanield58a0ba2014-06-11 10:30:05 -07001037 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001038 RETURN_IF_ABANDONED
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +00001039 SkASSERT(!path.isEmpty());
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001040
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +00001041 GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target);
1042
1043
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001044 // An Assumption here is that path renderer would use some form of tweaking
1045 // the src color (either the input alpha or in the frag shader) to implement
1046 // aa. If we have some future driver-mojo path AA that can do the right
1047 // thing WRT to the blend then we'll need some query on the PR.
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001048 bool useCoverageAA = useAA &&
egdaniel0bdeec92015-02-23 12:12:54 -08001049 !pipelineBuilder->getRenderTarget()->isMultisampled();
bsalomon@google.com289533a2011-10-27 12:34:25 +00001050
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001051
1052 GrPathRendererChain::DrawType type =
1053 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
joshualitt9853cce2014-11-17 14:22:48 -08001054 GrPathRendererChain::kColor_DrawType;
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001055
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001056 const SkPath* pathPtr = &path;
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +00001057 SkTLazy<SkPath> tmpPath;
egdanield58a0ba2014-06-11 10:30:05 -07001058 SkTCopyOnFirstWrite<SkStrokeRec> stroke(strokeInfo.getStrokeRec());
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001059
1060 // Try a 1st time without stroking the path and without allowing the SW renderer
egdaniel8dd688b2015-01-22 10:16:09 -08001061 GrPathRenderer* pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
1062 *stroke, false, type);
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001063
robertphillips@google.come79f3202014-02-11 16:30:21 +00001064 if (NULL == pr) {
joshualitt5531d512014-12-17 15:50:11 -08001065 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, NULL)) {
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001066 // It didn't work the 1st time, so try again with the stroked path
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +00001067 if (stroke->applyToPath(tmpPath.init(), *pathPtr)) {
1068 pathPtr = tmpPath.get();
1069 stroke.writable()->setFillStyle();
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001070 if (pathPtr->isEmpty()) {
1071 return;
1072 }
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001073 }
1074 }
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +00001075
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001076 // This time, allow SW renderer
egdaniel8dd688b2015-01-22 10:16:09 -08001077 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *stroke, true,
1078 type);
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001079 }
1080
robertphillips@google.come79f3202014-02-11 16:30:21 +00001081 if (NULL == pr) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +00001082#ifdef SK_DEBUG
tfarina38406c82014-10-31 07:11:12 -07001083 SkDebugf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001084#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001085 return;
1086 }
1087
egdaniel8dd688b2015-01-22 10:16:09 -08001088 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *stroke, useCoverageAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001089}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001090
bsalomon@google.com27847de2011-02-22 20:59:41 +00001091////////////////////////////////////////////////////////////////////////////////
1092
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001093void GrContext::flush(int flagsBitfield) {
robertphillips@google.come7db8d62013-07-04 11:48:52 +00001094 if (NULL == fDrawBuffer) {
1095 return;
1096 }
1097
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001098 if (kDiscard_FlushBit & flagsBitfield) {
1099 fDrawBuffer->reset();
1100 } else {
bsalomon@google.com6e4e6502013-02-25 20:12:45 +00001101 fDrawBuffer->flush();
junov@google.com53a55842011-06-08 22:55:10 +00001102 }
bsalomonf21dab92014-11-13 13:33:28 -08001103 fFlushToReduceCacheSize = false;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001104}
1105
bsalomon81beccc2014-10-13 12:32:55 -07001106bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
1107 const void* inPixels, size_t outRowBytes, void* outPixels) {
1108 SkSrcPixelInfo srcPI;
jvanverthfa1e8a72014-12-22 08:31:49 -08001109 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL)) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001110 return false;
1111 }
bsalomon81beccc2014-10-13 12:32:55 -07001112 srcPI.fAlphaType = kUnpremul_SkAlphaType;
1113 srcPI.fPixels = inPixels;
1114 srcPI.fRowBytes = inRowBytes;
1115
1116 SkDstPixelInfo dstPI;
1117 dstPI.fColorType = srcPI.fColorType;
1118 dstPI.fAlphaType = kPremul_SkAlphaType;
1119 dstPI.fPixels = outPixels;
1120 dstPI.fRowBytes = outRowBytes;
1121
1122 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001123}
1124
bsalomon81beccc2014-10-13 12:32:55 -07001125bool GrContext::writeSurfacePixels(GrSurface* surface,
1126 int left, int top, int width, int height,
1127 GrPixelConfig srcConfig, const void* buffer, size_t rowBytes,
1128 uint32_t pixelOpsFlags) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001129 RETURN_FALSE_IF_ABANDONED
bsalomon81beccc2014-10-13 12:32:55 -07001130 {
1131 GrTexture* texture = NULL;
1132 if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asTexture()) &&
1133 fGpu->canWriteTexturePixels(texture, srcConfig)) {
1134
1135 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) &&
1136 surface->surfacePriv().hasPendingIO()) {
1137 this->flush();
1138 }
1139 return fGpu->writeTexturePixels(texture, left, top, width, height,
1140 srcConfig, buffer, rowBytes);
1141 // Don't need to check kFlushWrites_PixelOp here, we just did a direct write so the
1142 // upload is already flushed.
1143 }
1144 }
1145
1146 // If we didn't do a direct texture write then we upload the pixels to a texture and draw.
1147 GrRenderTarget* renderTarget = surface->asRenderTarget();
1148 if (NULL == renderTarget) {
1149 return false;
1150 }
1151
1152 // We ignore the preferred config unless it is a R/B swap of the src config. In that case
1153 // we will upload the original src data to a scratch texture but we will spoof it as the swapped
1154 // config. This scratch will then have R and B swapped. We correct for this by swapping again
1155 // when drawing the scratch to the dst using a conversion effect.
1156 bool swapRAndB = false;
1157 GrPixelConfig writeConfig = srcConfig;
1158 if (GrPixelConfigSwapRAndB(srcConfig) ==
1159 fGpu->preferredWritePixelsConfig(srcConfig, renderTarget->config())) {
1160 writeConfig = GrPixelConfigSwapRAndB(srcConfig);
1161 swapRAndB = true;
1162 }
1163
bsalomonf2703d82014-10-28 14:33:06 -07001164 GrSurfaceDesc desc;
bsalomon81beccc2014-10-13 12:32:55 -07001165 desc.fWidth = width;
1166 desc.fHeight = height;
1167 desc.fConfig = writeConfig;
bsalomone3059732014-10-14 11:47:22 -07001168 SkAutoTUnref<GrTexture> texture(this->refScratchTexture(desc, kApprox_ScratchTexMatch));
1169 if (!texture) {
bsalomon81beccc2014-10-13 12:32:55 -07001170 return false;
1171 }
1172
1173 SkAutoTUnref<const GrFragmentProcessor> fp;
1174 SkMatrix textureMatrix;
1175 textureMatrix.setIDiv(texture->width(), texture->height());
1176
1177 // allocate a tmp buffer and sw convert the pixels to premul
1178 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
1179
1180 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) {
1181 if (!GrPixelConfigIs8888(srcConfig)) {
1182 return false;
1183 }
1184 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix));
1185 // handle the unpremul step on the CPU if we couldn't create an effect to do it.
1186 if (NULL == fp) {
1187 size_t tmpRowBytes = 4 * width;
1188 tmpPixels.reset(width * height);
1189 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
1190 tmpPixels.get())) {
1191 return false;
1192 }
1193 rowBytes = tmpRowBytes;
1194 buffer = tmpPixels.get();
1195 }
1196 }
1197 if (NULL == fp) {
1198 fp.reset(GrConfigConversionEffect::Create(texture,
1199 swapRAndB,
1200 GrConfigConversionEffect::kNone_PMConversion,
1201 textureMatrix));
1202 }
1203
1204 // Even if the client told us not to flush, we still flush here. The client may have known that
1205 // writes to the original surface caused no data hazards, but they can't know that the scratch
1206 // we just got is safe.
1207 if (texture->surfacePriv().hasPendingIO()) {
1208 this->flush();
1209 }
1210 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height,
1211 writeConfig, buffer, rowBytes)) {
1212 return false;
1213 }
1214
1215 SkMatrix matrix;
1216 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
1217
1218 // This function can be called in the midst of drawing another object (e.g., when uploading a
1219 // SW-rasterized clip while issuing a draw). So we push the current geometry state before
1220 // drawing a rect to the render target.
1221 // The bracket ensures we pop the stack if we wind up flushing below.
1222 {
joshualitt570d2f82015-02-25 13:19:48 -08001223 GrDrawTarget* drawTarget = this->prepareToDraw();
1224 if (!drawTarget) {
1225 return false;
1226 }
joshualitt9853cce2014-11-17 14:22:48 -08001227 GrDrawTarget::AutoGeometryPush agp(drawTarget);
1228
egdaniel8dd688b2015-01-22 10:16:09 -08001229 GrPipelineBuilder pipelineBuilder;
1230 pipelineBuilder.addColorProcessor(fp);
1231 pipelineBuilder.setRenderTarget(renderTarget);
joshualitt44701df2015-02-23 14:44:57 -08001232 drawTarget->drawSimpleRect(&pipelineBuilder,
1233 GrColor_WHITE,
1234 matrix,
joshualitt8059eb92014-12-29 15:10:07 -08001235 SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)));
bsalomon81beccc2014-10-13 12:32:55 -07001236 }
1237
1238 if (kFlushWrites_PixelOp & pixelOpsFlags) {
1239 this->flushSurfaceWrites(surface);
1240 }
1241
1242 return true;
1243}
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001244
reed@google.com7111d462014-03-25 16:20:24 +00001245// toggles between RGBA and BGRA
1246static SkColorType toggle_colortype32(SkColorType ct) {
1247 if (kRGBA_8888_SkColorType == ct) {
1248 return kBGRA_8888_SkColorType;
1249 } else {
1250 SkASSERT(kBGRA_8888_SkColorType == ct);
1251 return kRGBA_8888_SkColorType;
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001252 }
1253}
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001254
bsalomon@google.com0342a852012-08-20 19:22:38 +00001255bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1256 int left, int top, int width, int height,
bsalomon@google.com9c680582013-02-06 18:17:50 +00001257 GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
bsalomon@google.com0342a852012-08-20 19:22:38 +00001258 uint32_t flags) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001259 RETURN_FALSE_IF_ABANDONED
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001260 ASSERT_OWNED_RESOURCE(target);
bsalomon89c62982014-11-03 12:08:42 -08001261 SkASSERT(target);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001262
bsalomonafbf2d62014-09-30 12:18:44 -07001263 if (!(kDontFlush_PixelOpsFlag & flags) && target->surfacePriv().hasPendingWrite()) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001264 this->flush();
1265 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001266
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001267 // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
bsalomon@google.com0342a852012-08-20 19:22:38 +00001268
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001269 // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down. We'll
1270 // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read.
1271 bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top,
bsalomon@google.com9c680582013-02-06 18:17:50 +00001272 width, height, dstConfig,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001273 rowBytes);
bsalomon@google.com9c680582013-02-06 18:17:50 +00001274 // We ignore the preferred config if it is different than our config unless it is an R/B swap.
1275 // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
1276 // config. Then we will call readPixels on the scratch with the swapped config. The swaps during
1277 // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
1278 // dstConfig.
1279 GrPixelConfig readConfig = dstConfig;
1280 bool swapRAndB = false;
commit-bot@chromium.org5d1d79a2013-05-24 18:52:52 +00001281 if (GrPixelConfigSwapRAndB(dstConfig) ==
1282 fGpu->preferredReadPixelsConfig(dstConfig, target->config())) {
bsalomon@google.com9c680582013-02-06 18:17:50 +00001283 readConfig = GrPixelConfigSwapRAndB(readConfig);
1284 swapRAndB = true;
1285 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001286
bsalomon@google.com0342a852012-08-20 19:22:38 +00001287 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001288
bsalomon@google.com9c680582013-02-06 18:17:50 +00001289 if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001290 // The unpremul flag is only allowed for these two configs.
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001291 return false;
1292 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001293
bsalomon191bcc02014-11-14 11:31:13 -08001294 SkAutoTUnref<GrTexture> tempTexture;
1295
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001296 // If the src is a texture and we would have to do conversions after read pixels, we instead
1297 // do the conversions by drawing the src to a scratch texture. If we handle any of the
1298 // conversions in the draw we set the corresponding bool to false so that we don't reapply it
1299 // on the read back pixels.
1300 GrTexture* src = target->asTexture();
bsalomon49f085d2014-09-05 13:34:00 -07001301 if (src && (swapRAndB || unpremul || flipY)) {
bsalomon81beccc2014-10-13 12:32:55 -07001302 // Make the scratch a render so we can read its pixels.
bsalomonf2703d82014-10-28 14:33:06 -07001303 GrSurfaceDesc desc;
1304 desc.fFlags = kRenderTarget_GrSurfaceFlag;
robertphillips@google.com75b3c962012-06-07 12:08:45 +00001305 desc.fWidth = width;
1306 desc.fHeight = height;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001307 desc.fConfig = readConfig;
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001308 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001309
bsalomon@google.com9c680582013-02-06 18:17:50 +00001310 // 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 +00001311 // match the passed rect. However, if we see many different size rectangles we will trash
1312 // our texture cache and pay the cost of creating and destroying many textures. So, we only
1313 // request an exact match when the caller is reading an entire RT.
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001314 ScratchTexMatch match = kApprox_ScratchTexMatch;
1315 if (0 == left &&
1316 0 == top &&
1317 target->width() == width &&
1318 target->height() == height &&
1319 fGpu->fullReadPixelsIsFasterThanPartial()) {
1320 match = kExact_ScratchTexMatch;
1321 }
bsalomon191bcc02014-11-14 11:31:13 -08001322 tempTexture.reset(this->refScratchTexture(desc, match));
1323 if (tempTexture) {
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001324 // compute a matrix to perform the draw
bsalomon@google.comb9086a02012-11-01 18:02:54 +00001325 SkMatrix textureMatrix;
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001326 textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001327 textureMatrix.postIDiv(src->width(), src->height());
1328
joshualittb0a8a372014-09-23 09:50:21 -07001329 SkAutoTUnref<const GrFragmentProcessor> fp;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001330 if (unpremul) {
joshualittb0a8a372014-09-23 09:50:21 -07001331 fp.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix));
1332 if (fp) {
bsalomon@google.com9c680582013-02-06 18:17:50 +00001333 unpremul = false; // we no longer need to do this on CPU after the read back.
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001334 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001335 }
1336 // If we failed to create a PM->UPM effect and have no other conversions to perform then
1337 // there is no longer any point to using the scratch.
joshualittb0a8a372014-09-23 09:50:21 -07001338 if (fp || flipY || swapRAndB) {
1339 if (!fp) {
1340 fp.reset(GrConfigConversionEffect::Create(
1341 src, swapRAndB, GrConfigConversionEffect::kNone_PMConversion,
1342 textureMatrix));
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001343 }
1344 swapRAndB = false; // we will handle the swap in the draw.
bsalomon@google.comc4364992011-11-07 15:54:49 +00001345
robertphillips@google.com13f181f2013-03-02 12:02:08 +00001346 // We protect the existing geometry here since it may not be
1347 // clear to the caller that a draw operation (i.e., drawSimpleRect)
1348 // can be invoked in this method
joshualitt5c55fef2014-10-31 14:04:35 -07001349 {
joshualitt9853cce2014-11-17 14:22:48 -08001350 GrDrawTarget::AutoGeometryPush agp(fDrawBuffer);
egdaniel8dd688b2015-01-22 10:16:09 -08001351 GrPipelineBuilder pipelineBuilder;
joshualitt5c55fef2014-10-31 14:04:35 -07001352 SkASSERT(fp);
egdaniel8dd688b2015-01-22 10:16:09 -08001353 pipelineBuilder.addColorProcessor(fp);
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001354
egdaniel8dd688b2015-01-22 10:16:09 -08001355 pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget());
joshualitt5c55fef2014-10-31 14:04:35 -07001356 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
joshualitt44701df2015-02-23 14:44:57 -08001357 fDrawBuffer->drawSimpleRect(&pipelineBuilder,
1358 GrColor_WHITE,
1359 SkMatrix::I(),
egdaniel8dd688b2015-01-22 10:16:09 -08001360 rect);
joshualitt5c55fef2014-10-31 14:04:35 -07001361 // we want to read back from the scratch's origin
1362 left = 0;
1363 top = 0;
bsalomon191bcc02014-11-14 11:31:13 -08001364 target = tempTexture->asRenderTarget();
joshualitt5c55fef2014-10-31 14:04:35 -07001365 }
1366 this->flushSurfaceWrites(target);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001367 }
bsalomon@google.com0342a852012-08-20 19:22:38 +00001368 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001369 }
joshualitt5c55fef2014-10-31 14:04:35 -07001370
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001371 if (!fGpu->readPixels(target,
1372 left, top, width, height,
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001373 readConfig, buffer, rowBytes)) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001374 return false;
1375 }
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001376 // Perform any conversions we weren't able to perform using a scratch texture.
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001377 if (unpremul || swapRAndB) {
reed@google.com7111d462014-03-25 16:20:24 +00001378 SkDstPixelInfo dstPI;
jvanverthfa1e8a72014-12-22 08:31:49 -08001379 if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, NULL)) {
reed@google.com7111d462014-03-25 16:20:24 +00001380 return false;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001381 }
reed@google.com7111d462014-03-25 16:20:24 +00001382 dstPI.fAlphaType = kUnpremul_SkAlphaType;
1383 dstPI.fPixels = buffer;
1384 dstPI.fRowBytes = rowBytes;
1385
1386 SkSrcPixelInfo srcPI;
1387 srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : dstPI.fColorType;
1388 srcPI.fAlphaType = kPremul_SkAlphaType;
1389 srcPI.fPixels = buffer;
1390 srcPI.fRowBytes = rowBytes;
1391
1392 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001393 }
1394 return true;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001395}
1396
bsalomon87a94eb2014-11-03 14:28:32 -08001397void GrContext::prepareSurfaceForExternalRead(GrSurface* surface) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001398 RETURN_IF_ABANDONED
bsalomon87a94eb2014-11-03 14:28:32 -08001399 SkASSERT(surface);
1400 ASSERT_OWNED_RESOURCE(surface);
1401 if (surface->surfacePriv().hasPendingIO()) {
1402 this->flush();
1403 }
1404 GrRenderTarget* rt = surface->asRenderTarget();
1405 if (fGpu && rt) {
1406 fGpu->resolveRenderTarget(rt);
bsalomon41ebbdd2014-08-04 08:31:39 -07001407 }
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001408}
1409
bsalomon41ebbdd2014-08-04 08:31:39 -07001410void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001411 RETURN_IF_ABANDONED
bsalomon41ebbdd2014-08-04 08:31:39 -07001412 SkASSERT(renderTarget);
1413 ASSERT_OWNED_RESOURCE(renderTarget);
bsalomonf21dab92014-11-13 13:33:28 -08001414 AutoCheckFlush acf(this);
joshualitt570d2f82015-02-25 13:19:48 -08001415 GrDrawTarget* target = this->prepareToDraw();
bsalomon41ebbdd2014-08-04 08:31:39 -07001416 if (NULL == target) {
1417 return;
1418 }
1419 target->discard(renderTarget);
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001420}
1421
bsalomonf80bfed2014-10-07 05:56:02 -07001422void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
1423 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001424 RETURN_IF_ABANDONED
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001425 if (NULL == src || NULL == dst) {
1426 return;
1427 }
bsalomone3d4bf22014-09-23 09:15:03 -07001428 ASSERT_OWNED_RESOURCE(src);
junov2bb52102014-09-29 10:18:59 -07001429 ASSERT_OWNED_RESOURCE(dst);
Brian Salomon34a98952014-09-24 11:41:24 -04001430
bsalomonf80bfed2014-10-07 05:56:02 -07001431 // Since we're going to the draw target and not GPU, no need to check kNoFlush
1432 // here.
junov96c118e2014-09-26 13:09:47 -07001433
joshualitt570d2f82015-02-25 13:19:48 -08001434 GrDrawTarget* target = this->prepareToDraw();
junov96c118e2014-09-26 13:09:47 -07001435 if (NULL == target) {
1436 return;
1437 }
junov96c118e2014-09-26 13:09:47 -07001438 target->copySurface(dst, src, srcRect, dstPoint);
bsalomonf80bfed2014-10-07 05:56:02 -07001439
1440 if (kFlushWrites_PixelOp & pixelOpsFlags) {
1441 this->flush();
1442 }
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001443}
1444
bsalomonf80bfed2014-10-07 05:56:02 -07001445void GrContext::flushSurfaceWrites(GrSurface* surface) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001446 RETURN_IF_ABANDONED
bsalomonf80bfed2014-10-07 05:56:02 -07001447 if (surface->surfacePriv().hasPendingWrite()) {
1448 this->flush();
1449 }
1450}
1451
egdaniel8dd688b2015-01-22 10:16:09 -08001452GrDrawTarget* GrContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder,
joshualitt25d9c152015-02-18 12:29:52 -08001453 GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -08001454 const GrClip& clip,
joshualitt9853cce2014-11-17 14:22:48 -08001455 const GrPaint* paint,
1456 const AutoCheckFlush* acf) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001457 if (NULL == fGpu || NULL == fDrawBuffer) {
bsalomon41ebbdd2014-08-04 08:31:39 -07001458 return NULL;
1459 }
1460
joshualitt570d2f82015-02-25 13:19:48 -08001461 ASSERT_OWNED_RESOURCE(rt);
1462 SkASSERT(rt && paint && acf);
1463 pipelineBuilder->setFromPaint(*paint, rt, clip);
1464 return fDrawBuffer;
1465}
1466
1467GrDrawTarget* GrContext::prepareToDraw() {
1468 if (NULL == fGpu) {
1469 return NULL;
bsalomon@google.com07ea2db2012-08-17 14:06:49 +00001470 }
joshualitt5c55fef2014-10-31 14:04:35 -07001471 return fDrawBuffer;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001472}
1473
robertphillips@google.com72176b22012-05-23 13:19:12 +00001474/*
1475 * This method finds a path renderer that can draw the specified path on
1476 * the provided target.
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001477 * Due to its expense, the software path renderer has split out so it can
robertphillips@google.com72176b22012-05-23 13:19:12 +00001478 * can be individually allowed/disallowed via the "allowSW" boolean.
1479 */
joshualitt9853cce2014-11-17 14:22:48 -08001480GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -08001481 const GrPipelineBuilder* pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -08001482 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -08001483 const SkPath& path,
sugoi@google.com5f74cf82012-12-17 21:16:45 +00001484 const SkStrokeRec& stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001485 bool allowSW,
1486 GrPathRendererChain::DrawType drawType,
1487 GrPathRendererChain::StencilSupport* stencilSupport) {
1488
bsalomon@google.com30085192011-08-19 15:42:31 +00001489 if (NULL == fPathRendererChain) {
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001490 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
bsalomon@google.com30085192011-08-19 15:42:31 +00001491 }
robertphillips@google.com72176b22012-05-23 13:19:12 +00001492
joshualitt9853cce2014-11-17 14:22:48 -08001493 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target,
egdaniel8dd688b2015-01-22 10:16:09 -08001494 pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -08001495 viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -08001496 path,
sugoi@google.com12b4e272012-12-06 20:13:11 +00001497 stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001498 drawType,
1499 stencilSupport);
robertphillips@google.com72176b22012-05-23 13:19:12 +00001500
1501 if (NULL == pr && allowSW) {
1502 if (NULL == fSoftwarePathRenderer) {
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001503 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
robertphillips@google.com72176b22012-05-23 13:19:12 +00001504 }
robertphillips@google.com72176b22012-05-23 13:19:12 +00001505 pr = fSoftwarePathRenderer;
1506 }
1507
1508 return pr;
bsalomon@google.com30085192011-08-19 15:42:31 +00001509}
1510
bsalomon@google.com27847de2011-02-22 20:59:41 +00001511////////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org6b7938f2013-10-15 14:18:16 +00001512bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const {
1513 return fGpu->caps()->isConfigRenderable(config, withMSAA);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001514}
1515
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +00001516int GrContext::getRecommendedSampleCount(GrPixelConfig config,
1517 SkScalar dpi) const {
1518 if (!this->isConfigRenderable(config, true)) {
1519 return 0;
1520 }
1521 int chosenSampleCount = 0;
1522 if (fGpu->caps()->pathRenderingSupport()) {
1523 if (dpi >= 250.0f) {
1524 chosenSampleCount = 4;
1525 } else {
1526 chosenSampleCount = 16;
1527 }
1528 }
1529 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ?
1530 chosenSampleCount : 0;
1531}
1532
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001533void GrContext::setupDrawBuffer() {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +00001534 SkASSERT(NULL == fDrawBuffer);
1535 SkASSERT(NULL == fDrawBufferVBAllocPool);
1536 SkASSERT(NULL == fDrawBufferIBAllocPool);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001537
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001538 fDrawBufferVBAllocPool =
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001539 SkNEW_ARGS(GrVertexBufferAllocPool, (fGpu, false,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001540 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001541 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS));
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001542 fDrawBufferIBAllocPool =
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001543 SkNEW_ARGS(GrIndexBufferAllocPool, (fGpu, false,
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001544 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001545 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS));
bsalomon@google.com27847de2011-02-22 20:59:41 +00001546
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001547 fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (fGpu,
bsalomon@google.com6e4e6502013-02-25 20:12:45 +00001548 fDrawBufferVBAllocPool,
1549 fDrawBufferIBAllocPool));
bsalomon@google.com27847de2011-02-22 20:59:41 +00001550}
1551
bsalomon@google.com21c10c52013-06-13 17:44:07 +00001552GrDrawTarget* GrContext::getTextTarget() {
joshualitt570d2f82015-02-25 13:19:48 -08001553 return this->prepareToDraw();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001554}
1555
1556const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1557 return fGpu->getQuadIndexBuffer();
1558}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001559
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001560namespace {
1561void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
1562 GrConfigConversionEffect::PMConversion pmToUPM;
1563 GrConfigConversionEffect::PMConversion upmToPM;
1564 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
1565 *pmToUPMValue = pmToUPM;
1566 *upmToPMValue = upmToPM;
1567}
1568}
1569
joshualittb0a8a372014-09-23 09:50:21 -07001570const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
1571 bool swapRAndB,
1572 const SkMatrix& matrix) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001573 if (!fDidTestPMConversions) {
1574 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
bsalomon@google.comd0f3f682012-08-28 13:08:14 +00001575 fDidTestPMConversions = true;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001576 }
1577 GrConfigConversionEffect::PMConversion pmToUPM =
1578 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
1579 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001580 return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001581 } else {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001582 return NULL;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001583 }
1584}
1585
joshualittb0a8a372014-09-23 09:50:21 -07001586const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
1587 bool swapRAndB,
1588 const SkMatrix& matrix) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001589 if (!fDidTestPMConversions) {
1590 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
bsalomon@google.comd0f3f682012-08-28 13:08:14 +00001591 fDidTestPMConversions = true;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001592 }
1593 GrConfigConversionEffect::PMConversion upmToPM =
1594 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
1595 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001596 return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001597 } else {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001598 return NULL;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001599 }
1600}
1601
bsalomon37f9a262015-02-02 13:00:10 -08001602//////////////////////////////////////////////////////////////////////////////
1603
1604void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
1605 if (maxTextures) {
bsalomon0ea80f42015-02-11 10:49:59 -08001606 *maxTextures = fResourceCache->getMaxResourceCount();
bsalomon37f9a262015-02-02 13:00:10 -08001607 }
1608 if (maxTextureBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -08001609 *maxTextureBytes = fResourceCache->getMaxResourceBytes();
bsalomon37f9a262015-02-02 13:00:10 -08001610 }
1611}
1612
1613void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -08001614 fResourceCache->setLimits(maxTextures, maxTextureBytes);
bsalomon37f9a262015-02-02 13:00:10 -08001615}
1616
bsalomonf99e9612015-02-19 08:24:16 -08001617void GrContext::addResourceToCache(const GrUniqueKey& key, GrGpuResource* resource) {
bsalomon37f9a262015-02-02 13:00:10 -08001618 ASSERT_OWNED_RESOURCE(resource);
bsalomonf99e9612015-02-19 08:24:16 -08001619 if (!resource) {
1620 return;
bsalomon37f9a262015-02-02 13:00:10 -08001621 }
bsalomonf99e9612015-02-19 08:24:16 -08001622 resource->resourcePriv().setUniqueKey(key);
bsalomon37f9a262015-02-02 13:00:10 -08001623}
1624
bsalomon8718aaf2015-02-19 07:24:21 -08001625bool GrContext::isResourceInCache(const GrUniqueKey& key) const {
1626 return fResourceCache->hasUniqueKey(key);
commit-bot@chromium.org95a2b0e2014-05-05 19:21:16 +00001627}
1628
bsalomon8718aaf2015-02-19 07:24:21 -08001629GrGpuResource* GrContext::findAndRefCachedResource(const GrUniqueKey& key) {
1630 return fResourceCache->findAndRefUniqueResource(key);
commit-bot@chromium.org95a2b0e2014-05-05 19:21:16 +00001631}
1632
bsalomon37f9a262015-02-02 13:00:10 -08001633//////////////////////////////////////////////////////////////////////////////
1634
egdanielbbcb38d2014-06-19 10:19:29 -07001635void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
1636 fGpu->addGpuTraceMarker(marker);
bsalomon49f085d2014-09-05 13:34:00 -07001637 if (fDrawBuffer) {
egdanielbbcb38d2014-06-19 10:19:29 -07001638 fDrawBuffer->addGpuTraceMarker(marker);
1639 }
1640}
1641
1642void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
1643 fGpu->removeGpuTraceMarker(marker);
bsalomon49f085d2014-09-05 13:34:00 -07001644 if (fDrawBuffer) {
egdanielbbcb38d2014-06-19 10:19:29 -07001645 fDrawBuffer->removeGpuTraceMarker(marker);
1646 }
1647}
1648