blob: b5c8e3e592b21f1d7667d33434316c92a48f5435 [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"
bsalomon453cf402014-11-11 14:15:57 -080018#include "GrGpuResource.h"
bsalomon3582d3e2015-02-13 14:20:05 -080019#include "GrGpuResourcePriv.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000020#include "GrDrawTargetCaps.h"
joshualitt5478d422014-11-14 16:00:38 -080021#include "GrGpu.h"
commit-bot@chromium.orgdcb8ef92014-03-27 11:26:10 +000022#include "GrIndexBuffer.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000023#include "GrInOrderDrawBuffer.h"
robertphillips@google.come930a072014-04-03 00:34:27 +000024#include "GrLayerCache.h"
commit-bot@chromium.org81312832013-03-22 18:34:09 +000025#include "GrOvalRenderer.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000026#include "GrPathRenderer.h"
tomhudson@google.comd22b6e42011-06-24 15:53:40 +000027#include "GrPathUtils.h"
bsalomon6bc1b5f2015-02-23 09:06:38 -080028#include "GrRenderTargetPriv.h"
bsalomon0ea80f42015-02-11 10:49:59 -080029#include "GrResourceCache.h"
robertphillips@google.com72176b22012-05-23 13:19:12 +000030#include "GrSoftwarePathRenderer.h"
kkinnunenc6cb56f2014-06-24 00:12:27 -070031#include "GrStencilAndCoverTextContext.h"
egdanield58a0ba2014-06-11 10:30:05 -070032#include "GrStrokeInfo.h"
bsalomonafbf2d62014-09-30 12:18:44 -070033#include "GrSurfacePriv.h"
joshualittb7133be2015-04-08 09:08:31 -070034#include "GrTextBlobCache.h"
bsalomonafbf2d62014-09-30 12:18:44 -070035#include "GrTexturePriv.h"
egdanielbbcb38d2014-06-19 10:19:29 -070036#include "GrTraceMarker.h"
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +000037#include "GrTracing.h"
egdanield58a0ba2014-06-11 10:30:05 -070038#include "SkDashPathPriv.h"
bsalomon81beccc2014-10-13 12:32:55 -070039#include "SkConfig8888.h"
reed@google.com7111d462014-03-25 16:20:24 +000040#include "SkGr.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000041#include "SkRRect.h"
sugoi@google.com5f74cf82012-12-17 21:16:45 +000042#include "SkStrokeRec.h"
commit-bot@chromium.orgdcb8ef92014-03-27 11:26:10 +000043#include "SkTLazy.h"
commit-bot@chromium.org47841822014-03-27 14:19:17 +000044#include "SkTLS.h"
commit-bot@chromium.org933e65d2014-03-20 20:00:24 +000045#include "SkTraceEvent.h"
bsalomon@google.com27847de2011-02-22 20:59:41 +000046
joshualitt5478d422014-11-14 16:00:38 -080047#include "effects/GrConfigConversionEffect.h"
48#include "effects/GrDashingEffect.h"
49#include "effects/GrSingleTextureEffect.h"
50
bsalomon@google.com60361492012-03-15 17:47:06 +000051static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
bsalomon@google.com27847de2011-02-22 20:59:41 +000052static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
53
bsalomon@google.com1d4edd32012-08-16 18:36:06 +000054static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11;
55static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4;
bsalomon@google.com27847de2011-02-22 20:59:41 +000056
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +000057#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
joshualitt5f5a8d72015-02-25 14:09:45 -080058#define RETURN_IF_ABANDONED if (!fDrawBuffer) { return; }
59#define RETURN_FALSE_IF_ABANDONED if (!fDrawBuffer) { return false; }
60#define RETURN_NULL_IF_ABANDONED if (!fDrawBuffer) { return NULL; }
bsalomon@google.combc4b6542011-11-19 13:56:11 +000061
bsalomonf21dab92014-11-13 13:33:28 -080062class GrContext::AutoCheckFlush {
63public:
64 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
65
66 ~AutoCheckFlush() {
67 if (fContext->fFlushToReduceCacheSize) {
68 fContext->flush();
69 }
70 }
71
72private:
73 GrContext* fContext;
74};
75
krajcevski9c6d4d72014-08-12 07:26:25 -070076GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
77 const Options* opts) {
78 GrContext* context;
79 if (NULL == opts) {
80 context = SkNEW_ARGS(GrContext, (Options()));
81 } else {
82 context = SkNEW_ARGS(GrContext, (*opts));
83 }
84
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000085 if (context->init(backend, backendContext)) {
86 return context;
87 } else {
88 context->unref();
89 return NULL;
bsalomon@google.com27847de2011-02-22 20:59:41 +000090 }
bsalomon@google.com27847de2011-02-22 20:59:41 +000091}
92
krajcevski9c6d4d72014-08-12 07:26:25 -070093GrContext::GrContext(const Options& opts) : fOptions(opts) {
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000094 fGpu = NULL;
95 fPathRendererChain = NULL;
96 fSoftwarePathRenderer = NULL;
bsalomon0ea80f42015-02-11 10:49:59 -080097 fResourceCache = NULL;
joshualitt7c3a2f82015-03-31 13:32:05 -070098 fBatchFontCache = NULL;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +000099 fDrawBuffer = NULL;
100 fDrawBufferVBAllocPool = NULL;
101 fDrawBufferIBAllocPool = NULL;
bsalomonf21dab92014-11-13 13:33:28 -0800102 fFlushToReduceCacheSize = false;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000103 fAARectRenderer = NULL;
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000104 fOvalRenderer = NULL;
robertphillips@google.com44a91dc2013-07-25 15:32:06 +0000105 fMaxTextureSizeOverride = 1 << 20;
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000106}
107
108bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000109 SkASSERT(NULL == fGpu);
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000110
111 fGpu = GrGpu::Create(backend, backendContext, this);
112 if (NULL == fGpu) {
113 return false;
114 }
bsalomon33435572014-11-05 14:47:41 -0800115 this->initCommon();
116 return true;
117}
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000118
bsalomon33435572014-11-05 14:47:41 -0800119void GrContext::initCommon() {
bsalomon0ea80f42015-02-11 10:49:59 -0800120 fResourceCache = SkNEW(GrResourceCache);
121 fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
commit-bot@chromium.org1836d332013-07-16 22:55:03 +0000122
robertphillips4ec84da2014-06-24 13:10:43 -0700123 fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this)));
robertphillips@google.come930a072014-04-03 00:34:27 +0000124
joshualittb44293e2014-10-28 08:12:18 -0700125 fAARectRenderer = SkNEW_ARGS(GrAARectRenderer, (fGpu));
joshualitt5531d512014-12-17 15:50:11 -0800126 fOvalRenderer = SkNEW_ARGS(GrOvalRenderer, (fGpu));
bsalomon@google.com6e4e6502013-02-25 20:12:45 +0000127
128 fDidTestPMConversions = false;
129
130 this->setupDrawBuffer();
joshualitt7c3a2f82015-03-31 13:32:05 -0700131
132 // GrBatchFontCache will eventually replace GrFontCache
joshualitt62db8ba2015-04-09 08:22:37 -0700133 fBatchFontCache = SkNEW_ARGS(GrBatchFontCache, (this));
joshualittb7133be2015-04-08 09:08:31 -0700134
joshualitt0db6dfa2015-04-10 07:01:30 -0700135 fTextBlobCache.reset(SkNEW_ARGS(GrTextBlobCache, (TextBlobCacheOverBudgetCB, this)));
bsalomon@google.comc0af3172012-06-15 14:10:09 +0000136}
137
bsalomon@google.com27847de2011-02-22 20:59:41 +0000138GrContext::~GrContext() {
bsalomon@google.com733c0622013-04-24 17:59:32 +0000139 if (NULL == fGpu) {
140 return;
141 }
142
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000143 this->flush();
robertphillips@google.com5acc0e32012-05-17 12:01:02 +0000144
robertphillips@google.com950b1b02013-10-21 17:37:28 +0000145 for (int i = 0; i < fCleanUpData.count(); ++i) {
146 (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
147 }
148
bsalomon0ea80f42015-02-11 10:49:59 -0800149 SkDELETE(fResourceCache);
joshualitt7c3a2f82015-03-31 13:32:05 -0700150 SkDELETE(fBatchFontCache);
bsalomon33435572014-11-05 14:47:41 -0800151 SkDELETE(fDrawBuffer);
152 SkDELETE(fDrawBufferVBAllocPool);
153 SkDELETE(fDrawBufferIBAllocPool);
bsalomon@google.com30085192011-08-19 15:42:31 +0000154
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000155 fAARectRenderer->unref();
commit-bot@chromium.org81312832013-03-22 18:34:09 +0000156 fOvalRenderer->unref();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000157
bsalomon@google.com205d4602011-04-25 12:43:45 +0000158 fGpu->unref();
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000159 SkSafeUnref(fPathRendererChain);
160 SkSafeUnref(fSoftwarePathRenderer);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000161}
162
bsalomon2354f842014-07-28 13:48:36 -0700163void GrContext::abandonContext() {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000164 // abandon first to so destructors
165 // don't try to free the resources in the API.
bsalomon0ea80f42015-02-11 10:49:59 -0800166 fResourceCache->abandonAll();
bsalomonc8dc1f72014-08-21 13:02:13 -0700167
robertphillipse3371302014-09-17 06:01:06 -0700168 fGpu->contextAbandoned();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000169
bsalomon@google.com30085192011-08-19 15:42:31 +0000170 // a path renderer may be holding onto resources that
171 // are now unusable
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000172 SkSafeSetNull(fPathRendererChain);
173 SkSafeSetNull(fSoftwarePathRenderer);
bsalomon@google.com30085192011-08-19 15:42:31 +0000174
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000175 delete fDrawBuffer;
176 fDrawBuffer = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000177
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000178 delete fDrawBufferVBAllocPool;
179 fDrawBufferVBAllocPool = NULL;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000180
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000181 delete fDrawBufferIBAllocPool;
182 fDrawBufferIBAllocPool = NULL;
183
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000184 fAARectRenderer->reset();
commit-bot@chromium.orgef284a82013-07-11 22:29:29 +0000185 fOvalRenderer->reset();
bsalomon@google.com205d4602011-04-25 12:43:45 +0000186
joshualitt7c3a2f82015-03-31 13:32:05 -0700187 fBatchFontCache->freeAll();
robertphillips@google.come930a072014-04-03 00:34:27 +0000188 fLayerCache->freeAll();
joshualitt26ffc002015-04-16 11:24:04 -0700189 fTextBlobCache->freeAll();
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000190}
191
bsalomon@google.com0a208a12013-06-28 18:57:35 +0000192void GrContext::resetContext(uint32_t state) {
193 fGpu->markContextDirty(state);
bsalomon@google.com8fe72472011-03-30 21:26:44 +0000194}
195
196void GrContext::freeGpuResources() {
197 this->flush();
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000198
bsalomon49f085d2014-09-05 13:34:00 -0700199 if (fDrawBuffer) {
bsalomonc8dc1f72014-08-21 13:02:13 -0700200 fDrawBuffer->purgeResources();
201 }
robertphillips@google.comff175842012-05-14 19:31:39 +0000202
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000203 fAARectRenderer->reset();
commit-bot@chromium.orgef284a82013-07-11 22:29:29 +0000204 fOvalRenderer->reset();
robertphillips@google.comf6747b02012-06-12 00:32:28 +0000205
joshualitt7c3a2f82015-03-31 13:32:05 -0700206 fBatchFontCache->freeAll();
robertphillips@google.come930a072014-04-03 00:34:27 +0000207 fLayerCache->freeAll();
bsalomon@google.com30085192011-08-19 15:42:31 +0000208 // a path renderer may be holding onto resources
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000209 SkSafeSetNull(fPathRendererChain);
210 SkSafeSetNull(fSoftwarePathRenderer);
bsalomon3033b9f2015-04-13 11:09:56 -0700211
212 fResourceCache->purgeAllUnlocked();
bsalomon@google.com27847de2011-02-22 20:59:41 +0000213}
214
commit-bot@chromium.org95c20032014-05-09 14:29:32 +0000215void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
bsalomon71cb0c22014-11-14 12:10:14 -0800216 if (resourceCount) {
bsalomon0ea80f42015-02-11 10:49:59 -0800217 *resourceCount = fResourceCache->getBudgetedResourceCount();
bsalomon71cb0c22014-11-14 12:10:14 -0800218 }
219 if (resourceBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -0800220 *resourceBytes = fResourceCache->getBudgetedResourceBytes();
bsalomon71cb0c22014-11-14 12:10:14 -0800221 }
commit-bot@chromium.orgd8a57af2014-03-19 21:19:16 +0000222}
223
kkinnunenc6cb56f2014-06-24 00:12:27 -0700224GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
joshualitt6e8cd962015-03-20 10:30:14 -0700225 SkGpuDevice* gpuDevice,
kkinnunenc6cb56f2014-06-24 00:12:27 -0700226 const SkDeviceProperties&
227 leakyProperties,
228 bool enableDistanceFieldFonts) {
jvanverthe9c0fc62015-04-29 11:18:05 -0700229 if (fGpu->caps()->shaderCaps()->pathRenderingSupport() && renderTarget->isMultisampled()) {
egdaniel8dc7c3a2015-04-16 11:22:42 -0700230 GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment();
bsalomon6bc1b5f2015-02-23 09:06:38 -0800231 if (sb) {
joshualitt6e8cd962015-03-20 10:30:14 -0700232 return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyProperties);
bsalomon6bc1b5f2015-02-23 09:06:38 -0800233 }
jvanverth8c27a182014-10-14 08:45:50 -0700234 }
235
joshualitt9bd2daf2015-04-17 09:30:06 -0700236 return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDistanceFieldFonts);
kkinnunenc6cb56f2014-06-24 00:12:27 -0700237}
238
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000239////////////////////////////////////////////////////////////////////////////////
bsalomond0423582015-02-06 08:49:24 -0800240enum ScratchTextureFlags {
241 kExact_ScratchTextureFlag = 0x1,
242 kNoPendingIO_ScratchTextureFlag = 0x2,
243 kNoCreate_ScratchTextureFlag = 0x4,
244};
bsalomon@google.comfea37b52011-04-25 15:51:06 +0000245
bsalomond2a6f4e2015-02-04 10:55:54 -0800246bool GrContext::isConfigTexturable(GrPixelConfig config) const {
247 return fGpu->caps()->isConfigTexturable(config);
248}
249
250bool GrContext::npotTextureTileSupport() const {
251 return fGpu->caps()->npotTextureTileSupport();
252}
253
bsalomond0423582015-02-06 08:49:24 -0800254GrTexture* GrContext::createTexture(const GrSurfaceDesc& desc, bool budgeted, const void* srcData,
bsalomon37f9a262015-02-02 13:00:10 -0800255 size_t rowBytes) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800256 RETURN_NULL_IF_ABANDONED
bsalomond0423582015-02-06 08:49:24 -0800257 if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) &&
258 !this->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
bsalomond2a6f4e2015-02-04 10:55:54 -0800259 return NULL;
260 }
bsalomond0423582015-02-06 08:49:24 -0800261 if (!GrPixelConfigIsCompressed(desc.fConfig)) {
262 static const uint32_t kFlags = kExact_ScratchTextureFlag |
263 kNoCreate_ScratchTextureFlag;
264 if (GrTexture* texture = this->internalRefScratchTexture(desc, kFlags)) {
265 if (!srcData || texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
266 srcData, rowBytes)) {
267 if (!budgeted) {
bsalomon3582d3e2015-02-13 14:20:05 -0800268 texture->resourcePriv().makeUnbudgeted();
bsalomond0423582015-02-06 08:49:24 -0800269 }
270 return texture;
271 }
272 texture->unref();
273 }
274 }
275 return fGpu->createTexture(desc, budgeted, srcData, rowBytes);
276}
bsalomond2a6f4e2015-02-04 10:55:54 -0800277
bsalomond0423582015-02-06 08:49:24 -0800278GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& desc, ScratchTexMatch match,
279 bool calledDuringFlush) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800280 RETURN_NULL_IF_ABANDONED
bsalomond0423582015-02-06 08:49:24 -0800281 // Currently we don't recycle compressed textures as scratch.
282 if (GrPixelConfigIsCompressed(desc.fConfig)) {
283 return NULL;
284 } else {
285 uint32_t flags = 0;
286 if (kExact_ScratchTexMatch == match) {
287 flags |= kExact_ScratchTextureFlag;
288 }
289 if (calledDuringFlush) {
290 flags |= kNoPendingIO_ScratchTextureFlag;
291 }
292 return this->internalRefScratchTexture(desc, flags);
293 }
294}
295
296GrTexture* GrContext::internalRefScratchTexture(const GrSurfaceDesc& inDesc, uint32_t flags) {
297 SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig));
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000298
bsalomonf2703d82014-10-28 14:33:06 -0700299 SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc);
robertphillips@google.come4eaea22013-07-19 16:51:46 +0000300
bsalomonf2703d82014-10-28 14:33:06 -0700301 if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
bsalomond0423582015-02-06 08:49:24 -0800302 if (!(kExact_ScratchTextureFlag & flags)) {
bsalomonbcf0a522014-10-08 08:40:09 -0700303 // bin by pow2 with a reasonable min
304 static const int MIN_SIZE = 16;
bsalomonf2703d82014-10-28 14:33:06 -0700305 GrSurfaceDesc* wdesc = desc.writable();
bsalomonbcf0a522014-10-08 08:40:09 -0700306 wdesc->fWidth = SkTMax(MIN_SIZE, GrNextPow2(desc->fWidth));
307 wdesc->fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc->fHeight));
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000308 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000309
bsalomon6bc1b5f2015-02-23 09:06:38 -0800310 GrScratchKey key;
311 GrTexturePriv::ComputeScratchKey(*desc, &key);
312 uint32_t scratchFlags = 0;
313 if (kNoPendingIO_ScratchTextureFlag & flags) {
314 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
315 } else if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
316 // If it is not a render target then it will most likely be populated by
317 // writePixels() which will trigger a flush if the texture has pending IO.
318 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
319 }
320 GrGpuResource* resource = fResourceCache->findAndRefScratchResource(key, scratchFlags);
321 if (resource) {
322 GrSurface* surface = static_cast<GrSurface*>(resource);
323 GrRenderTarget* rt = surface->asRenderTarget();
324 if (rt && fGpu->caps()->discardRenderTargetSupport()) {
325 rt->discard();
bsalomon000f8292014-10-15 19:04:14 -0700326 }
bsalomon6bc1b5f2015-02-23 09:06:38 -0800327 return surface->asTexture();
328 }
bsalomon@google.comb5b31682011-06-16 18:05:35 +0000329 }
330
bsalomond0423582015-02-06 08:49:24 -0800331 if (!(kNoCreate_ScratchTextureFlag & flags)) {
bsalomon3582d3e2015-02-13 14:20:05 -0800332 return fGpu->createTexture(*desc, true, NULL, 0);
bsalomone167f962015-01-27 09:56:04 -0800333 }
bsalomond0423582015-02-06 08:49:24 -0800334
335 return NULL;
Brian Salomon9323b8b2014-10-07 15:07:38 -0400336}
337
bsalomon71cb0c22014-11-14 12:10:14 -0800338void GrContext::OverBudgetCB(void* data) {
bsalomon66a450f2014-11-13 13:19:10 -0800339 SkASSERT(data);
bsalomonf21dab92014-11-13 13:33:28 -0800340
bsalomon66a450f2014-11-13 13:19:10 -0800341 GrContext* context = reinterpret_cast<GrContext*>(data);
bsalomonf21dab92014-11-13 13:33:28 -0800342
343 // Flush the InOrderDrawBuffer to possibly free up some textures
344 context->fFlushToReduceCacheSize = true;
commit-bot@chromium.orgcae27fe2013-07-10 10:14:35 +0000345}
346
joshualitt0db6dfa2015-04-10 07:01:30 -0700347void GrContext::TextBlobCacheOverBudgetCB(void* data) {
348 SkASSERT(data);
349
350 // Unlike the GrResourceCache, TextBlobs are drawn at the SkGpuDevice level, therefore they
351 // cannot use fFlushTorReduceCacheSize because it uses AutoCheckFlush. The solution is to move
352 // drawText calls to below the GrContext level, but this is not trivial because they call
353 // drawPath on SkGpuDevice
354 GrContext* context = reinterpret_cast<GrContext*>(data);
355 context->flush();
356}
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
bsalomon@google.com205d4602011-04-25 12:43:45 +0000456////////////////////////////////////////////////////////////////////////////////
457
bsalomonc30aaa02014-08-13 07:15:29 -0700458static inline bool is_irect(const SkRect& r) {
tfarina38406c82014-10-31 07:11:12 -0700459 return SkScalarIsInt(r.fLeft) && SkScalarIsInt(r.fTop) &&
460 SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
bsalomonc30aaa02014-08-13 07:15:29 -0700461}
462
bsalomon@google.com205d4602011-04-25 12:43:45 +0000463static bool apply_aa_to_rect(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -0800464 GrPipelineBuilder* pipelineBuilder,
joshualitt9853cce2014-11-17 14:22:48 -0800465 SkRect* devBoundRect,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000466 const SkRect& rect,
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000467 SkScalar strokeWidth,
joshualitt2e3b3e32014-12-09 13:31:14 -0800468 const SkMatrix& combinedMatrix,
469 GrColor color) {
egdaniel8dd688b2015-01-22 10:16:09 -0800470 if (pipelineBuilder->getRenderTarget()->isMultisampled()) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000471 return false;
472 }
473
robertphillips@google.com4b140b52013-05-02 17:13:13 +0000474#if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000475 if (strokeWidth >= 0) {
476#endif
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000477 if (!combinedMatrix.preservesAxisAlignment()) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000478 return false;
479 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000480
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 } else {
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000483 if (!combinedMatrix.preservesRightAngles()) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000484 return false;
485 }
bsalomon@google.com205d4602011-04-25 12:43:45 +0000486 }
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000487#endif
bsalomon@google.com205d4602011-04-25 12:43:45 +0000488
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000489 combinedMatrix.mapRect(devBoundRect, rect);
derekfe638d1c2014-12-02 13:51:29 -0800490 if (!combinedMatrix.rectStaysRect()) {
491 return true;
492 }
493
bsalomonc30aaa02014-08-13 07:15:29 -0700494 if (strokeWidth < 0) {
495 return !is_irect(*devBoundRect);
496 }
robertphillips@google.com28ac96e2013-05-13 13:38:35 +0000497
bsalomon9c0822a2014-08-11 11:07:48 -0700498 return true;
bsalomon@google.com205d4602011-04-25 12:43:45 +0000499}
500
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000501static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
502 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
503 point.fY >= rect.fTop && point.fY <= rect.fBottom;
504}
505
joshualitt0823bfa2015-02-27 10:06:15 -0800506class StrokeRectBatch : public GrBatch {
507public:
508 struct Geometry {
509 GrColor fColor;
510 SkMatrix fViewMatrix;
511 SkRect fRect;
512 SkScalar fStrokeWidth;
513 };
514
515 static GrBatch* Create(const Geometry& geometry) {
516 return SkNEW_ARGS(StrokeRectBatch, (geometry));
517 }
518
mtklein36352bf2015-03-25 18:17:31 -0700519 const char* name() const override { return "StrokeRectBatch"; }
joshualitt0823bfa2015-02-27 10:06:15 -0800520
mtklein36352bf2015-03-25 18:17:31 -0700521 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
joshualitt0823bfa2015-02-27 10:06:15 -0800522 // When this is called on a batch, there is only one geometry bundle
523 out->setKnownFourComponents(fGeoData[0].fColor);
524 }
525
mtklein36352bf2015-03-25 18:17:31 -0700526 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
joshualitt0823bfa2015-02-27 10:06:15 -0800527 out->setKnownSingleComponent(0xff);
528 }
529
mtklein36352bf2015-03-25 18:17:31 -0700530 void initBatchTracker(const GrPipelineInfo& init) override {
joshualitt0823bfa2015-02-27 10:06:15 -0800531 // Handle any color overrides
532 if (init.fColorIgnored) {
533 fGeoData[0].fColor = GrColor_ILLEGAL;
534 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
535 fGeoData[0].fColor = init.fOverrideColor;
536 }
537
538 // setup batch properties
539 fBatch.fColorIgnored = init.fColorIgnored;
540 fBatch.fColor = fGeoData[0].fColor;
541 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
542 fBatch.fCoverageIgnored = init.fCoverageIgnored;
543 }
544
mtklein36352bf2015-03-25 18:17:31 -0700545 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
joshualitt0823bfa2015-02-27 10:06:15 -0800546 SkAutoTUnref<const GrGeometryProcessor> gp(
547 GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType,
548 this->color(),
549 this->viewMatrix(),
550 SkMatrix::I()));
551
552 batchTarget->initDraw(gp, pipeline);
553
554 // TODO this is hacky, but the only way we have to initialize the GP is to use the
555 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
556 // everywhere we can remove this nastiness
557 GrPipelineInfo init;
558 init.fColorIgnored = fBatch.fColorIgnored;
559 init.fOverrideColor = GrColor_ILLEGAL;
560 init.fCoverageIgnored = fBatch.fCoverageIgnored;
561 init.fUsesLocalCoords = this->usesLocalCoords();
562 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
563
564 size_t vertexStride = gp->getVertexStride();
565
566 SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr));
567
568 Geometry& args = fGeoData[0];
569
570 int vertexCount = kVertsPerHairlineRect;
571 if (args.fStrokeWidth > 0) {
572 vertexCount = kVertsPerStrokeRect;
573 }
574
575 const GrVertexBuffer* vertexBuffer;
576 int firstVertex;
577
578 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
579 vertexCount,
580 &vertexBuffer,
581 &firstVertex);
582
joshualitt4b31de82015-03-05 14:33:41 -0800583 if (!vertices) {
584 SkDebugf("Could not allocate vertices\n");
585 return;
586 }
587
joshualitt0823bfa2015-02-27 10:06:15 -0800588 SkPoint* vertex = reinterpret_cast<SkPoint*>(vertices);
589
590 GrPrimitiveType primType;
591
592 if (args.fStrokeWidth > 0) {;
593 primType = kTriangleStrip_GrPrimitiveType;
594 args.fRect.sort();
595 this->setStrokeRectStrip(vertex, args.fRect, args.fStrokeWidth);
596 } else {
597 // hairline
598 primType = kLineStrip_GrPrimitiveType;
599 vertex[0].set(args.fRect.fLeft, args.fRect.fTop);
600 vertex[1].set(args.fRect.fRight, args.fRect.fTop);
601 vertex[2].set(args.fRect.fRight, args.fRect.fBottom);
602 vertex[3].set(args.fRect.fLeft, args.fRect.fBottom);
603 vertex[4].set(args.fRect.fLeft, args.fRect.fTop);
604 }
605
606 GrDrawTarget::DrawInfo drawInfo;
607 drawInfo.setPrimitiveType(primType);
608 drawInfo.setVertexBuffer(vertexBuffer);
609 drawInfo.setStartVertex(firstVertex);
610 drawInfo.setVertexCount(vertexCount);
611 drawInfo.setStartIndex(0);
612 drawInfo.setIndexCount(0);
613 drawInfo.setInstanceCount(0);
614 drawInfo.setVerticesPerInstance(0);
615 drawInfo.setIndicesPerInstance(0);
616 batchTarget->draw(drawInfo);
617 }
618
619 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
620
621private:
622 StrokeRectBatch(const Geometry& geometry) {
623 this->initClassID<StrokeRectBatch>();
624
625 fBatch.fHairline = geometry.fStrokeWidth == 0;
626
627 fGeoData.push_back(geometry);
628 }
629
630 /* create a triangle strip that strokes the specified rect. There are 8
631 unique vertices, but we repeat the last 2 to close up. Alternatively we
632 could use an indices array, and then only send 8 verts, but not sure that
633 would be faster.
634 */
635 void setStrokeRectStrip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
636 const SkScalar rad = SkScalarHalf(width);
637 // TODO we should be able to enable this assert, but we'd have to filter these draws
638 // this is a bug
639 //SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2);
640
641 verts[0].set(rect.fLeft + rad, rect.fTop + rad);
642 verts[1].set(rect.fLeft - rad, rect.fTop - rad);
643 verts[2].set(rect.fRight - rad, rect.fTop + rad);
644 verts[3].set(rect.fRight + rad, rect.fTop - rad);
645 verts[4].set(rect.fRight - rad, rect.fBottom - rad);
646 verts[5].set(rect.fRight + rad, rect.fBottom + rad);
647 verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
648 verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
649 verts[8] = verts[0];
650 verts[9] = verts[1];
651 }
652
653
654 GrColor color() const { return fBatch.fColor; }
655 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
656 bool colorIgnored() const { return fBatch.fColorIgnored; }
657 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
658 bool hairline() const { return fBatch.fHairline; }
659
mtklein36352bf2015-03-25 18:17:31 -0700660 bool onCombineIfPossible(GrBatch* t) override {
joshualitt0823bfa2015-02-27 10:06:15 -0800661 // StrokeRectBatch* that = t->cast<StrokeRectBatch>();
662
663 // NonAA stroke rects cannot batch right now
664 // TODO make these batchable
665 return false;
666 }
667
668 struct BatchTracker {
669 GrColor fColor;
670 bool fUsesLocalCoords;
671 bool fColorIgnored;
672 bool fCoverageIgnored;
673 bool fHairline;
674 };
675
676 const static int kVertsPerHairlineRect = 5;
677 const static int kVertsPerStrokeRect = 10;
678
679 BatchTracker fBatch;
680 SkSTArray<1, Geometry, true> fGeoData;
681};
682
joshualitt25d9c152015-02-18 12:29:52 -0800683void GrContext::drawRect(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800684 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800685 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -0800686 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +0000687 const SkRect& rect,
bsalomon01c8da12014-08-04 09:21:30 -0700688 const GrStrokeInfo* strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800689 RETURN_IF_ABANDONED
bsalomon49f085d2014-09-05 13:34:00 -0700690 if (strokeInfo && strokeInfo->isDashed()) {
egdanield58a0ba2014-06-11 10:30:05 -0700691 SkPath path;
692 path.addRect(rect);
joshualitt570d2f82015-02-25 13:19:48 -0800693 this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -0700694 return;
695 }
696
bsalomonf21dab92014-11-13 13:33:28 -0800697 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800698 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800699 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -0700700 if (NULL == target) {
701 return;
702 }
bsalomon@google.com27847de2011-02-22 20:59:41 +0000703
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +0000704 GR_CREATE_TRACE_MARKER("GrContext::drawRect", target);
egdanield58a0ba2014-06-11 10:30:05 -0700705 SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getStrokeRec().getWidth();
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000706
707 // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
708 // cases where the RT is fully inside a stroke.
709 if (width < 0) {
710 SkRect rtRect;
egdaniel8dd688b2015-01-22 10:16:09 -0800711 pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000712 SkRect clipSpaceRTRect = rtRect;
joshualitt570d2f82015-02-25 13:19:48 -0800713 bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
joshualitt44701df2015-02-23 14:44:57 -0800714 if (checkClip) {
joshualitt570d2f82015-02-25 13:19:48 -0800715 clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
716 SkIntToScalar(clip.origin().fY));
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000717 }
718 // Does the clip contain the entire RT?
joshualitt570d2f82015-02-25 13:19:48 -0800719 if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000720 SkMatrix invM;
joshualitt8059eb92014-12-29 15:10:07 -0800721 if (!viewMatrix.invert(&invM)) {
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000722 return;
723 }
724 // Does the rect bound the RT?
725 SkPoint srcSpaceRTQuad[4];
726 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
727 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
728 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
729 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
730 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
731 // Will it blend?
732 GrColor clearColor;
733 if (paint.isOpaqueAndConstantColor(&clearColor)) {
joshualitt25d9c152015-02-18 12:29:52 -0800734 target->clear(NULL, clearColor, true, rt);
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000735 return;
736 }
737 }
738 }
739 }
740
joshualitt2e3b3e32014-12-09 13:31:14 -0800741 GrColor color = paint.getColor();
commit-bot@chromium.org24ab3b02013-08-14 21:56:37 +0000742 SkRect devBoundRect;
egdaniel8dd688b2015-01-22 10:16:09 -0800743 bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isMultisampled();
744 bool doAA = needAA && apply_aa_to_rect(target, &pipelineBuilder, &devBoundRect, rect, width,
joshualitt8059eb92014-12-29 15:10:07 -0800745 viewMatrix, color);
egdanield58a0ba2014-06-11 10:30:05 -0700746
bsalomon@google.com205d4602011-04-25 12:43:45 +0000747 if (doAA) {
bsalomon@google.com205d4602011-04-25 12:43:45 +0000748 if (width >= 0) {
bsalomon395ef052014-11-12 11:35:22 -0800749 const SkStrokeRec& strokeRec = strokeInfo->getStrokeRec();
joshualitt9853cce2014-11-17 14:22:48 -0800750 fAARectRenderer->strokeAARect(target,
egdaniel8dd688b2015-01-22 10:16:09 -0800751 &pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -0800752 color,
joshualitt8059eb92014-12-29 15:10:07 -0800753 viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -0800754 rect,
joshualitt9853cce2014-11-17 14:22:48 -0800755 devBoundRect,
756 strokeRec);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000757 } else {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000758 // filled AA rect
joshualitt8059eb92014-12-29 15:10:07 -0800759 fAARectRenderer->fillAARect(target,
egdaniel8dd688b2015-01-22 10:16:09 -0800760 &pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -0800761 color,
762 viewMatrix,
763 rect,
joshualittd27f73e2014-12-29 07:43:36 -0800764 devBoundRect);
bsalomon@google.com205d4602011-04-25 12:43:45 +0000765 }
766 return;
767 }
768
bsalomon@google.com27847de2011-02-22 20:59:41 +0000769 if (width >= 0) {
joshualitt0823bfa2015-02-27 10:06:15 -0800770 StrokeRectBatch::Geometry geometry;
771 geometry.fViewMatrix = viewMatrix;
772 geometry.fColor = color;
773 geometry.fRect = rect;
774 geometry.fStrokeWidth = width;
bsalomon@google.com26c2d0a2011-05-17 20:15:30 +0000775
joshualitt0823bfa2015-02-27 10:06:15 -0800776 SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry));
bsalomon@google.com27847de2011-02-22 20:59:41 +0000777
joshualitt0823bfa2015-02-27 10:06:15 -0800778 SkRect bounds = rect;
779 SkScalar rad = SkScalarHalf(width);
780 bounds.outset(rad, rad);
781 viewMatrix.mapRect(&bounds);
bsalomond79c5492015-04-27 10:07:04 -0700782 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
783 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
784 // is enabled because it can cause ugly artifacts.
785 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
786 0 == width && !rt->isMultisampled());
joshualitt0823bfa2015-02-27 10:06:15 -0800787 target->drawBatch(&pipelineBuilder, batch, &bounds);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000788 } else {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000789 // filled BW rect
egdaniel8dd688b2015-01-22 10:16:09 -0800790 target->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000791 }
792}
793
joshualitt25d9c152015-02-18 12:29:52 -0800794void GrContext::drawNonAARectToRect(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -0800795 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -0800796 const GrPaint& paint,
joshualitt16b27892014-12-18 07:47:16 -0800797 const SkMatrix& viewMatrix,
798 const SkRect& rectToDraw,
799 const SkRect& localRect,
800 const SkMatrix* localMatrix) {
joshualitt5f5a8d72015-02-25 14:09:45 -0800801 RETURN_IF_ABANDONED
bsalomonf21dab92014-11-13 13:33:28 -0800802 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -0800803 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -0800804 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -0700805 if (NULL == target) {
806 return;
807 }
bsalomon@google.com64386952013-02-08 21:22:44 +0000808
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +0000809 GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target);
810
joshualitt44701df2015-02-23 14:44:57 -0800811 target->drawRect(&pipelineBuilder,
812 paint.getColor(),
813 viewMatrix,
814 rectToDraw,
815 &localRect,
egdaniel8dd688b2015-01-22 10:16:09 -0800816 localMatrix);
bsalomon@google.com27847de2011-02-22 20:59:41 +0000817}
818
joshualitt0823bfa2015-02-27 10:06:15 -0800819static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
820 bool hasColors,
joshualitt56995b52014-12-11 15:44:02 -0800821 int* colorOffset,
822 int* texOffset,
joshualitt8059eb92014-12-29 15:10:07 -0800823 GrColor color,
824 const SkMatrix& viewMatrix) {
robertphillips@google.com42903302013-04-20 12:26:07 +0000825 *texOffset = -1;
826 *colorOffset = -1;
joshualitt5478d422014-11-14 16:00:38 -0800827 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType;
joshualitt0823bfa2015-02-27 10:06:15 -0800828 if (hasLocalCoords && hasColors) {
joshualitt5478d422014-11-14 16:00:38 -0800829 *colorOffset = sizeof(SkPoint);
830 *texOffset = sizeof(SkPoint) + sizeof(GrColor);
831 flags |= GrDefaultGeoProcFactory::kColor_GPType |
832 GrDefaultGeoProcFactory::kLocalCoord_GPType;
joshualitt0823bfa2015-02-27 10:06:15 -0800833 } else if (hasLocalCoords) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000834 *texOffset = sizeof(SkPoint);
joshualitt5478d422014-11-14 16:00:38 -0800835 flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType;
joshualitt0823bfa2015-02-27 10:06:15 -0800836 } else if (hasColors) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000837 *colorOffset = sizeof(SkPoint);
joshualitt5478d422014-11-14 16:00:38 -0800838 flags |= GrDefaultGeoProcFactory::kColor_GPType;
robertphillips@google.com42903302013-04-20 12:26:07 +0000839 }
joshualitt8059eb92014-12-29 15:10:07 -0800840 return GrDefaultGeoProcFactory::Create(flags, color, viewMatrix, SkMatrix::I());
robertphillips@google.com42903302013-04-20 12:26:07 +0000841}
842
joshualitt0823bfa2015-02-27 10:06:15 -0800843class DrawVerticesBatch : public GrBatch {
844public:
845 struct Geometry {
846 GrColor fColor;
847 SkTDArray<SkPoint> fPositions;
848 SkTDArray<uint16_t> fIndices;
849 SkTDArray<GrColor> fColors;
850 SkTDArray<SkPoint> fLocalCoords;
851 };
852
853 static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveType,
854 const SkMatrix& viewMatrix,
855 const SkPoint* positions, int vertexCount,
856 const uint16_t* indices, int indexCount,
857 const GrColor* colors, const SkPoint* localCoords) {
858 return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatrix, positions,
859 vertexCount, indices, indexCount, colors,
860 localCoords));
861 }
862
mtklein36352bf2015-03-25 18:17:31 -0700863 const char* name() const override { return "DrawVerticesBatch"; }
joshualitt0823bfa2015-02-27 10:06:15 -0800864
mtklein36352bf2015-03-25 18:17:31 -0700865 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
joshualitt0823bfa2015-02-27 10:06:15 -0800866 // When this is called on a batch, there is only one geometry bundle
867 if (this->hasColors()) {
868 out->setUnknownFourComponents();
869 } else {
870 out->setKnownFourComponents(fGeoData[0].fColor);
871 }
872 }
873
mtklein36352bf2015-03-25 18:17:31 -0700874 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
joshualittd4c7d552015-02-27 13:00:56 -0800875 out->setKnownSingleComponent(0xff);
joshualitt0823bfa2015-02-27 10:06:15 -0800876 }
877
mtklein36352bf2015-03-25 18:17:31 -0700878 void initBatchTracker(const GrPipelineInfo& init) override {
joshualitt0823bfa2015-02-27 10:06:15 -0800879 // Handle any color overrides
880 if (init.fColorIgnored) {
881 fGeoData[0].fColor = GrColor_ILLEGAL;
882 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
883 fGeoData[0].fColor = init.fOverrideColor;
884 }
885
886 // setup batch properties
887 fBatch.fColorIgnored = init.fColorIgnored;
888 fBatch.fColor = fGeoData[0].fColor;
889 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
890 fBatch.fCoverageIgnored = init.fCoverageIgnored;
891 }
892
mtklein36352bf2015-03-25 18:17:31 -0700893 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
joshualitt0823bfa2015-02-27 10:06:15 -0800894 int colorOffset = -1, texOffset = -1;
895 SkAutoTUnref<const GrGeometryProcessor> gp(
896 set_vertex_attributes(this->hasLocalCoords(), this->hasColors(), &colorOffset,
897 &texOffset, this->color(), this->viewMatrix()));
898
899 batchTarget->initDraw(gp, pipeline);
900
901 // TODO this is hacky, but the only way we have to initialize the GP is to use the
902 // GrPipelineInfo struct so we can generate the correct shader. Once we have GrBatch
903 // everywhere we can remove this nastiness
904 GrPipelineInfo init;
905 init.fColorIgnored = fBatch.fColorIgnored;
906 init.fOverrideColor = GrColor_ILLEGAL;
907 init.fCoverageIgnored = fBatch.fCoverageIgnored;
908 init.fUsesLocalCoords = this->usesLocalCoords();
909 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
910
911 size_t vertexStride = gp->getVertexStride();
912
913 SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? sizeof(SkPoint) : 0)
914 + (this->hasColors() ? sizeof(GrColor) : 0));
915
916 int instanceCount = fGeoData.count();
917
918 const GrVertexBuffer* vertexBuffer;
919 int firstVertex;
920
921 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
922 this->vertexCount(),
923 &vertexBuffer,
924 &firstVertex);
925
joshualitt4b31de82015-03-05 14:33:41 -0800926 if (!vertices) {
927 SkDebugf("Could not allocate vertices\n");
928 return;
929 }
930
joshualitt0823bfa2015-02-27 10:06:15 -0800931 const GrIndexBuffer* indexBuffer;
932 int firstIndex;
933
934 void* indices = NULL;
935 if (this->hasIndices()) {
936 indices = batchTarget->indexPool()->makeSpace(this->indexCount(),
937 &indexBuffer,
938 &firstIndex);
joshualitt4b31de82015-03-05 14:33:41 -0800939
940 if (!indices) {
941 SkDebugf("Could not allocate indices\n");
942 return;
943 }
joshualitt0823bfa2015-02-27 10:06:15 -0800944 }
945
946 int indexOffset = 0;
947 int vertexOffset = 0;
948 for (int i = 0; i < instanceCount; i++) {
949 const Geometry& args = fGeoData[i];
950
951 // TODO we can actually cache this interleaved and then just memcopy
952 if (this->hasIndices()) {
953 for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
954 *((uint16_t*)indices + indexOffset) = args.fIndices[j] + vertexOffset;
955 }
956 }
957
958 for (int j = 0; j < args.fPositions.count(); ++j) {
959 *((SkPoint*)vertices) = args.fPositions[j];
960 if (this->hasColors()) {
961 *(GrColor*)((intptr_t)vertices + colorOffset) = args.fColors[j];
962 }
963 if (this->hasLocalCoords()) {
964 *(SkPoint*)((intptr_t)vertices + texOffset) = args.fLocalCoords[j];
965 }
966 vertices = (void*)((intptr_t)vertices + vertexStride);
967 vertexOffset++;
968 }
969 }
970
971 GrDrawTarget::DrawInfo drawInfo;
972 drawInfo.setPrimitiveType(this->primitiveType());
973 drawInfo.setVertexBuffer(vertexBuffer);
974 drawInfo.setStartVertex(firstVertex);
975 drawInfo.setVertexCount(this->vertexCount());
976 if (this->hasIndices()) {
977 drawInfo.setIndexBuffer(indexBuffer);
978 drawInfo.setStartIndex(firstIndex);
979 drawInfo.setIndexCount(this->indexCount());
980 } else {
981 drawInfo.setStartIndex(0);
982 drawInfo.setIndexCount(0);
983 }
984 batchTarget->draw(drawInfo);
985 }
986
987 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
988
989private:
990 DrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
991 const SkMatrix& viewMatrix,
992 const SkPoint* positions, int vertexCount,
993 const uint16_t* indices, int indexCount,
994 const GrColor* colors, const SkPoint* localCoords) {
995 this->initClassID<DrawVerticesBatch>();
996 SkASSERT(positions);
997
998 fBatch.fViewMatrix = viewMatrix;
999 Geometry& installedGeo = fGeoData.push_back(geometry);
1000
1001 installedGeo.fPositions.append(vertexCount, positions);
1002 if (indices) {
1003 installedGeo.fIndices.append(indexCount, indices);
1004 fBatch.fHasIndices = true;
1005 } else {
1006 fBatch.fHasIndices = false;
1007 }
1008
1009 if (colors) {
1010 installedGeo.fColors.append(vertexCount, colors);
1011 fBatch.fHasColors = true;
1012 } else {
1013 fBatch.fHasColors = false;
1014 }
1015
1016 if (localCoords) {
1017 installedGeo.fLocalCoords.append(vertexCount, localCoords);
1018 fBatch.fHasLocalCoords = true;
1019 } else {
1020 fBatch.fHasLocalCoords = false;
1021 }
1022 fBatch.fVertexCount = vertexCount;
1023 fBatch.fIndexCount = indexCount;
1024 fBatch.fPrimitiveType = primitiveType;
1025 }
1026
1027 GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; }
1028 bool batchablePrimitiveType() const {
1029 return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType ||
1030 kLines_GrPrimitiveType == fBatch.fPrimitiveType ||
1031 kPoints_GrPrimitiveType == fBatch.fPrimitiveType;
1032 }
1033 GrColor color() const { return fBatch.fColor; }
1034 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1035 bool colorIgnored() const { return fBatch.fColorIgnored; }
1036 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
1037 bool hasColors() const { return fBatch.fHasColors; }
1038 bool hasIndices() const { return fBatch.fHasIndices; }
1039 bool hasLocalCoords() const { return fBatch.fHasLocalCoords; }
1040 int vertexCount() const { return fBatch.fVertexCount; }
1041 int indexCount() const { return fBatch.fIndexCount; }
1042
mtklein36352bf2015-03-25 18:17:31 -07001043 bool onCombineIfPossible(GrBatch* t) override {
joshualitt0823bfa2015-02-27 10:06:15 -08001044 DrawVerticesBatch* that = t->cast<DrawVerticesBatch>();
1045
1046 if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
1047 return false;
1048 }
1049
1050 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1051
1052 // We currently use a uniform viewmatrix for this batch
1053 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1054 return false;
1055 }
1056
1057 if (this->hasColors() != that->hasColors()) {
1058 return false;
1059 }
1060
1061 if (this->hasIndices() != that->hasIndices()) {
1062 return false;
1063 }
1064
1065 if (this->hasLocalCoords() != that->hasLocalCoords()) {
1066 return false;
1067 }
1068
1069 if (!this->hasColors() && this->color() != that->color()) {
1070 return false;
1071 }
1072
1073 if (this->color() != that->color()) {
1074 fBatch.fColor = GrColor_ILLEGAL;
1075 }
1076 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
1077 fBatch.fVertexCount += that->vertexCount();
1078 fBatch.fIndexCount += that->indexCount();
1079 return true;
1080 }
1081
1082 struct BatchTracker {
1083 GrPrimitiveType fPrimitiveType;
1084 SkMatrix fViewMatrix;
1085 GrColor fColor;
1086 bool fUsesLocalCoords;
1087 bool fColorIgnored;
1088 bool fCoverageIgnored;
1089 bool fHasColors;
1090 bool fHasIndices;
1091 bool fHasLocalCoords;
1092 int fVertexCount;
1093 int fIndexCount;
1094 };
1095
1096 BatchTracker fBatch;
1097 SkSTArray<1, Geometry, true> fGeoData;
1098};
1099
joshualitt25d9c152015-02-18 12:29:52 -08001100void GrContext::drawVertices(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -08001101 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -08001102 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -08001103 const SkMatrix& viewMatrix,
bsalomon@google.com27847de2011-02-22 20:59:41 +00001104 GrPrimitiveType primitiveType,
1105 int vertexCount,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +00001106 const SkPoint positions[],
1107 const SkPoint texCoords[],
bsalomon@google.com27847de2011-02-22 20:59:41 +00001108 const GrColor colors[],
1109 const uint16_t indices[],
1110 int indexCount) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001111 RETURN_IF_ABANDONED
bsalomonf21dab92014-11-13 13:33:28 -08001112 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -08001113 GrPipelineBuilder pipelineBuilder;
commit-bot@chromium.org5a567932014-01-08 21:26:09 +00001114
joshualitt570d2f82015-02-25 13:19:48 -08001115 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -07001116 if (NULL == target) {
1117 return;
1118 }
bsalomon@google.com27847de2011-02-22 20:59:41 +00001119
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +00001120 GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target);
1121
joshualitt0823bfa2015-02-27 10:06:15 -08001122 DrawVerticesBatch::Geometry geometry;
1123 geometry.fColor = paint.getColor();
jvanverth@google.com9b855c72013-03-01 18:21:22 +00001124
joshualitt0823bfa2015-02-27 10:06:15 -08001125 SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
1126 positions, vertexCount, indices,
1127 indexCount,colors, texCoords));
bsalomon@google.com27847de2011-02-22 20:59:41 +00001128
joshualitt0823bfa2015-02-27 10:06:15 -08001129 // TODO figure out bounds
1130 target->drawBatch(&pipelineBuilder, batch, NULL);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001131}
1132
bsalomon@google.com06afe7b2011-04-26 15:31:40 +00001133///////////////////////////////////////////////////////////////////////////////
bsalomon@google.com93c96602012-04-27 13:05:21 +00001134
joshualitt25d9c152015-02-18 12:29:52 -08001135void GrContext::drawRRect(GrRenderTarget*rt,
joshualitt570d2f82015-02-25 13:19:48 -08001136 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -08001137 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -08001138 const SkMatrix& viewMatrix,
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001139 const SkRRect& rrect,
egdanield58a0ba2014-06-11 10:30:05 -07001140 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001141 RETURN_IF_ABANDONED
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001142 if (rrect.isEmpty()) {
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +00001143 return;
1144 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001145
egdanield58a0ba2014-06-11 10:30:05 -07001146 if (strokeInfo.isDashed()) {
1147 SkPath path;
1148 path.addRRect(rrect);
joshualitt570d2f82015-02-25 13:19:48 -08001149 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -07001150 return;
1151 }
1152
bsalomonf21dab92014-11-13 13:33:28 -08001153 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -08001154 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -08001155 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -07001156 if (NULL == target) {
1157 return;
1158 }
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001159
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +00001160 GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target);
1161
egdanield58a0ba2014-06-11 10:30:05 -07001162 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1163
joshualitt2e3b3e32014-12-09 13:31:14 -08001164 GrColor color = paint.getColor();
joshualitt44701df2015-02-23 14:44:57 -08001165 if (!fOvalRenderer->drawRRect(target,
1166 &pipelineBuilder,
1167 color,
1168 viewMatrix,
1169 paint.isAntiAlias(),
1170 rrect,
1171 strokeRec)) {
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001172 SkPath path;
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001173 path.addRRect(rrect);
egdaniel8dd688b2015-01-22 10:16:09 -08001174 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1175 path, strokeInfo);
commit-bot@chromium.orgf2bfd542013-04-25 15:27:00 +00001176 }
1177}
1178
1179///////////////////////////////////////////////////////////////////////////////
1180
joshualitt25d9c152015-02-18 12:29:52 -08001181void GrContext::drawDRRect(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -08001182 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -08001183 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -08001184 const SkMatrix& viewMatrix,
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001185 const SkRRect& outer,
1186 const SkRRect& inner) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001187 RETURN_IF_ABANDONED
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001188 if (outer.isEmpty()) {
1189 return;
1190 }
1191
bsalomonf21dab92014-11-13 13:33:28 -08001192 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -08001193 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -08001194 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001195
1196 GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
1197
joshualitt2e3b3e32014-12-09 13:31:14 -08001198 GrColor color = paint.getColor();
joshualitt44701df2015-02-23 14:44:57 -08001199 if (!fOvalRenderer->drawDRRect(target,
1200 &pipelineBuilder,
1201 color,
1202 viewMatrix,
1203 paint.isAntiAlias(),
1204 outer,
1205 inner)) {
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001206 SkPath path;
1207 path.addRRect(inner);
1208 path.addRRect(outer);
1209 path.setFillType(SkPath::kEvenOdd_FillType);
1210
egdanield58a0ba2014-06-11 10:30:05 -07001211 GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
egdaniel8dd688b2015-01-22 10:16:09 -08001212 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1213 path, fillRec);
commit-bot@chromium.org0a09d712014-04-09 21:26:11 +00001214 }
1215}
1216
1217///////////////////////////////////////////////////////////////////////////////
1218
joshualitt570d2f82015-02-25 13:19:48 -08001219void GrContext::drawOval(GrRenderTarget* rt,
1220 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -08001221 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -08001222 const SkMatrix& viewMatrix,
commit-bot@chromium.orgfd03d4a2013-07-17 21:39:42 +00001223 const SkRect& oval,
egdanield58a0ba2014-06-11 10:30:05 -07001224 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001225 RETURN_IF_ABANDONED
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +00001226 if (oval.isEmpty()) {
1227 return;
1228 }
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001229
egdanield58a0ba2014-06-11 10:30:05 -07001230 if (strokeInfo.isDashed()) {
1231 SkPath path;
1232 path.addOval(oval);
joshualitt570d2f82015-02-25 13:19:48 -08001233 this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
egdanield58a0ba2014-06-11 10:30:05 -07001234 return;
1235 }
1236
bsalomonf21dab92014-11-13 13:33:28 -08001237 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -08001238 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -08001239 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -07001240 if (NULL == target) {
1241 return;
1242 }
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001243
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +00001244 GR_CREATE_TRACE_MARKER("GrContext::drawOval", target);
1245
egdanield58a0ba2014-06-11 10:30:05 -07001246 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1247
joshualitt2e3b3e32014-12-09 13:31:14 -08001248 GrColor color = paint.getColor();
joshualitt44701df2015-02-23 14:44:57 -08001249 if (!fOvalRenderer->drawOval(target,
1250 &pipelineBuilder,
1251 color,
1252 viewMatrix,
1253 paint.isAntiAlias(),
1254 oval,
1255 strokeRec)) {
bsalomon@google.com93c96602012-04-27 13:05:21 +00001256 SkPath path;
jvanverth@google.com46d3d392013-01-22 13:34:01 +00001257 path.addOval(oval);
egdaniel8dd688b2015-01-22 10:16:09 -08001258 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1259 path, strokeInfo);
skia.committer@gmail.com98ded842013-01-23 07:06:17 +00001260 }
bsalomon@google.com150d2842012-01-12 20:19:56 +00001261}
bsalomon@google.com27847de2011-02-22 20:59:41 +00001262
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001263// Can 'path' be drawn as a pair of filled nested rectangles?
1264static bool is_nested_rects(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -08001265 GrPipelineBuilder* pipelineBuilder,
joshualitt2e3b3e32014-12-09 13:31:14 -08001266 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -08001267 const SkMatrix& viewMatrix,
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001268 const SkPath& path,
1269 const SkStrokeRec& stroke,
bsalomon9c0822a2014-08-11 11:07:48 -07001270 SkRect rects[2]) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001271 SkASSERT(stroke.isFillStyle());
1272
1273 if (path.isInverseFillType()) {
1274 return false;
1275 }
1276
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001277 // TODO: this restriction could be lifted if we were willing to apply
1278 // the matrix to all the points individually rather than just to the rect
joshualitt8059eb92014-12-29 15:10:07 -08001279 if (!viewMatrix.preservesAxisAlignment()) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001280 return false;
1281 }
1282
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001283 SkPath::Direction dirs[2];
caryclark95bc5f32015-04-08 08:34:15 -07001284 if (!path.isNestedFillRects(rects, dirs)) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001285 return false;
1286 }
1287
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001288 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001289 // The two rects need to be wound opposite to each other
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001290 return false;
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001291 }
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001292
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001293 // Right now, nested rects where the margin is not the same width
1294 // all around do not render correctly
1295 const SkScalar* outer = rects[0].asScalars();
1296 const SkScalar* inner = rects[1].asScalars();
1297
robertphillips183e9852014-10-21 11:25:37 -07001298 bool allEq = true;
1299
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001300 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
robertphillips183e9852014-10-21 11:25:37 -07001301 bool allGoE1 = margin >= SK_Scalar1;
1302
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001303 for (int i = 1; i < 4; ++i) {
1304 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
robertphillips183e9852014-10-21 11:25:37 -07001305 if (temp < SK_Scalar1) {
1306 allGoE1 = false;
1307 }
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001308 if (!SkScalarNearlyEqual(margin, temp)) {
robertphillips183e9852014-10-21 11:25:37 -07001309 allEq = false;
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001310 }
1311 }
1312
robertphillips183e9852014-10-21 11:25:37 -07001313 return allEq || allGoE1;
robertphillips@google.com8d3c6402013-08-20 12:11:31 +00001314}
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001315
joshualitt25d9c152015-02-18 12:29:52 -08001316void GrContext::drawPath(GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -08001317 const GrClip& clip,
joshualitt25d9c152015-02-18 12:29:52 -08001318 const GrPaint& paint,
joshualitt5531d512014-12-17 15:50:11 -08001319 const SkMatrix& viewMatrix,
1320 const SkPath& path,
1321 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001322 RETURN_IF_ABANDONED
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001323 if (path.isEmpty()) {
sugoi@google.com12b4e272012-12-06 20:13:11 +00001324 if (path.isInverseFillType()) {
joshualitt570d2f82015-02-25 13:19:48 -08001325 this->drawPaint(rt, clip, paint, viewMatrix);
bsalomon@google.comfa6ac932011-10-05 19:57:55 +00001326 }
1327 return;
1328 }
1329
joshualitt2e3b3e32014-12-09 13:31:14 -08001330 GrColor color = paint.getColor();
egdanield58a0ba2014-06-11 10:30:05 -07001331
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001332 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
bsalomon@google.comfb4ce6f2012-03-14 13:27:54 +00001333 // Scratch textures can be recycled after they are returned to the texture
1334 // cache. This presents a potential hazard for buffered drawing. However,
1335 // the writePixels that uploads to the scratch will perform a flush so we're
1336 // OK.
bsalomonf21dab92014-11-13 13:33:28 -08001337 AutoCheckFlush acf(this);
egdaniel8dd688b2015-01-22 10:16:09 -08001338 GrPipelineBuilder pipelineBuilder;
joshualitt570d2f82015-02-25 13:19:48 -08001339 GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
bsalomon41ebbdd2014-08-04 08:31:39 -07001340 if (NULL == target) {
1341 return;
1342 }
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001343
egdaniel93a37bc2014-07-21 13:47:57 -07001344 GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isConvex());
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +00001345
kkinnunen18996512015-04-26 23:18:49 -07001346 if (!strokeInfo.isDashed()) {
1347 const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1348 bool useCoverageAA = paint.isAntiAlias() &&
1349 !pipelineBuilder.getRenderTarget()->isMultisampled();
egdanield58a0ba2014-06-11 10:30:05 -07001350
kkinnunen18996512015-04-26 23:18:49 -07001351 if (useCoverageAA && strokeRec.getWidth() < 0 && !path.isConvex()) {
1352 // Concave AA paths are expensive - try to avoid them for special cases
1353 SkRect rects[2];
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001354
kkinnunen18996512015-04-26 23:18:49 -07001355 if (is_nested_rects(target, &pipelineBuilder, color, viewMatrix, path, strokeRec,
1356 rects)) {
1357 fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, color, viewMatrix,
1358 rects);
1359 return;
1360 }
1361 }
1362 SkRect ovalRect;
1363 bool isOval = path.isOval(&ovalRect);
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001364
kkinnunen18996512015-04-26 23:18:49 -07001365 if (isOval && !path.isInverseFillType()) {
1366 if (fOvalRenderer->drawOval(target,
1367 &pipelineBuilder,
1368 color,
1369 viewMatrix,
1370 paint.isAntiAlias(),
1371 ovalRect,
1372 strokeRec)) {
1373 return;
1374 }
robertphillips@google.com83d1a682013-05-17 12:50:27 +00001375 }
1376 }
kkinnunen18996512015-04-26 23:18:49 -07001377 this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1378 path, strokeInfo);
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001379}
1380
joshualitt9853cce2014-11-17 14:22:48 -08001381void GrContext::internalDrawPath(GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -08001382 GrPipelineBuilder* pipelineBuilder,
joshualitt5531d512014-12-17 15:50:11 -08001383 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -08001384 GrColor color,
joshualitt9853cce2014-11-17 14:22:48 -08001385 bool useAA,
1386 const SkPath& path,
egdanield58a0ba2014-06-11 10:30:05 -07001387 const GrStrokeInfo& strokeInfo) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001388 RETURN_IF_ABANDONED
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +00001389 SkASSERT(!path.isEmpty());
commit-bot@chromium.org81312832013-03-22 18:34:09 +00001390
commit-bot@chromium.org2a05de02014-03-25 15:17:32 +00001391 GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target);
1392
1393
bsalomon@google.comd46e2422011-09-23 17:40:07 +00001394 // An Assumption here is that path renderer would use some form of tweaking
1395 // the src color (either the input alpha or in the frag shader) to implement
1396 // aa. If we have some future driver-mojo path AA that can do the right
1397 // thing WRT to the blend then we'll need some query on the PR.
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001398 bool useCoverageAA = useAA &&
egdaniel0bdeec92015-02-23 12:12:54 -08001399 !pipelineBuilder->getRenderTarget()->isMultisampled();
bsalomon@google.com289533a2011-10-27 12:34:25 +00001400
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001401
1402 GrPathRendererChain::DrawType type =
1403 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
joshualitt9853cce2014-11-17 14:22:48 -08001404 GrPathRendererChain::kColor_DrawType;
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001405
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001406 const SkPath* pathPtr = &path;
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +00001407 SkTLazy<SkPath> tmpPath;
kkinnunen18996512015-04-26 23:18:49 -07001408 const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001409
1410 // Try a 1st time without stroking the path and without allowing the SW renderer
egdaniel8dd688b2015-01-22 10:16:09 -08001411 GrPathRenderer* pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
kkinnunen18996512015-04-26 23:18:49 -07001412 *strokeInfoPtr, false, type);
1413
1414 GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
1415 if (NULL == pr && strokeInfo.isDashed()) {
1416 // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
1417 if (strokeInfo.applyDash(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
1418 pathPtr = tmpPath.get();
1419 if (pathPtr->isEmpty()) {
1420 return;
1421 }
1422 strokeInfoPtr = &dashlessStrokeInfo;
1423 }
1424 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
1425 false, type);
1426 }
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001427
robertphillips@google.come79f3202014-02-11 16:30:21 +00001428 if (NULL == pr) {
kkinnunen18996512015-04-26 23:18:49 -07001429 if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, NULL)) {
1430 // It didn't work above, so try again with stroke converted to a fill.
1431 if (!tmpPath.isValid()) {
1432 tmpPath.init();
1433 }
1434 SkStrokeRec* strokeRec = dashlessStrokeInfo.getStrokeRecPtr();
1435 strokeRec->setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
1436 if (strokeRec->applyToPath(tmpPath.get(), *pathPtr)) {
commit-bot@chromium.orgf0c41e22014-01-14 18:42:34 +00001437 pathPtr = tmpPath.get();
commit-bot@chromium.orge0a868c2013-11-22 07:02:11 +00001438 if (pathPtr->isEmpty()) {
1439 return;
1440 }
kkinnunen18996512015-04-26 23:18:49 -07001441 strokeRec->setFillStyle();
1442 strokeInfoPtr = &dashlessStrokeInfo;
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001443 }
1444 }
commit-bot@chromium.org19dd0172013-08-05 13:28:55 +00001445
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001446 // This time, allow SW renderer
kkinnunen18996512015-04-26 23:18:49 -07001447 pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *strokeInfoPtr,
1448 true, type);
robertphillips@google.comeb928ea2013-01-08 13:45:09 +00001449 }
1450
robertphillips@google.come79f3202014-02-11 16:30:21 +00001451 if (NULL == pr) {
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +00001452#ifdef SK_DEBUG
tfarina38406c82014-10-31 07:11:12 -07001453 SkDebugf("Unable to find path renderer compatible with path.\n");
bsalomon@google.com1983f392011-10-10 15:17:58 +00001454#endif
bsalomon@google.com30085192011-08-19 15:42:31 +00001455 return;
1456 }
1457
kkinnunen18996512015-04-26 23:18:49 -07001458 pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *strokeInfoPtr, useCoverageAA);
bsalomon@google.com27847de2011-02-22 20:59:41 +00001459}
bsalomon@google.com8295dc12011-05-02 12:53:34 +00001460
bsalomon@google.com27847de2011-02-22 20:59:41 +00001461////////////////////////////////////////////////////////////////////////////////
1462
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001463void GrContext::flush(int flagsBitfield) {
robertphillips@google.come7db8d62013-07-04 11:48:52 +00001464 if (NULL == fDrawBuffer) {
1465 return;
1466 }
1467
bsalomon@google.coma7f84e12011-03-10 14:13:19 +00001468 if (kDiscard_FlushBit & flagsBitfield) {
1469 fDrawBuffer->reset();
1470 } else {
bsalomon@google.com6e4e6502013-02-25 20:12:45 +00001471 fDrawBuffer->flush();
junov@google.com53a55842011-06-08 22:55:10 +00001472 }
bsalomon3f324322015-04-08 11:01:54 -07001473 fResourceCache->notifyFlushOccurred();
bsalomonf21dab92014-11-13 13:33:28 -08001474 fFlushToReduceCacheSize = false;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001475}
1476
bsalomon81beccc2014-10-13 12:32:55 -07001477bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
1478 const void* inPixels, size_t outRowBytes, void* outPixels) {
1479 SkSrcPixelInfo srcPI;
jvanverthfa1e8a72014-12-22 08:31:49 -08001480 if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL)) {
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001481 return false;
1482 }
bsalomon81beccc2014-10-13 12:32:55 -07001483 srcPI.fAlphaType = kUnpremul_SkAlphaType;
1484 srcPI.fPixels = inPixels;
1485 srcPI.fRowBytes = inRowBytes;
1486
1487 SkDstPixelInfo dstPI;
1488 dstPI.fColorType = srcPI.fColorType;
1489 dstPI.fAlphaType = kPremul_SkAlphaType;
1490 dstPI.fPixels = outPixels;
1491 dstPI.fRowBytes = outRowBytes;
1492
1493 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001494}
1495
bsalomon81beccc2014-10-13 12:32:55 -07001496bool GrContext::writeSurfacePixels(GrSurface* surface,
1497 int left, int top, int width, int height,
1498 GrPixelConfig srcConfig, const void* buffer, size_t rowBytes,
1499 uint32_t pixelOpsFlags) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001500 RETURN_FALSE_IF_ABANDONED
bsalomon81beccc2014-10-13 12:32:55 -07001501 {
1502 GrTexture* texture = NULL;
1503 if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asTexture()) &&
1504 fGpu->canWriteTexturePixels(texture, srcConfig)) {
1505
1506 if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) &&
1507 surface->surfacePriv().hasPendingIO()) {
1508 this->flush();
1509 }
1510 return fGpu->writeTexturePixels(texture, left, top, width, height,
1511 srcConfig, buffer, rowBytes);
1512 // Don't need to check kFlushWrites_PixelOp here, we just did a direct write so the
1513 // upload is already flushed.
1514 }
1515 }
1516
1517 // If we didn't do a direct texture write then we upload the pixels to a texture and draw.
1518 GrRenderTarget* renderTarget = surface->asRenderTarget();
1519 if (NULL == renderTarget) {
1520 return false;
1521 }
1522
1523 // We ignore the preferred config unless it is a R/B swap of the src config. In that case
1524 // we will upload the original src data to a scratch texture but we will spoof it as the swapped
1525 // config. This scratch will then have R and B swapped. We correct for this by swapping again
1526 // when drawing the scratch to the dst using a conversion effect.
1527 bool swapRAndB = false;
1528 GrPixelConfig writeConfig = srcConfig;
1529 if (GrPixelConfigSwapRAndB(srcConfig) ==
1530 fGpu->preferredWritePixelsConfig(srcConfig, renderTarget->config())) {
1531 writeConfig = GrPixelConfigSwapRAndB(srcConfig);
1532 swapRAndB = true;
1533 }
1534
bsalomonf2703d82014-10-28 14:33:06 -07001535 GrSurfaceDesc desc;
bsalomon81beccc2014-10-13 12:32:55 -07001536 desc.fWidth = width;
1537 desc.fHeight = height;
1538 desc.fConfig = writeConfig;
bsalomone3059732014-10-14 11:47:22 -07001539 SkAutoTUnref<GrTexture> texture(this->refScratchTexture(desc, kApprox_ScratchTexMatch));
1540 if (!texture) {
bsalomon81beccc2014-10-13 12:32:55 -07001541 return false;
1542 }
1543
1544 SkAutoTUnref<const GrFragmentProcessor> fp;
1545 SkMatrix textureMatrix;
1546 textureMatrix.setIDiv(texture->width(), texture->height());
1547
1548 // allocate a tmp buffer and sw convert the pixels to premul
1549 SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
1550
1551 if (kUnpremul_PixelOpsFlag & pixelOpsFlags) {
1552 if (!GrPixelConfigIs8888(srcConfig)) {
1553 return false;
1554 }
1555 fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix));
1556 // handle the unpremul step on the CPU if we couldn't create an effect to do it.
1557 if (NULL == fp) {
1558 size_t tmpRowBytes = 4 * width;
1559 tmpPixels.reset(width * height);
1560 if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
1561 tmpPixels.get())) {
1562 return false;
1563 }
1564 rowBytes = tmpRowBytes;
1565 buffer = tmpPixels.get();
1566 }
1567 }
1568 if (NULL == fp) {
1569 fp.reset(GrConfigConversionEffect::Create(texture,
1570 swapRAndB,
1571 GrConfigConversionEffect::kNone_PMConversion,
1572 textureMatrix));
1573 }
1574
1575 // Even if the client told us not to flush, we still flush here. The client may have known that
1576 // writes to the original surface caused no data hazards, but they can't know that the scratch
1577 // we just got is safe.
1578 if (texture->surfacePriv().hasPendingIO()) {
1579 this->flush();
1580 }
1581 if (!fGpu->writeTexturePixels(texture, 0, 0, width, height,
1582 writeConfig, buffer, rowBytes)) {
1583 return false;
1584 }
1585
1586 SkMatrix matrix;
1587 matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
1588
1589 // This function can be called in the midst of drawing another object (e.g., when uploading a
1590 // SW-rasterized clip while issuing a draw). So we push the current geometry state before
1591 // drawing a rect to the render target.
1592 // The bracket ensures we pop the stack if we wind up flushing below.
1593 {
joshualitt570d2f82015-02-25 13:19:48 -08001594 GrDrawTarget* drawTarget = this->prepareToDraw();
1595 if (!drawTarget) {
1596 return false;
1597 }
joshualitt9853cce2014-11-17 14:22:48 -08001598
egdaniel8dd688b2015-01-22 10:16:09 -08001599 GrPipelineBuilder pipelineBuilder;
1600 pipelineBuilder.addColorProcessor(fp);
1601 pipelineBuilder.setRenderTarget(renderTarget);
joshualitt44701df2015-02-23 14:44:57 -08001602 drawTarget->drawSimpleRect(&pipelineBuilder,
1603 GrColor_WHITE,
1604 matrix,
joshualitt8059eb92014-12-29 15:10:07 -08001605 SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)));
bsalomon81beccc2014-10-13 12:32:55 -07001606 }
1607
1608 if (kFlushWrites_PixelOp & pixelOpsFlags) {
1609 this->flushSurfaceWrites(surface);
1610 }
1611
1612 return true;
1613}
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001614
reed@google.com7111d462014-03-25 16:20:24 +00001615// toggles between RGBA and BGRA
1616static SkColorType toggle_colortype32(SkColorType ct) {
1617 if (kRGBA_8888_SkColorType == ct) {
1618 return kBGRA_8888_SkColorType;
1619 } else {
1620 SkASSERT(kBGRA_8888_SkColorType == ct);
1621 return kRGBA_8888_SkColorType;
bsalomon@google.coma91e9232012-02-23 15:39:54 +00001622 }
1623}
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001624
bsalomon@google.com0342a852012-08-20 19:22:38 +00001625bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1626 int left, int top, int width, int height,
bsalomon@google.com9c680582013-02-06 18:17:50 +00001627 GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
bsalomon@google.com0342a852012-08-20 19:22:38 +00001628 uint32_t flags) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001629 RETURN_FALSE_IF_ABANDONED
bsalomon@google.combc4b6542011-11-19 13:56:11 +00001630 ASSERT_OWNED_RESOURCE(target);
bsalomon89c62982014-11-03 12:08:42 -08001631 SkASSERT(target);
bsalomon@google.com669fdc42011-04-05 17:08:27 +00001632
bsalomonafbf2d62014-09-30 12:18:44 -07001633 if (!(kDontFlush_PixelOpsFlag & flags) && target->surfacePriv().hasPendingWrite()) {
bsalomon@google.com6f379512011-11-16 20:36:03 +00001634 this->flush();
1635 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001636
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001637 // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
bsalomon@google.com0342a852012-08-20 19:22:38 +00001638
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001639 // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down. We'll
1640 // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read.
1641 bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top,
bsalomon@google.com9c680582013-02-06 18:17:50 +00001642 width, height, dstConfig,
bsalomon@google.comc4364992011-11-07 15:54:49 +00001643 rowBytes);
bsalomon@google.com9c680582013-02-06 18:17:50 +00001644 // We ignore the preferred config if it is different than our config unless it is an R/B swap.
1645 // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
1646 // config. Then we will call readPixels on the scratch with the swapped config. The swaps during
1647 // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
1648 // dstConfig.
1649 GrPixelConfig readConfig = dstConfig;
1650 bool swapRAndB = false;
commit-bot@chromium.org5d1d79a2013-05-24 18:52:52 +00001651 if (GrPixelConfigSwapRAndB(dstConfig) ==
1652 fGpu->preferredReadPixelsConfig(dstConfig, target->config())) {
bsalomon@google.com9c680582013-02-06 18:17:50 +00001653 readConfig = GrPixelConfigSwapRAndB(readConfig);
1654 swapRAndB = true;
1655 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001656
bsalomon@google.com0342a852012-08-20 19:22:38 +00001657 bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
bsalomon@google.comc4364992011-11-07 15:54:49 +00001658
bsalomon@google.com9c680582013-02-06 18:17:50 +00001659 if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001660 // The unpremul flag is only allowed for these two configs.
bsalomon@google.com0a97be22011-11-08 19:20:57 +00001661 return false;
1662 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001663
bsalomon191bcc02014-11-14 11:31:13 -08001664 SkAutoTUnref<GrTexture> tempTexture;
1665
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001666 // If the src is a texture and we would have to do conversions after read pixels, we instead
1667 // do the conversions by drawing the src to a scratch texture. If we handle any of the
1668 // conversions in the draw we set the corresponding bool to false so that we don't reapply it
1669 // on the read back pixels.
1670 GrTexture* src = target->asTexture();
bsalomon49f085d2014-09-05 13:34:00 -07001671 if (src && (swapRAndB || unpremul || flipY)) {
bsalomon81beccc2014-10-13 12:32:55 -07001672 // Make the scratch a render so we can read its pixels.
bsalomonf2703d82014-10-28 14:33:06 -07001673 GrSurfaceDesc desc;
1674 desc.fFlags = kRenderTarget_GrSurfaceFlag;
robertphillips@google.com75b3c962012-06-07 12:08:45 +00001675 desc.fWidth = width;
1676 desc.fHeight = height;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001677 desc.fConfig = readConfig;
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001678 desc.fOrigin = kTopLeft_GrSurfaceOrigin;
bsalomon@google.comc4ff22a2011-11-10 21:56:21 +00001679
bsalomon@google.com9c680582013-02-06 18:17:50 +00001680 // 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 +00001681 // match the passed rect. However, if we see many different size rectangles we will trash
1682 // our texture cache and pay the cost of creating and destroying many textures. So, we only
1683 // request an exact match when the caller is reading an entire RT.
bsalomon@google.com56d11e02011-11-30 19:59:08 +00001684 ScratchTexMatch match = kApprox_ScratchTexMatch;
1685 if (0 == left &&
1686 0 == top &&
1687 target->width() == width &&
1688 target->height() == height &&
1689 fGpu->fullReadPixelsIsFasterThanPartial()) {
1690 match = kExact_ScratchTexMatch;
1691 }
bsalomon191bcc02014-11-14 11:31:13 -08001692 tempTexture.reset(this->refScratchTexture(desc, match));
1693 if (tempTexture) {
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001694 // compute a matrix to perform the draw
bsalomon@google.comb9086a02012-11-01 18:02:54 +00001695 SkMatrix textureMatrix;
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001696 textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001697 textureMatrix.postIDiv(src->width(), src->height());
1698
joshualittb0a8a372014-09-23 09:50:21 -07001699 SkAutoTUnref<const GrFragmentProcessor> fp;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001700 if (unpremul) {
joshualittb0a8a372014-09-23 09:50:21 -07001701 fp.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix));
1702 if (fp) {
bsalomon@google.com9c680582013-02-06 18:17:50 +00001703 unpremul = false; // we no longer need to do this on CPU after the read back.
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001704 }
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001705 }
1706 // If we failed to create a PM->UPM effect and have no other conversions to perform then
1707 // there is no longer any point to using the scratch.
joshualittb0a8a372014-09-23 09:50:21 -07001708 if (fp || flipY || swapRAndB) {
1709 if (!fp) {
1710 fp.reset(GrConfigConversionEffect::Create(
1711 src, swapRAndB, GrConfigConversionEffect::kNone_PMConversion,
1712 textureMatrix));
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001713 }
1714 swapRAndB = false; // we will handle the swap in the draw.
bsalomon@google.comc4364992011-11-07 15:54:49 +00001715
robertphillips@google.com13f181f2013-03-02 12:02:08 +00001716 // We protect the existing geometry here since it may not be
1717 // clear to the caller that a draw operation (i.e., drawSimpleRect)
1718 // can be invoked in this method
joshualitt5c55fef2014-10-31 14:04:35 -07001719 {
egdaniel8dd688b2015-01-22 10:16:09 -08001720 GrPipelineBuilder pipelineBuilder;
joshualitt5c55fef2014-10-31 14:04:35 -07001721 SkASSERT(fp);
egdaniel8dd688b2015-01-22 10:16:09 -08001722 pipelineBuilder.addColorProcessor(fp);
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001723
egdaniel8dd688b2015-01-22 10:16:09 -08001724 pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget());
joshualitt5c55fef2014-10-31 14:04:35 -07001725 SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
joshualitt44701df2015-02-23 14:44:57 -08001726 fDrawBuffer->drawSimpleRect(&pipelineBuilder,
1727 GrColor_WHITE,
1728 SkMatrix::I(),
egdaniel8dd688b2015-01-22 10:16:09 -08001729 rect);
joshualitt5c55fef2014-10-31 14:04:35 -07001730 // we want to read back from the scratch's origin
1731 left = 0;
1732 top = 0;
bsalomon191bcc02014-11-14 11:31:13 -08001733 target = tempTexture->asRenderTarget();
joshualitt5c55fef2014-10-31 14:04:35 -07001734 }
1735 this->flushSurfaceWrites(target);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001736 }
bsalomon@google.com0342a852012-08-20 19:22:38 +00001737 }
bsalomon@google.comc4364992011-11-07 15:54:49 +00001738 }
joshualitt5c55fef2014-10-31 14:04:35 -07001739
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001740 if (!fGpu->readPixels(target,
1741 left, top, width, height,
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001742 readConfig, buffer, rowBytes)) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001743 return false;
1744 }
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +00001745 // Perform any conversions we weren't able to perform using a scratch texture.
senorblanco@chromium.org3cb406b2013-02-05 19:50:46 +00001746 if (unpremul || swapRAndB) {
reed@google.com7111d462014-03-25 16:20:24 +00001747 SkDstPixelInfo dstPI;
jvanverthfa1e8a72014-12-22 08:31:49 -08001748 if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, NULL)) {
reed@google.com7111d462014-03-25 16:20:24 +00001749 return false;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001750 }
reed@google.com7111d462014-03-25 16:20:24 +00001751 dstPI.fAlphaType = kUnpremul_SkAlphaType;
1752 dstPI.fPixels = buffer;
1753 dstPI.fRowBytes = rowBytes;
1754
1755 SkSrcPixelInfo srcPI;
1756 srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : dstPI.fColorType;
1757 srcPI.fAlphaType = kPremul_SkAlphaType;
1758 srcPI.fPixels = buffer;
1759 srcPI.fRowBytes = rowBytes;
1760
1761 return srcPI.convertPixelsTo(&dstPI, width, height);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001762 }
1763 return true;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001764}
1765
bsalomon87a94eb2014-11-03 14:28:32 -08001766void GrContext::prepareSurfaceForExternalRead(GrSurface* surface) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001767 RETURN_IF_ABANDONED
bsalomon87a94eb2014-11-03 14:28:32 -08001768 SkASSERT(surface);
1769 ASSERT_OWNED_RESOURCE(surface);
1770 if (surface->surfacePriv().hasPendingIO()) {
1771 this->flush();
1772 }
1773 GrRenderTarget* rt = surface->asRenderTarget();
1774 if (fGpu && rt) {
1775 fGpu->resolveRenderTarget(rt);
bsalomon41ebbdd2014-08-04 08:31:39 -07001776 }
bsalomon@google.com75f9f252012-01-31 13:35:56 +00001777}
1778
bsalomon41ebbdd2014-08-04 08:31:39 -07001779void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001780 RETURN_IF_ABANDONED
bsalomon41ebbdd2014-08-04 08:31:39 -07001781 SkASSERT(renderTarget);
1782 ASSERT_OWNED_RESOURCE(renderTarget);
bsalomonf21dab92014-11-13 13:33:28 -08001783 AutoCheckFlush acf(this);
joshualitt570d2f82015-02-25 13:19:48 -08001784 GrDrawTarget* target = this->prepareToDraw();
bsalomon41ebbdd2014-08-04 08:31:39 -07001785 if (NULL == target) {
1786 return;
1787 }
1788 target->discard(renderTarget);
commit-bot@chromium.org28361fa2014-03-28 16:08:05 +00001789}
1790
bsalomonf80bfed2014-10-07 05:56:02 -07001791void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
1792 const SkIPoint& dstPoint, uint32_t pixelOpsFlags) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001793 RETURN_IF_ABANDONED
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001794 if (NULL == src || NULL == dst) {
1795 return;
1796 }
bsalomone3d4bf22014-09-23 09:15:03 -07001797 ASSERT_OWNED_RESOURCE(src);
junov2bb52102014-09-29 10:18:59 -07001798 ASSERT_OWNED_RESOURCE(dst);
Brian Salomon34a98952014-09-24 11:41:24 -04001799
bsalomonf80bfed2014-10-07 05:56:02 -07001800 // Since we're going to the draw target and not GPU, no need to check kNoFlush
1801 // here.
junov96c118e2014-09-26 13:09:47 -07001802
joshualitt570d2f82015-02-25 13:19:48 -08001803 GrDrawTarget* target = this->prepareToDraw();
junov96c118e2014-09-26 13:09:47 -07001804 if (NULL == target) {
1805 return;
1806 }
junov96c118e2014-09-26 13:09:47 -07001807 target->copySurface(dst, src, srcRect, dstPoint);
bsalomonf80bfed2014-10-07 05:56:02 -07001808
1809 if (kFlushWrites_PixelOp & pixelOpsFlags) {
1810 this->flush();
1811 }
senorblanco@chromium.orgef843cd2011-12-02 19:11:17 +00001812}
1813
bsalomonf80bfed2014-10-07 05:56:02 -07001814void GrContext::flushSurfaceWrites(GrSurface* surface) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001815 RETURN_IF_ABANDONED
bsalomonf80bfed2014-10-07 05:56:02 -07001816 if (surface->surfacePriv().hasPendingWrite()) {
1817 this->flush();
1818 }
1819}
1820
egdaniel8dd688b2015-01-22 10:16:09 -08001821GrDrawTarget* GrContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder,
joshualitt25d9c152015-02-18 12:29:52 -08001822 GrRenderTarget* rt,
joshualitt570d2f82015-02-25 13:19:48 -08001823 const GrClip& clip,
joshualitt9853cce2014-11-17 14:22:48 -08001824 const GrPaint* paint,
1825 const AutoCheckFlush* acf) {
joshualitt5f5a8d72015-02-25 14:09:45 -08001826 if (NULL == fGpu || NULL == fDrawBuffer) {
bsalomon41ebbdd2014-08-04 08:31:39 -07001827 return NULL;
1828 }
1829
joshualitt570d2f82015-02-25 13:19:48 -08001830 ASSERT_OWNED_RESOURCE(rt);
1831 SkASSERT(rt && paint && acf);
1832 pipelineBuilder->setFromPaint(*paint, rt, clip);
1833 return fDrawBuffer;
1834}
1835
1836GrDrawTarget* GrContext::prepareToDraw() {
1837 if (NULL == fGpu) {
1838 return NULL;
bsalomon@google.com07ea2db2012-08-17 14:06:49 +00001839 }
joshualitt5c55fef2014-10-31 14:04:35 -07001840 return fDrawBuffer;
bsalomon@google.com27847de2011-02-22 20:59:41 +00001841}
1842
robertphillips@google.com72176b22012-05-23 13:19:12 +00001843/*
1844 * This method finds a path renderer that can draw the specified path on
1845 * the provided target.
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001846 * Due to its expense, the software path renderer has split out so it can
robertphillips@google.com72176b22012-05-23 13:19:12 +00001847 * can be individually allowed/disallowed via the "allowSW" boolean.
1848 */
joshualitt9853cce2014-11-17 14:22:48 -08001849GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
egdaniel8dd688b2015-01-22 10:16:09 -08001850 const GrPipelineBuilder* pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -08001851 const SkMatrix& viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -08001852 const SkPath& path,
kkinnunen18996512015-04-26 23:18:49 -07001853 const GrStrokeInfo& stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001854 bool allowSW,
1855 GrPathRendererChain::DrawType drawType,
1856 GrPathRendererChain::StencilSupport* stencilSupport) {
1857
bsalomon@google.com30085192011-08-19 15:42:31 +00001858 if (NULL == fPathRendererChain) {
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001859 fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
bsalomon@google.com30085192011-08-19 15:42:31 +00001860 }
robertphillips@google.com72176b22012-05-23 13:19:12 +00001861
joshualitt9853cce2014-11-17 14:22:48 -08001862 GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target,
egdaniel8dd688b2015-01-22 10:16:09 -08001863 pipelineBuilder,
joshualitt8059eb92014-12-29 15:10:07 -08001864 viewMatrix,
joshualitt9853cce2014-11-17 14:22:48 -08001865 path,
sugoi@google.com12b4e272012-12-06 20:13:11 +00001866 stroke,
bsalomon@google.com45a15f52012-12-10 19:10:17 +00001867 drawType,
1868 stencilSupport);
robertphillips@google.com72176b22012-05-23 13:19:12 +00001869
1870 if (NULL == pr && allowSW) {
1871 if (NULL == fSoftwarePathRenderer) {
tomhudson@google.comc377baf2012-07-09 20:17:56 +00001872 fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
robertphillips@google.com72176b22012-05-23 13:19:12 +00001873 }
robertphillips@google.com72176b22012-05-23 13:19:12 +00001874 pr = fSoftwarePathRenderer;
1875 }
1876
1877 return pr;
bsalomon@google.com30085192011-08-19 15:42:31 +00001878}
1879
bsalomon@google.com27847de2011-02-22 20:59:41 +00001880////////////////////////////////////////////////////////////////////////////////
commit-bot@chromium.org6b7938f2013-10-15 14:18:16 +00001881bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const {
1882 return fGpu->caps()->isConfigRenderable(config, withMSAA);
robertphillips@google.com99a5ac02012-04-10 19:26:38 +00001883}
1884
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +00001885int GrContext::getRecommendedSampleCount(GrPixelConfig config,
1886 SkScalar dpi) const {
1887 if (!this->isConfigRenderable(config, true)) {
1888 return 0;
1889 }
1890 int chosenSampleCount = 0;
jvanverthe9c0fc62015-04-29 11:18:05 -07001891 if (fGpu->caps()->shaderCaps()->pathRenderingSupport()) {
commit-bot@chromium.orgb471a322014-03-10 07:40:03 +00001892 if (dpi >= 250.0f) {
1893 chosenSampleCount = 4;
1894 } else {
1895 chosenSampleCount = 16;
1896 }
1897 }
1898 return chosenSampleCount <= fGpu->caps()->maxSampleCount() ?
1899 chosenSampleCount : 0;
1900}
1901
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001902void GrContext::setupDrawBuffer() {
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +00001903 SkASSERT(NULL == fDrawBuffer);
1904 SkASSERT(NULL == fDrawBufferVBAllocPool);
1905 SkASSERT(NULL == fDrawBufferIBAllocPool);
bsalomon@google.com8fe72472011-03-30 21:26:44 +00001906
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001907 fDrawBufferVBAllocPool =
bsalomonecb8e3e2015-04-29 04:33:52 -07001908 SkNEW_ARGS(GrVertexBufferAllocPool, (fGpu,
1909 DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1910 DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS));
bsalomon@google.comde6ac2d2011-02-25 21:50:42 +00001911 fDrawBufferIBAllocPool =
bsalomonecb8e3e2015-04-29 04:33:52 -07001912 SkNEW_ARGS(GrIndexBufferAllocPool, (fGpu,
1913 DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1914 DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS));
bsalomon@google.com27847de2011-02-22 20:59:41 +00001915
bsalomona73239a2015-04-28 13:35:17 -07001916 fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (this,
bsalomon@google.com6e4e6502013-02-25 20:12:45 +00001917 fDrawBufferVBAllocPool,
1918 fDrawBufferIBAllocPool));
bsalomon@google.com27847de2011-02-22 20:59:41 +00001919}
1920
bsalomon@google.com21c10c52013-06-13 17:44:07 +00001921GrDrawTarget* GrContext::getTextTarget() {
joshualitt570d2f82015-02-25 13:19:48 -08001922 return this->prepareToDraw();
bsalomon@google.com27847de2011-02-22 20:59:41 +00001923}
1924
1925const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1926 return fGpu->getQuadIndexBuffer();
1927}
bsalomon@google.comdfe75bc2011-03-25 12:31:16 +00001928
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001929namespace {
1930void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
1931 GrConfigConversionEffect::PMConversion pmToUPM;
1932 GrConfigConversionEffect::PMConversion upmToPM;
1933 GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
1934 *pmToUPMValue = pmToUPM;
1935 *upmToPMValue = upmToPM;
1936}
1937}
1938
joshualittb0a8a372014-09-23 09:50:21 -07001939const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
1940 bool swapRAndB,
1941 const SkMatrix& matrix) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001942 if (!fDidTestPMConversions) {
1943 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
bsalomon@google.comd0f3f682012-08-28 13:08:14 +00001944 fDidTestPMConversions = true;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001945 }
1946 GrConfigConversionEffect::PMConversion pmToUPM =
1947 static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
1948 if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001949 return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001950 } else {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001951 return NULL;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001952 }
1953}
1954
joshualittb0a8a372014-09-23 09:50:21 -07001955const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
1956 bool swapRAndB,
1957 const SkMatrix& matrix) {
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001958 if (!fDidTestPMConversions) {
1959 test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
bsalomon@google.comd0f3f682012-08-28 13:08:14 +00001960 fDidTestPMConversions = true;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001961 }
1962 GrConfigConversionEffect::PMConversion upmToPM =
1963 static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
1964 if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001965 return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix);
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001966 } else {
bsalomon@google.comadc65362013-01-28 14:26:09 +00001967 return NULL;
bsalomon@google.coma04e8e82012-08-27 12:53:13 +00001968 }
1969}
1970
bsalomon37f9a262015-02-02 13:00:10 -08001971//////////////////////////////////////////////////////////////////////////////
1972
1973void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
1974 if (maxTextures) {
bsalomon0ea80f42015-02-11 10:49:59 -08001975 *maxTextures = fResourceCache->getMaxResourceCount();
bsalomon37f9a262015-02-02 13:00:10 -08001976 }
1977 if (maxTextureBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -08001978 *maxTextureBytes = fResourceCache->getMaxResourceBytes();
bsalomon37f9a262015-02-02 13:00:10 -08001979 }
1980}
1981
1982void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
bsalomon0ea80f42015-02-11 10:49:59 -08001983 fResourceCache->setLimits(maxTextures, maxTextureBytes);
bsalomon37f9a262015-02-02 13:00:10 -08001984}
1985
bsalomonf99e9612015-02-19 08:24:16 -08001986void GrContext::addResourceToCache(const GrUniqueKey& key, GrGpuResource* resource) {
bsalomon37f9a262015-02-02 13:00:10 -08001987 ASSERT_OWNED_RESOURCE(resource);
bsalomonf99e9612015-02-19 08:24:16 -08001988 if (!resource) {
1989 return;
bsalomon37f9a262015-02-02 13:00:10 -08001990 }
bsalomonf99e9612015-02-19 08:24:16 -08001991 resource->resourcePriv().setUniqueKey(key);
bsalomon37f9a262015-02-02 13:00:10 -08001992}
1993
bsalomon8718aaf2015-02-19 07:24:21 -08001994bool GrContext::isResourceInCache(const GrUniqueKey& key) const {
1995 return fResourceCache->hasUniqueKey(key);
commit-bot@chromium.org95a2b0e2014-05-05 19:21:16 +00001996}
1997
bsalomon8718aaf2015-02-19 07:24:21 -08001998GrGpuResource* GrContext::findAndRefCachedResource(const GrUniqueKey& key) {
1999 return fResourceCache->findAndRefUniqueResource(key);
commit-bot@chromium.org95a2b0e2014-05-05 19:21:16 +00002000}
2001
bsalomon37f9a262015-02-02 13:00:10 -08002002//////////////////////////////////////////////////////////////////////////////
2003
egdanielbbcb38d2014-06-19 10:19:29 -07002004void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
2005 fGpu->addGpuTraceMarker(marker);
bsalomon49f085d2014-09-05 13:34:00 -07002006 if (fDrawBuffer) {
egdanielbbcb38d2014-06-19 10:19:29 -07002007 fDrawBuffer->addGpuTraceMarker(marker);
2008 }
2009}
2010
2011void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
2012 fGpu->removeGpuTraceMarker(marker);
bsalomon49f085d2014-09-05 13:34:00 -07002013 if (fDrawBuffer) {
egdanielbbcb38d2014-06-19 10:19:29 -07002014 fDrawBuffer->removeGpuTraceMarker(marker);
2015 }
2016}
2017