C++11 override should now be supported by all of {bots,Chrome,Android,Mozilla}
[platform/upstream/libSkiaSharp.git] / src / gpu / GrContext.cpp
1
2 /*
3  * 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.
7  */
8
9 #include "GrContext.h"
10
11 #include "GrAARectRenderer.h"
12 #include "GrBatch.h"
13 #include "GrBatchTarget.h"
14 #include "GrBufferAllocPool.h"
15 #include "GrDefaultGeoProcFactory.h"
16 #include "GrFontCache.h"
17 #include "GrGpuResource.h"
18 #include "GrGpuResourcePriv.h"
19 #include "GrDistanceFieldTextContext.h"
20 #include "GrDrawTargetCaps.h"
21 #include "GrGpu.h"
22 #include "GrIndexBuffer.h"
23 #include "GrInOrderDrawBuffer.h"
24 #include "GrLayerCache.h"
25 #include "GrOvalRenderer.h"
26 #include "GrPathRenderer.h"
27 #include "GrPathUtils.h"
28 #include "GrRenderTargetPriv.h"
29 #include "GrResourceCache.h"
30 #include "GrSoftwarePathRenderer.h"
31 #include "GrStencilAndCoverTextContext.h"
32 #include "GrStrokeInfo.h"
33 #include "GrSurfacePriv.h"
34 #include "GrTexturePriv.h"
35 #include "GrTraceMarker.h"
36 #include "GrTracing.h"
37 #include "SkDashPathPriv.h"
38 #include "SkConfig8888.h"
39 #include "SkGr.h"
40 #include "SkRRect.h"
41 #include "SkStrokeRec.h"
42 #include "SkTLazy.h"
43 #include "SkTLS.h"
44 #include "SkTraceEvent.h"
45
46 #include "effects/GrConfigConversionEffect.h"
47 #include "effects/GrDashingEffect.h"
48 #include "effects/GrSingleTextureEffect.h"
49
50 static const size_t DRAW_BUFFER_VBPOOL_BUFFER_SIZE = 1 << 15;
51 static const int DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS = 4;
52
53 static const size_t DRAW_BUFFER_IBPOOL_BUFFER_SIZE = 1 << 11;
54 static const int DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS = 4;
55
56 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this)
57 #define RETURN_IF_ABANDONED if (!fDrawBuffer) { return; }
58 #define RETURN_FALSE_IF_ABANDONED if (!fDrawBuffer) { return false; }
59 #define RETURN_NULL_IF_ABANDONED if (!fDrawBuffer) { return NULL; }
60
61 class GrContext::AutoCheckFlush {
62 public:
63     AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context); }
64
65     ~AutoCheckFlush() {
66         if (fContext->fFlushToReduceCacheSize) {
67             fContext->flush();
68         }
69     }
70
71 private:
72     GrContext* fContext;
73 };
74
75 GrContext* GrContext::Create(GrBackend backend, GrBackendContext backendContext,
76                              const Options* opts) {
77     GrContext* context;
78     if (NULL == opts) {
79         context = SkNEW_ARGS(GrContext, (Options()));
80     } else {
81         context = SkNEW_ARGS(GrContext, (*opts));
82     }
83
84     if (context->init(backend, backendContext)) {
85         return context;
86     } else {
87         context->unref();
88         return NULL;
89     }
90 }
91
92 GrContext::GrContext(const Options& opts) : fOptions(opts) {
93     fGpu = NULL;
94     fPathRendererChain = NULL;
95     fSoftwarePathRenderer = NULL;
96     fResourceCache = NULL;
97     fFontCache = NULL;
98     fDrawBuffer = NULL;
99     fDrawBufferVBAllocPool = NULL;
100     fDrawBufferIBAllocPool = NULL;
101     fFlushToReduceCacheSize = false;
102     fAARectRenderer = NULL;
103     fOvalRenderer = NULL;
104     fMaxTextureSizeOverride = 1 << 20;
105 }
106
107 bool GrContext::init(GrBackend backend, GrBackendContext backendContext) {
108     SkASSERT(NULL == fGpu);
109
110     fGpu = GrGpu::Create(backend, backendContext, this);
111     if (NULL == fGpu) {
112         return false;
113     }
114     this->initCommon();
115     return true;
116 }
117
118 void GrContext::initCommon() {
119     fResourceCache = SkNEW(GrResourceCache);
120     fResourceCache->setOverBudgetCallback(OverBudgetCB, this);
121
122     fFontCache = SkNEW_ARGS(GrFontCache, (fGpu));
123
124     fLayerCache.reset(SkNEW_ARGS(GrLayerCache, (this)));
125
126     fAARectRenderer = SkNEW_ARGS(GrAARectRenderer, (fGpu));
127     fOvalRenderer = SkNEW_ARGS(GrOvalRenderer, (fGpu));
128
129     fDidTestPMConversions = false;
130
131     this->setupDrawBuffer();
132 }
133
134 GrContext::~GrContext() {
135     if (NULL == fGpu) {
136         return;
137     }
138
139     this->flush();
140
141     for (int i = 0; i < fCleanUpData.count(); ++i) {
142         (*fCleanUpData[i].fFunc)(this, fCleanUpData[i].fInfo);
143     }
144
145     SkDELETE(fResourceCache);
146     SkDELETE(fFontCache);
147     SkDELETE(fDrawBuffer);
148     SkDELETE(fDrawBufferVBAllocPool);
149     SkDELETE(fDrawBufferIBAllocPool);
150
151     fAARectRenderer->unref();
152     fOvalRenderer->unref();
153
154     fGpu->unref();
155     SkSafeUnref(fPathRendererChain);
156     SkSafeUnref(fSoftwarePathRenderer);
157 }
158
159 void GrContext::abandonContext() {
160     // abandon first to so destructors
161     // don't try to free the resources in the API.
162     fResourceCache->abandonAll();
163
164     fGpu->contextAbandoned();
165
166     // a path renderer may be holding onto resources that
167     // are now unusable
168     SkSafeSetNull(fPathRendererChain);
169     SkSafeSetNull(fSoftwarePathRenderer);
170
171     delete fDrawBuffer;
172     fDrawBuffer = NULL;
173
174     delete fDrawBufferVBAllocPool;
175     fDrawBufferVBAllocPool = NULL;
176
177     delete fDrawBufferIBAllocPool;
178     fDrawBufferIBAllocPool = NULL;
179
180     fAARectRenderer->reset();
181     fOvalRenderer->reset();
182
183     fFontCache->freeAll();
184     fLayerCache->freeAll();
185 }
186
187 void GrContext::resetContext(uint32_t state) {
188     fGpu->markContextDirty(state);
189 }
190
191 void GrContext::freeGpuResources() {
192     this->flush();
193
194     if (fDrawBuffer) {
195         fDrawBuffer->purgeResources();
196     }
197
198     fAARectRenderer->reset();
199     fOvalRenderer->reset();
200
201     fFontCache->freeAll();
202     fLayerCache->freeAll();
203     // a path renderer may be holding onto resources
204     SkSafeSetNull(fPathRendererChain);
205     SkSafeSetNull(fSoftwarePathRenderer);
206 }
207
208 void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes) const {
209     if (resourceCount) {
210         *resourceCount = fResourceCache->getBudgetedResourceCount();
211     }
212     if (resourceBytes) {
213         *resourceBytes = fResourceCache->getBudgetedResourceBytes();
214     }
215 }
216
217 GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
218                                             SkGpuDevice* gpuDevice,
219                                             const SkDeviceProperties&
220                                             leakyProperties,
221                                             bool enableDistanceFieldFonts) {
222     if (fGpu->caps()->pathRenderingSupport() && renderTarget->isMultisampled()) {
223         GrStencilBuffer* sb = renderTarget->renderTargetPriv().attachStencilBuffer();
224         if (sb) {
225             return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyProperties);
226         }
227     } 
228
229     return GrDistanceFieldTextContext::Create(this, gpuDevice, leakyProperties,
230                                               enableDistanceFieldFonts);
231 }
232
233 ////////////////////////////////////////////////////////////////////////////////
234 enum ScratchTextureFlags {
235     kExact_ScratchTextureFlag           = 0x1,
236     kNoPendingIO_ScratchTextureFlag     = 0x2,
237     kNoCreate_ScratchTextureFlag        = 0x4,
238 };
239
240 bool GrContext::isConfigTexturable(GrPixelConfig config) const {
241     return fGpu->caps()->isConfigTexturable(config);
242 }
243
244 bool GrContext::npotTextureTileSupport() const {
245     return fGpu->caps()->npotTextureTileSupport();
246 }
247
248 GrTexture* GrContext::createTexture(const GrSurfaceDesc& desc, bool budgeted, const void* srcData,
249                                     size_t rowBytes) {
250     RETURN_NULL_IF_ABANDONED
251     if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) &&
252         !this->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
253         return NULL;
254     }
255     if (!GrPixelConfigIsCompressed(desc.fConfig)) {
256         static const uint32_t kFlags = kExact_ScratchTextureFlag |
257                                        kNoCreate_ScratchTextureFlag;
258         if (GrTexture* texture = this->internalRefScratchTexture(desc, kFlags)) {
259             if (!srcData || texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
260                                                  srcData, rowBytes)) {
261                 if (!budgeted) {
262                     texture->resourcePriv().makeUnbudgeted();
263                 }
264                 return texture;
265             }
266             texture->unref();
267         }
268     }
269     return fGpu->createTexture(desc, budgeted, srcData, rowBytes);
270 }
271
272 GrTexture* GrContext::refScratchTexture(const GrSurfaceDesc& desc, ScratchTexMatch match,
273                                         bool calledDuringFlush) {
274     RETURN_NULL_IF_ABANDONED
275     // Currently we don't recycle compressed textures as scratch.
276     if (GrPixelConfigIsCompressed(desc.fConfig)) {
277         return NULL;
278     } else {
279         uint32_t flags = 0;
280         if (kExact_ScratchTexMatch == match) {
281             flags |= kExact_ScratchTextureFlag;
282         }
283         if (calledDuringFlush) {
284             flags |= kNoPendingIO_ScratchTextureFlag;
285         }
286         return this->internalRefScratchTexture(desc, flags);
287     }
288 }
289
290 GrTexture* GrContext::internalRefScratchTexture(const GrSurfaceDesc& inDesc, uint32_t flags) {
291     SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig));
292
293     SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc);
294
295     if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
296         if (!(kExact_ScratchTextureFlag & flags)) {
297             // bin by pow2 with a reasonable min
298             static const int MIN_SIZE = 16;
299             GrSurfaceDesc* wdesc = desc.writable();
300             wdesc->fWidth  = SkTMax(MIN_SIZE, GrNextPow2(desc->fWidth));
301             wdesc->fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc->fHeight));
302         }
303
304         GrScratchKey key;
305         GrTexturePriv::ComputeScratchKey(*desc, &key);
306         uint32_t scratchFlags = 0;
307         if (kNoPendingIO_ScratchTextureFlag & flags) {
308             scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
309         } else  if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
310             // If it is not a render target then it will most likely be populated by
311             // writePixels() which will trigger a flush if the texture has pending IO.
312             scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
313         }
314         GrGpuResource* resource = fResourceCache->findAndRefScratchResource(key, scratchFlags);
315         if (resource) {
316             GrSurface* surface = static_cast<GrSurface*>(resource);
317             GrRenderTarget* rt = surface->asRenderTarget();
318             if (rt && fGpu->caps()->discardRenderTargetSupport()) {
319                 rt->discard();
320             }
321             return surface->asTexture();
322         }
323     }
324
325     if (!(kNoCreate_ScratchTextureFlag & flags)) {
326         return fGpu->createTexture(*desc, true, NULL, 0);
327     }
328
329     return NULL;
330 }
331
332 void GrContext::OverBudgetCB(void* data) {
333     SkASSERT(data);
334
335     GrContext* context = reinterpret_cast<GrContext*>(data);
336
337     // Flush the InOrderDrawBuffer to possibly free up some textures
338     context->fFlushToReduceCacheSize = true;
339 }
340
341 int GrContext::getMaxTextureSize() const {
342     return SkTMin(fGpu->caps()->maxTextureSize(), fMaxTextureSizeOverride);
343 }
344
345 int GrContext::getMaxRenderTargetSize() const {
346     return fGpu->caps()->maxRenderTargetSize();
347 }
348
349 int GrContext::getMaxSampleCount() const {
350     return fGpu->caps()->maxSampleCount();
351 }
352
353 ///////////////////////////////////////////////////////////////////////////////
354
355 GrTexture* GrContext::wrapBackendTexture(const GrBackendTextureDesc& desc) {
356     RETURN_NULL_IF_ABANDONED
357     return fGpu->wrapBackendTexture(desc);
358 }
359
360 GrRenderTarget* GrContext::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
361     RETURN_NULL_IF_ABANDONED
362     return fGpu->wrapBackendRenderTarget(desc);
363 }
364
365 ////////////////////////////////////////////////////////////////////////////////
366
367 void GrContext::clear(const SkIRect* rect,
368                       const GrColor color,
369                       bool canIgnoreRect,
370                       GrRenderTarget* renderTarget) {
371     RETURN_IF_ABANDONED
372     ASSERT_OWNED_RESOURCE(renderTarget);
373     SkASSERT(renderTarget);
374
375     AutoCheckFlush acf(this);
376     GR_CREATE_TRACE_MARKER_CONTEXT("GrContext::clear", this);
377     GrDrawTarget* target = this->prepareToDraw();
378     if (NULL == target) {
379         return;
380     }
381     target->clear(rect, color, canIgnoreRect, renderTarget);
382 }
383
384 void GrContext::drawPaint(GrRenderTarget* rt,
385                           const GrClip& clip,
386                           const GrPaint& origPaint,
387                           const SkMatrix& viewMatrix) {
388     RETURN_IF_ABANDONED
389     // set rect to be big enough to fill the space, but not super-huge, so we
390     // don't overflow fixed-point implementations
391     SkRect r;
392     r.setLTRB(0, 0,
393               SkIntToScalar(rt->width()),
394               SkIntToScalar(rt->height()));
395     SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
396
397     // by definition this fills the entire clip, no need for AA
398     if (paint->isAntiAlias()) {
399         paint.writable()->setAntiAlias(false);
400     }
401
402     bool isPerspective = viewMatrix.hasPerspective();
403
404     // We attempt to map r by the inverse matrix and draw that. mapRect will
405     // map the four corners and bound them with a new rect. This will not
406     // produce a correct result for some perspective matrices.
407     if (!isPerspective) {
408         SkMatrix inverse;
409         if (!viewMatrix.invert(&inverse)) {
410             SkDebugf("Could not invert matrix\n");
411             return;
412         }
413         inverse.mapRect(&r);
414         this->drawRect(rt, clip, *paint, viewMatrix, r);
415     } else {
416         SkMatrix localMatrix;
417         if (!viewMatrix.invert(&localMatrix)) {
418             SkDebugf("Could not invert matrix\n");
419             return;
420         }
421
422         AutoCheckFlush acf(this);
423         GrPipelineBuilder pipelineBuilder;
424         GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, paint, &acf);
425         if (NULL == target) {
426             return;
427         }
428
429         GR_CREATE_TRACE_MARKER("GrContext::drawPaintWithPerspective", target);
430         target->drawRect(&pipelineBuilder,
431                          paint->getColor(),
432                          SkMatrix::I(),
433                          r,
434                          NULL,
435                          &localMatrix);
436     }
437 }
438
439 #ifdef SK_DEVELOPER
440 void GrContext::dumpFontCache() const {
441     fFontCache->dump();
442 }
443 #endif
444
445 ////////////////////////////////////////////////////////////////////////////////
446
447 static inline bool is_irect(const SkRect& r) {
448   return SkScalarIsInt(r.fLeft)  && SkScalarIsInt(r.fTop) &&
449          SkScalarIsInt(r.fRight) && SkScalarIsInt(r.fBottom);
450 }
451
452 static bool apply_aa_to_rect(GrDrawTarget* target,
453                              GrPipelineBuilder* pipelineBuilder,
454                              SkRect* devBoundRect,
455                              const SkRect& rect,
456                              SkScalar strokeWidth,
457                              const SkMatrix& combinedMatrix,
458                              GrColor color) {
459     if (pipelineBuilder->getRenderTarget()->isMultisampled()) {
460         return false;
461     }
462
463 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
464     if (strokeWidth >= 0) {
465 #endif
466         if (!combinedMatrix.preservesAxisAlignment()) {
467             return false;
468         }
469
470 #if defined(SHADER_AA_FILL_RECT) || !defined(IGNORE_ROT_AA_RECT_OPT)
471     } else {
472         if (!combinedMatrix.preservesRightAngles()) {
473             return false;
474         }
475     }
476 #endif
477
478     combinedMatrix.mapRect(devBoundRect, rect);
479     if (!combinedMatrix.rectStaysRect()) {
480         return true;
481     }
482
483     if (strokeWidth < 0) {
484         return !is_irect(*devBoundRect);
485     }
486
487     return true;
488 }
489
490 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
491     return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
492            point.fY >= rect.fTop && point.fY <= rect.fBottom;
493 }
494
495 class StrokeRectBatch : public GrBatch {
496 public:
497     struct Geometry {
498         GrColor fColor;
499         SkMatrix fViewMatrix;
500         SkRect fRect;
501         SkScalar fStrokeWidth;
502     };
503
504     static GrBatch* Create(const Geometry& geometry) {
505         return SkNEW_ARGS(StrokeRectBatch, (geometry));
506     }
507
508     const char* name() const override { return "StrokeRectBatch"; }
509
510     void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
511         // When this is called on a batch, there is only one geometry bundle
512         out->setKnownFourComponents(fGeoData[0].fColor);
513     }
514
515     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
516         out->setKnownSingleComponent(0xff);
517     }
518
519     void initBatchTracker(const GrPipelineInfo& init) override {
520         // Handle any color overrides
521         if (init.fColorIgnored) {
522             fGeoData[0].fColor = GrColor_ILLEGAL;
523         } else if (GrColor_ILLEGAL != init.fOverrideColor) {
524             fGeoData[0].fColor = init.fOverrideColor;
525         }
526
527         // setup batch properties
528         fBatch.fColorIgnored = init.fColorIgnored;
529         fBatch.fColor = fGeoData[0].fColor;
530         fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
531         fBatch.fCoverageIgnored = init.fCoverageIgnored;
532     }
533
534     void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
535         SkAutoTUnref<const GrGeometryProcessor> gp(
536                 GrDefaultGeoProcFactory::Create(GrDefaultGeoProcFactory::kPosition_GPType,
537                                                 this->color(),
538                                                 this->viewMatrix(),
539                                                 SkMatrix::I()));
540
541         batchTarget->initDraw(gp, pipeline);
542
543         // TODO this is hacky, but the only way we have to initialize the GP is to use the
544         // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
545         // everywhere we can remove this nastiness
546         GrPipelineInfo init;
547         init.fColorIgnored = fBatch.fColorIgnored;
548         init.fOverrideColor = GrColor_ILLEGAL;
549         init.fCoverageIgnored = fBatch.fCoverageIgnored;
550         init.fUsesLocalCoords = this->usesLocalCoords();
551         gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
552
553         size_t vertexStride = gp->getVertexStride();
554
555         SkASSERT(vertexStride == sizeof(GrDefaultGeoProcFactory::PositionAttr));
556
557         Geometry& args = fGeoData[0];
558
559         int vertexCount = kVertsPerHairlineRect;
560         if (args.fStrokeWidth > 0) {
561             vertexCount = kVertsPerStrokeRect;
562         }
563
564         const GrVertexBuffer* vertexBuffer;
565         int firstVertex;
566
567         void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
568                                                               vertexCount,
569                                                               &vertexBuffer,
570                                                               &firstVertex);
571
572         if (!vertices) {
573             SkDebugf("Could not allocate vertices\n");
574             return;
575         }
576
577         SkPoint* vertex = reinterpret_cast<SkPoint*>(vertices);
578
579         GrPrimitiveType primType;
580
581         if (args.fStrokeWidth > 0) {;
582             primType = kTriangleStrip_GrPrimitiveType;
583             args.fRect.sort();
584             this->setStrokeRectStrip(vertex, args.fRect, args.fStrokeWidth);
585         } else {
586             // hairline
587             primType = kLineStrip_GrPrimitiveType;
588             vertex[0].set(args.fRect.fLeft, args.fRect.fTop);
589             vertex[1].set(args.fRect.fRight, args.fRect.fTop);
590             vertex[2].set(args.fRect.fRight, args.fRect.fBottom);
591             vertex[3].set(args.fRect.fLeft, args.fRect.fBottom);
592             vertex[4].set(args.fRect.fLeft, args.fRect.fTop);
593         }
594
595         GrDrawTarget::DrawInfo drawInfo;
596         drawInfo.setPrimitiveType(primType);
597         drawInfo.setVertexBuffer(vertexBuffer);
598         drawInfo.setStartVertex(firstVertex);
599         drawInfo.setVertexCount(vertexCount);
600         drawInfo.setStartIndex(0);
601         drawInfo.setIndexCount(0);
602         drawInfo.setInstanceCount(0);
603         drawInfo.setVerticesPerInstance(0);
604         drawInfo.setIndicesPerInstance(0);
605         batchTarget->draw(drawInfo);
606     }
607
608     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
609
610 private:
611     StrokeRectBatch(const Geometry& geometry) {
612         this->initClassID<StrokeRectBatch>();
613
614         fBatch.fHairline = geometry.fStrokeWidth == 0;
615
616         fGeoData.push_back(geometry);
617     }
618
619     /*  create a triangle strip that strokes the specified rect. There are 8
620      unique vertices, but we repeat the last 2 to close up. Alternatively we
621      could use an indices array, and then only send 8 verts, but not sure that
622      would be faster.
623      */
624     void setStrokeRectStrip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
625         const SkScalar rad = SkScalarHalf(width);
626         // TODO we should be able to enable this assert, but we'd have to filter these draws
627         // this is a bug
628         //SkASSERT(rad < rect.width() / 2 && rad < rect.height() / 2);
629
630         verts[0].set(rect.fLeft + rad, rect.fTop + rad);
631         verts[1].set(rect.fLeft - rad, rect.fTop - rad);
632         verts[2].set(rect.fRight - rad, rect.fTop + rad);
633         verts[3].set(rect.fRight + rad, rect.fTop - rad);
634         verts[4].set(rect.fRight - rad, rect.fBottom - rad);
635         verts[5].set(rect.fRight + rad, rect.fBottom + rad);
636         verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
637         verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
638         verts[8] = verts[0];
639         verts[9] = verts[1];
640     }
641
642
643     GrColor color() const { return fBatch.fColor; }
644     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
645     bool colorIgnored() const { return fBatch.fColorIgnored; }
646     const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; }
647     bool hairline() const { return fBatch.fHairline; }
648
649     bool onCombineIfPossible(GrBatch* t) override {
650         // StrokeRectBatch* that = t->cast<StrokeRectBatch>();
651
652         // NonAA stroke rects cannot batch right now
653         // TODO make these batchable
654         return false;
655     }
656
657     struct BatchTracker {
658         GrColor fColor;
659         bool fUsesLocalCoords;
660         bool fColorIgnored;
661         bool fCoverageIgnored;
662         bool fHairline;
663     };
664
665     const static int kVertsPerHairlineRect = 5;
666     const static int kVertsPerStrokeRect = 10;
667
668     BatchTracker fBatch;
669     SkSTArray<1, Geometry, true> fGeoData;
670 };
671
672 void GrContext::drawRect(GrRenderTarget* rt,
673                          const GrClip& clip,
674                          const GrPaint& paint,
675                          const SkMatrix& viewMatrix,
676                          const SkRect& rect,
677                          const GrStrokeInfo* strokeInfo) {
678     RETURN_IF_ABANDONED
679     if (strokeInfo && strokeInfo->isDashed()) {
680         SkPath path;
681         path.addRect(rect);
682         this->drawPath(rt, clip, paint, viewMatrix, path, *strokeInfo);
683         return;
684     }
685
686     AutoCheckFlush acf(this);
687     GrPipelineBuilder pipelineBuilder;
688     GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
689     if (NULL == target) {
690         return;
691     }
692
693     GR_CREATE_TRACE_MARKER("GrContext::drawRect", target);
694     SkScalar width = NULL == strokeInfo ? -1 : strokeInfo->getStrokeRec().getWidth();
695
696     // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
697     // cases where the RT is fully inside a stroke.
698     if (width < 0) {
699         SkRect rtRect;
700         pipelineBuilder.getRenderTarget()->getBoundsRect(&rtRect);
701         SkRect clipSpaceRTRect = rtRect;
702         bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
703         if (checkClip) {
704             clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
705                                    SkIntToScalar(clip.origin().fY));
706         }
707         // Does the clip contain the entire RT?
708         if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
709             SkMatrix invM;
710             if (!viewMatrix.invert(&invM)) {
711                 return;
712             }
713             // Does the rect bound the RT?
714             SkPoint srcSpaceRTQuad[4];
715             invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
716             if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
717                 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
718                 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
719                 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
720                 // Will it blend?
721                 GrColor clearColor;
722                 if (paint.isOpaqueAndConstantColor(&clearColor)) {
723                     target->clear(NULL, clearColor, true, rt);
724                     return;
725                 }
726             }
727         }
728     }
729
730     GrColor color = paint.getColor();
731     SkRect devBoundRect;
732     bool needAA = paint.isAntiAlias() && !pipelineBuilder.getRenderTarget()->isMultisampled();
733     bool doAA = needAA && apply_aa_to_rect(target, &pipelineBuilder, &devBoundRect, rect, width,
734                                            viewMatrix, color);
735
736     if (doAA) {
737         if (width >= 0) {
738             const SkStrokeRec& strokeRec = strokeInfo->getStrokeRec();
739             fAARectRenderer->strokeAARect(target,
740                                           &pipelineBuilder,
741                                           color,
742                                           viewMatrix,
743                                           rect,
744                                           devBoundRect,
745                                           strokeRec);
746         } else {
747             // filled AA rect
748             fAARectRenderer->fillAARect(target,
749                                         &pipelineBuilder,
750                                         color,
751                                         viewMatrix,
752                                         rect,
753                                         devBoundRect);
754         }
755         return;
756     }
757
758     if (width >= 0) {
759         StrokeRectBatch::Geometry geometry;
760         geometry.fViewMatrix = viewMatrix;
761         geometry.fColor = color;
762         geometry.fRect = rect;
763         geometry.fStrokeWidth = width;
764
765         SkAutoTUnref<GrBatch> batch(StrokeRectBatch::Create(geometry));
766
767         SkRect bounds = rect;
768         SkScalar rad = SkScalarHalf(width);
769         bounds.outset(rad, rad);
770         viewMatrix.mapRect(&bounds);
771         target->drawBatch(&pipelineBuilder, batch, &bounds);
772     } else {
773         // filled BW rect
774         target->drawSimpleRect(&pipelineBuilder, color, viewMatrix, rect);
775     }
776 }
777
778 void GrContext::drawNonAARectToRect(GrRenderTarget* rt,
779                                     const GrClip& clip,
780                                     const GrPaint& paint,
781                                     const SkMatrix& viewMatrix,
782                                     const SkRect& rectToDraw,
783                                     const SkRect& localRect,
784                                     const SkMatrix* localMatrix) {
785     RETURN_IF_ABANDONED
786     AutoCheckFlush acf(this);
787     GrPipelineBuilder pipelineBuilder;
788     GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
789     if (NULL == target) {
790         return;
791     }
792
793     GR_CREATE_TRACE_MARKER("GrContext::drawRectToRect", target);
794
795     target->drawRect(&pipelineBuilder,
796                      paint.getColor(),
797                      viewMatrix,
798                      rectToDraw,
799                      &localRect,
800                      localMatrix);
801 }
802
803 static const GrGeometryProcessor* set_vertex_attributes(bool hasLocalCoords,
804                                                         bool hasColors,
805                                                         int* colorOffset,
806                                                         int* texOffset,
807                                                         GrColor color,
808                                                         const SkMatrix& viewMatrix) {
809     *texOffset = -1;
810     *colorOffset = -1;
811     uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType;
812     if (hasLocalCoords && hasColors) {
813         *colorOffset = sizeof(SkPoint);
814         *texOffset = sizeof(SkPoint) + sizeof(GrColor);
815         flags |= GrDefaultGeoProcFactory::kColor_GPType |
816                  GrDefaultGeoProcFactory::kLocalCoord_GPType;
817     } else if (hasLocalCoords) {
818         *texOffset = sizeof(SkPoint);
819         flags |= GrDefaultGeoProcFactory::kLocalCoord_GPType;
820     } else if (hasColors) {
821         *colorOffset = sizeof(SkPoint);
822         flags |= GrDefaultGeoProcFactory::kColor_GPType;
823     }
824     return GrDefaultGeoProcFactory::Create(flags, color, viewMatrix, SkMatrix::I());
825 }
826
827 class DrawVerticesBatch : public GrBatch {
828 public:
829     struct Geometry {
830         GrColor fColor;
831         SkTDArray<SkPoint> fPositions;
832         SkTDArray<uint16_t> fIndices;
833         SkTDArray<GrColor> fColors;
834         SkTDArray<SkPoint> fLocalCoords;
835     };
836
837     static GrBatch* Create(const Geometry& geometry, GrPrimitiveType primitiveType,
838                            const SkMatrix& viewMatrix,
839                            const SkPoint* positions, int vertexCount,
840                            const uint16_t* indices, int indexCount,
841                            const GrColor* colors, const SkPoint* localCoords) {
842         return SkNEW_ARGS(DrawVerticesBatch, (geometry, primitiveType, viewMatrix, positions,
843                                               vertexCount, indices, indexCount, colors,
844                                               localCoords));
845     }
846
847     const char* name() const override { return "DrawVerticesBatch"; }
848
849     void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
850         // When this is called on a batch, there is only one geometry bundle
851         if (this->hasColors()) {
852             out->setUnknownFourComponents();
853         } else {
854             out->setKnownFourComponents(fGeoData[0].fColor);
855         }
856     }
857
858     void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
859         out->setKnownSingleComponent(0xff);
860     }
861
862     void initBatchTracker(const GrPipelineInfo& init) override {
863         // Handle any color overrides
864         if (init.fColorIgnored) {
865             fGeoData[0].fColor = GrColor_ILLEGAL;
866         } else if (GrColor_ILLEGAL != init.fOverrideColor) {
867             fGeoData[0].fColor = init.fOverrideColor;
868         }
869
870         // setup batch properties
871         fBatch.fColorIgnored = init.fColorIgnored;
872         fBatch.fColor = fGeoData[0].fColor;
873         fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
874         fBatch.fCoverageIgnored = init.fCoverageIgnored;
875     }
876
877     void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) override {
878         int colorOffset = -1, texOffset = -1;
879         SkAutoTUnref<const GrGeometryProcessor> gp(
880                 set_vertex_attributes(this->hasLocalCoords(), this->hasColors(), &colorOffset,
881                                       &texOffset, this->color(), this->viewMatrix()));
882
883         batchTarget->initDraw(gp, pipeline);
884
885         // TODO this is hacky, but the only way we have to initialize the GP is to use the
886         // GrPipelineInfo struct so we can generate the correct shader.  Once we have GrBatch
887         // everywhere we can remove this nastiness
888         GrPipelineInfo init;
889         init.fColorIgnored = fBatch.fColorIgnored;
890         init.fOverrideColor = GrColor_ILLEGAL;
891         init.fCoverageIgnored = fBatch.fCoverageIgnored;
892         init.fUsesLocalCoords = this->usesLocalCoords();
893         gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
894
895         size_t vertexStride = gp->getVertexStride();
896
897         SkASSERT(vertexStride == sizeof(SkPoint) + (this->hasLocalCoords() ? sizeof(SkPoint) : 0)
898                                                  + (this->hasColors() ? sizeof(GrColor) : 0));
899
900         int instanceCount = fGeoData.count();
901
902         const GrVertexBuffer* vertexBuffer;
903         int firstVertex;
904
905         void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
906                                                               this->vertexCount(),
907                                                               &vertexBuffer,
908                                                               &firstVertex);
909
910         if (!vertices) {
911             SkDebugf("Could not allocate vertices\n");
912             return;
913         }
914
915         const GrIndexBuffer* indexBuffer;
916         int firstIndex;
917
918         void* indices = NULL;
919         if (this->hasIndices()) {
920             indices = batchTarget->indexPool()->makeSpace(this->indexCount(),
921                                                           &indexBuffer,
922                                                           &firstIndex);
923
924             if (!indices) {
925                 SkDebugf("Could not allocate indices\n");
926                 return;
927             }
928         }
929
930         int indexOffset = 0;
931         int vertexOffset = 0;
932         for (int i = 0; i < instanceCount; i++) {
933             const Geometry& args = fGeoData[i];
934
935             // TODO we can actually cache this interleaved and then just memcopy
936             if (this->hasIndices()) {
937                 for (int j = 0; j < args.fIndices.count(); ++j, ++indexOffset) {
938                     *((uint16_t*)indices + indexOffset) = args.fIndices[j] + vertexOffset;
939                 }
940             }
941
942             for (int j = 0; j < args.fPositions.count(); ++j) {
943                 *((SkPoint*)vertices) = args.fPositions[j];
944                 if (this->hasColors()) {
945                     *(GrColor*)((intptr_t)vertices + colorOffset) = args.fColors[j];
946                 }
947                 if (this->hasLocalCoords()) {
948                     *(SkPoint*)((intptr_t)vertices + texOffset) = args.fLocalCoords[j];
949                 }
950                 vertices = (void*)((intptr_t)vertices + vertexStride);
951                 vertexOffset++;
952             }
953         }
954
955         GrDrawTarget::DrawInfo drawInfo;
956         drawInfo.setPrimitiveType(this->primitiveType());
957         drawInfo.setVertexBuffer(vertexBuffer);
958         drawInfo.setStartVertex(firstVertex);
959         drawInfo.setVertexCount(this->vertexCount());
960         if (this->hasIndices()) {
961             drawInfo.setIndexBuffer(indexBuffer);
962             drawInfo.setStartIndex(firstIndex);
963             drawInfo.setIndexCount(this->indexCount());
964         } else {
965             drawInfo.setStartIndex(0);
966             drawInfo.setIndexCount(0);
967         }
968         batchTarget->draw(drawInfo);
969     }
970
971     SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
972
973 private:
974     DrawVerticesBatch(const Geometry& geometry, GrPrimitiveType primitiveType,
975                       const SkMatrix& viewMatrix,
976                       const SkPoint* positions, int vertexCount,
977                       const uint16_t* indices, int indexCount,
978                       const GrColor* colors, const SkPoint* localCoords) {
979         this->initClassID<DrawVerticesBatch>();
980         SkASSERT(positions);
981
982         fBatch.fViewMatrix = viewMatrix;
983         Geometry& installedGeo = fGeoData.push_back(geometry);
984
985         installedGeo.fPositions.append(vertexCount, positions);
986         if (indices) {
987             installedGeo.fIndices.append(indexCount, indices);
988             fBatch.fHasIndices = true;
989         } else {
990             fBatch.fHasIndices = false;
991         }
992
993         if (colors) {
994             installedGeo.fColors.append(vertexCount, colors);
995             fBatch.fHasColors = true;
996         } else {
997             fBatch.fHasColors = false;
998         }
999
1000         if (localCoords) {
1001             installedGeo.fLocalCoords.append(vertexCount, localCoords);
1002             fBatch.fHasLocalCoords = true;
1003         } else {
1004             fBatch.fHasLocalCoords = false;
1005         }
1006         fBatch.fVertexCount = vertexCount;
1007         fBatch.fIndexCount = indexCount;
1008         fBatch.fPrimitiveType = primitiveType;
1009     }
1010
1011     GrPrimitiveType primitiveType() const { return fBatch.fPrimitiveType; }
1012     bool batchablePrimitiveType() const {
1013         return kTriangles_GrPrimitiveType == fBatch.fPrimitiveType ||
1014                kLines_GrPrimitiveType == fBatch.fPrimitiveType ||
1015                kPoints_GrPrimitiveType == fBatch.fPrimitiveType;
1016     }
1017     GrColor color() const { return fBatch.fColor; }
1018     bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1019     bool colorIgnored() const { return fBatch.fColorIgnored; }
1020     const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
1021     bool hasColors() const { return fBatch.fHasColors; }
1022     bool hasIndices() const { return fBatch.fHasIndices; }
1023     bool hasLocalCoords() const { return fBatch.fHasLocalCoords; }
1024     int vertexCount() const { return fBatch.fVertexCount; }
1025     int indexCount() const { return fBatch.fIndexCount; }
1026
1027     bool onCombineIfPossible(GrBatch* t) override {
1028         DrawVerticesBatch* that = t->cast<DrawVerticesBatch>();
1029
1030         if (!this->batchablePrimitiveType() || this->primitiveType() != that->primitiveType()) {
1031             return false;
1032         }
1033
1034         SkASSERT(this->usesLocalCoords() == that->usesLocalCoords());
1035
1036         // We currently use a uniform viewmatrix for this batch
1037         if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1038             return false;
1039         }
1040
1041         if (this->hasColors() != that->hasColors()) {
1042             return false;
1043         }
1044
1045         if (this->hasIndices() != that->hasIndices()) {
1046             return false;
1047         }
1048
1049         if (this->hasLocalCoords() != that->hasLocalCoords()) {
1050             return false;
1051         }
1052
1053         if (!this->hasColors() && this->color() != that->color()) {
1054             return false;
1055         }
1056
1057         if (this->color() != that->color()) {
1058             fBatch.fColor = GrColor_ILLEGAL;
1059         }
1060         fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin());
1061         fBatch.fVertexCount += that->vertexCount();
1062         fBatch.fIndexCount += that->indexCount();
1063         return true;
1064     }
1065
1066     struct BatchTracker {
1067         GrPrimitiveType fPrimitiveType;
1068         SkMatrix fViewMatrix;
1069         GrColor fColor;
1070         bool fUsesLocalCoords;
1071         bool fColorIgnored;
1072         bool fCoverageIgnored;
1073         bool fHasColors;
1074         bool fHasIndices;
1075         bool fHasLocalCoords;
1076         int fVertexCount;
1077         int fIndexCount;
1078     };
1079
1080     BatchTracker fBatch;
1081     SkSTArray<1, Geometry, true> fGeoData;
1082 };
1083
1084 void GrContext::drawVertices(GrRenderTarget* rt,
1085                              const GrClip& clip,
1086                              const GrPaint& paint,
1087                              const SkMatrix& viewMatrix,
1088                              GrPrimitiveType primitiveType,
1089                              int vertexCount,
1090                              const SkPoint positions[],
1091                              const SkPoint texCoords[],
1092                              const GrColor colors[],
1093                              const uint16_t indices[],
1094                              int indexCount) {
1095     RETURN_IF_ABANDONED
1096     AutoCheckFlush acf(this);
1097     GrPipelineBuilder pipelineBuilder;
1098     GrDrawTarget::AutoReleaseGeometry geo; // must be inside AutoCheckFlush scope
1099
1100     GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
1101     if (NULL == target) {
1102         return;
1103     }
1104
1105     GR_CREATE_TRACE_MARKER("GrContext::drawVertices", target);
1106
1107     DrawVerticesBatch::Geometry geometry;
1108     geometry.fColor = paint.getColor();
1109
1110     SkAutoTUnref<GrBatch> batch(DrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
1111                                                           positions, vertexCount, indices,
1112                                                           indexCount,colors, texCoords));
1113
1114     // TODO figure out bounds
1115     target->drawBatch(&pipelineBuilder, batch, NULL);
1116 }
1117
1118 ///////////////////////////////////////////////////////////////////////////////
1119
1120 void GrContext::drawRRect(GrRenderTarget*rt,
1121                           const GrClip& clip,
1122                           const GrPaint& paint,
1123                           const SkMatrix& viewMatrix,
1124                           const SkRRect& rrect,
1125                           const GrStrokeInfo& strokeInfo) {
1126     RETURN_IF_ABANDONED
1127     if (rrect.isEmpty()) {
1128        return;
1129     }
1130
1131     if (strokeInfo.isDashed()) {
1132         SkPath path;
1133         path.addRRect(rrect);
1134         this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
1135         return;
1136     }
1137
1138     AutoCheckFlush acf(this);
1139     GrPipelineBuilder pipelineBuilder;
1140     GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
1141     if (NULL == target) {
1142         return;
1143     }
1144
1145     GR_CREATE_TRACE_MARKER("GrContext::drawRRect", target);
1146
1147     const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1148
1149     GrColor color = paint.getColor();
1150     if (!fOvalRenderer->drawRRect(target,
1151                                   &pipelineBuilder,
1152                                   color,
1153                                   viewMatrix,
1154                                   paint.isAntiAlias(),
1155                                   rrect,
1156                                   strokeRec)) {
1157         SkPath path;
1158         path.addRRect(rrect);
1159         this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1160                                path, strokeInfo);
1161     }
1162 }
1163
1164 ///////////////////////////////////////////////////////////////////////////////
1165
1166 void GrContext::drawDRRect(GrRenderTarget* rt,
1167                            const GrClip& clip,
1168                            const GrPaint& paint,
1169                            const SkMatrix& viewMatrix,
1170                            const SkRRect& outer,
1171                            const SkRRect& inner) {
1172     RETURN_IF_ABANDONED
1173     if (outer.isEmpty()) {
1174        return;
1175     }
1176
1177     AutoCheckFlush acf(this);
1178     GrPipelineBuilder pipelineBuilder;
1179     GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
1180
1181     GR_CREATE_TRACE_MARKER("GrContext::drawDRRect", target);
1182
1183     GrColor color = paint.getColor();
1184     if (!fOvalRenderer->drawDRRect(target,
1185                                    &pipelineBuilder,
1186                                    color,
1187                                    viewMatrix,
1188                                    paint.isAntiAlias(),
1189                                    outer,
1190                                    inner)) {
1191         SkPath path;
1192         path.addRRect(inner);
1193         path.addRRect(outer);
1194         path.setFillType(SkPath::kEvenOdd_FillType);
1195
1196         GrStrokeInfo fillRec(SkStrokeRec::kFill_InitStyle);
1197         this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1198                                path, fillRec);
1199     }
1200 }
1201
1202 ///////////////////////////////////////////////////////////////////////////////
1203
1204 void GrContext::drawOval(GrRenderTarget* rt,
1205                          const GrClip& clip,
1206                          const GrPaint& paint,
1207                          const SkMatrix& viewMatrix,
1208                          const SkRect& oval,
1209                          const GrStrokeInfo& strokeInfo) {
1210     RETURN_IF_ABANDONED
1211     if (oval.isEmpty()) {
1212        return;
1213     }
1214
1215     if (strokeInfo.isDashed()) {
1216         SkPath path;
1217         path.addOval(oval);
1218         this->drawPath(rt, clip, paint, viewMatrix, path, strokeInfo);
1219         return;
1220     }
1221
1222     AutoCheckFlush acf(this);
1223     GrPipelineBuilder pipelineBuilder;
1224     GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
1225     if (NULL == target) {
1226         return;
1227     }
1228
1229     GR_CREATE_TRACE_MARKER("GrContext::drawOval", target);
1230
1231     const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1232
1233     GrColor color = paint.getColor();
1234     if (!fOvalRenderer->drawOval(target,
1235                                  &pipelineBuilder,
1236                                  color,
1237                                  viewMatrix,
1238                                  paint.isAntiAlias(),
1239                                  oval,
1240                                  strokeRec)) {
1241         SkPath path;
1242         path.addOval(oval);
1243         this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1244                                path, strokeInfo);
1245     }
1246 }
1247
1248 // Can 'path' be drawn as a pair of filled nested rectangles?
1249 static bool is_nested_rects(GrDrawTarget* target,
1250                             GrPipelineBuilder* pipelineBuilder,
1251                             GrColor color,
1252                             const SkMatrix& viewMatrix,
1253                             const SkPath& path,
1254                             const SkStrokeRec& stroke,
1255                             SkRect rects[2]) {
1256     SkASSERT(stroke.isFillStyle());
1257
1258     if (path.isInverseFillType()) {
1259         return false;
1260     }
1261
1262     // TODO: this restriction could be lifted if we were willing to apply
1263     // the matrix to all the points individually rather than just to the rect
1264     if (!viewMatrix.preservesAxisAlignment()) {
1265         return false;
1266     }
1267
1268     SkPath::Direction dirs[2];
1269     if (!path.isNestedRects(rects, dirs)) {
1270         return false;
1271     }
1272
1273     if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
1274         // The two rects need to be wound opposite to each other
1275         return false;
1276     }
1277
1278     // Right now, nested rects where the margin is not the same width
1279     // all around do not render correctly
1280     const SkScalar* outer = rects[0].asScalars();
1281     const SkScalar* inner = rects[1].asScalars();
1282
1283     bool allEq = true;
1284
1285     SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
1286     bool allGoE1 = margin >= SK_Scalar1;
1287
1288     for (int i = 1; i < 4; ++i) {
1289         SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
1290         if (temp < SK_Scalar1) {
1291             allGoE1 = false;
1292         }
1293         if (!SkScalarNearlyEqual(margin, temp)) {
1294             allEq = false;
1295         }
1296     }
1297
1298     return allEq || allGoE1;
1299 }
1300
1301 void GrContext::drawPath(GrRenderTarget* rt,
1302                          const GrClip& clip,
1303                          const GrPaint& paint,
1304                          const SkMatrix& viewMatrix,
1305                          const SkPath& path,
1306                          const GrStrokeInfo& strokeInfo) {
1307     RETURN_IF_ABANDONED
1308     if (path.isEmpty()) {
1309        if (path.isInverseFillType()) {
1310            this->drawPaint(rt, clip, paint, viewMatrix);
1311        }
1312        return;
1313     }
1314
1315     GrColor color = paint.getColor();
1316     if (strokeInfo.isDashed()) {
1317         SkPoint pts[2];
1318         if (path.isLine(pts)) {
1319             AutoCheckFlush acf(this);
1320             GrPipelineBuilder pipelineBuilder;
1321             GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
1322             if (NULL == target) {
1323                 return;
1324             }
1325
1326             if (GrDashingEffect::DrawDashLine(fGpu, target, &pipelineBuilder, color, viewMatrix,
1327                                               pts, paint, strokeInfo)) {
1328                 return;
1329             }
1330         }
1331
1332         // Filter dashed path into new path with the dashing applied
1333         const SkPathEffect::DashInfo& info = strokeInfo.getDashInfo();
1334         SkTLazy<SkPath> effectPath;
1335         GrStrokeInfo newStrokeInfo(strokeInfo, false);
1336         SkStrokeRec* stroke = newStrokeInfo.getStrokeRecPtr();
1337         if (SkDashPath::FilterDashPath(effectPath.init(), path, stroke, NULL, info)) {
1338             this->drawPath(rt, clip, paint, viewMatrix, *effectPath.get(), newStrokeInfo);
1339             return;
1340         }
1341
1342         this->drawPath(rt, clip, paint, viewMatrix, path, newStrokeInfo);
1343         return;
1344     }
1345
1346     // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
1347     // Scratch textures can be recycled after they are returned to the texture
1348     // cache. This presents a potential hazard for buffered drawing. However,
1349     // the writePixels that uploads to the scratch will perform a flush so we're
1350     // OK.
1351     AutoCheckFlush acf(this);
1352     GrPipelineBuilder pipelineBuilder;
1353     GrDrawTarget* target = this->prepareToDraw(&pipelineBuilder, rt, clip, &paint, &acf);
1354     if (NULL == target) {
1355         return;
1356     }
1357
1358     GR_CREATE_TRACE_MARKER1("GrContext::drawPath", target, "Is Convex", path.isConvex());
1359
1360     const SkStrokeRec& strokeRec = strokeInfo.getStrokeRec();
1361
1362     bool useCoverageAA = paint.isAntiAlias() &&
1363         !pipelineBuilder.getRenderTarget()->isMultisampled();
1364
1365     if (useCoverageAA && strokeRec.getWidth() < 0 && !path.isConvex()) {
1366         // Concave AA paths are expensive - try to avoid them for special cases
1367         SkRect rects[2];
1368
1369         if (is_nested_rects(target, &pipelineBuilder, color, viewMatrix, path, strokeRec, rects)) {
1370             fAARectRenderer->fillAANestedRects(target, &pipelineBuilder, color, viewMatrix, rects);
1371             return;
1372         }
1373     }
1374
1375     SkRect ovalRect;
1376     bool isOval = path.isOval(&ovalRect);
1377
1378     if (!isOval || path.isInverseFillType() ||
1379         !fOvalRenderer->drawOval(target,
1380                                  &pipelineBuilder,
1381                                  color,
1382                                  viewMatrix,
1383                                  paint.isAntiAlias(),
1384                                  ovalRect,
1385                                  strokeRec)) {
1386         this->internalDrawPath(target, &pipelineBuilder, viewMatrix, color, paint.isAntiAlias(),
1387                                path, strokeInfo);
1388     }
1389 }
1390
1391 void GrContext::internalDrawPath(GrDrawTarget* target,
1392                                  GrPipelineBuilder* pipelineBuilder,
1393                                  const SkMatrix& viewMatrix,
1394                                  GrColor color,
1395                                  bool useAA,
1396                                  const SkPath& path,
1397                                  const GrStrokeInfo& strokeInfo) {
1398     RETURN_IF_ABANDONED
1399     SkASSERT(!path.isEmpty());
1400
1401     GR_CREATE_TRACE_MARKER("GrContext::internalDrawPath", target);
1402
1403
1404     // An Assumption here is that path renderer would use some form of tweaking
1405     // the src color (either the input alpha or in the frag shader) to implement
1406     // aa. If we have some future driver-mojo path AA that can do the right
1407     // thing WRT to the blend then we'll need some query on the PR.
1408     bool useCoverageAA = useAA &&
1409         !pipelineBuilder->getRenderTarget()->isMultisampled();
1410
1411
1412     GrPathRendererChain::DrawType type =
1413         useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType :
1414                         GrPathRendererChain::kColor_DrawType;
1415
1416     const SkPath* pathPtr = &path;
1417     SkTLazy<SkPath> tmpPath;
1418     SkTCopyOnFirstWrite<SkStrokeRec> stroke(strokeInfo.getStrokeRec());
1419
1420     // Try a 1st time without stroking the path and without allowing the SW renderer
1421     GrPathRenderer* pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr,
1422                                                *stroke, false, type);
1423
1424     if (NULL == pr) {
1425         if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*stroke, viewMatrix, NULL)) {
1426             // It didn't work the 1st time, so try again with the stroked path
1427             if (stroke->applyToPath(tmpPath.init(), *pathPtr)) {
1428                 pathPtr = tmpPath.get();
1429                 stroke.writable()->setFillStyle();
1430                 if (pathPtr->isEmpty()) {
1431                     return;
1432                 }
1433             }
1434         }
1435
1436         // This time, allow SW renderer
1437         pr = this->getPathRenderer(target, pipelineBuilder, viewMatrix, *pathPtr, *stroke, true,
1438                                    type);
1439     }
1440
1441     if (NULL == pr) {
1442 #ifdef SK_DEBUG
1443         SkDebugf("Unable to find path renderer compatible with path.\n");
1444 #endif
1445         return;
1446     }
1447
1448     pr->drawPath(target, pipelineBuilder, color, viewMatrix, *pathPtr, *stroke, useCoverageAA);
1449 }
1450
1451 ////////////////////////////////////////////////////////////////////////////////
1452
1453 void GrContext::flush(int flagsBitfield) {
1454     if (NULL == fDrawBuffer) {
1455         return;
1456     }
1457
1458     if (kDiscard_FlushBit & flagsBitfield) {
1459         fDrawBuffer->reset();
1460     } else {
1461         fDrawBuffer->flush();
1462     }
1463     fFlushToReduceCacheSize = false;
1464 }
1465
1466 bool sw_convert_to_premul(GrPixelConfig srcConfig, int width, int height, size_t inRowBytes,
1467                           const void* inPixels, size_t outRowBytes, void* outPixels) {
1468     SkSrcPixelInfo srcPI;
1469     if (!GrPixelConfig2ColorAndProfileType(srcConfig, &srcPI.fColorType, NULL)) {
1470         return false;
1471     }
1472     srcPI.fAlphaType = kUnpremul_SkAlphaType;
1473     srcPI.fPixels = inPixels;
1474     srcPI.fRowBytes = inRowBytes;
1475
1476     SkDstPixelInfo dstPI;
1477     dstPI.fColorType = srcPI.fColorType;
1478     dstPI.fAlphaType = kPremul_SkAlphaType;
1479     dstPI.fPixels = outPixels;
1480     dstPI.fRowBytes = outRowBytes;
1481
1482     return srcPI.convertPixelsTo(&dstPI, width, height);
1483 }
1484
1485 bool GrContext::writeSurfacePixels(GrSurface* surface,
1486                                    int left, int top, int width, int height,
1487                                    GrPixelConfig srcConfig, const void* buffer, size_t rowBytes,
1488                                    uint32_t pixelOpsFlags) {
1489     RETURN_FALSE_IF_ABANDONED
1490     {
1491         GrTexture* texture = NULL;
1492         if (!(kUnpremul_PixelOpsFlag & pixelOpsFlags) && (texture = surface->asTexture()) &&
1493             fGpu->canWriteTexturePixels(texture, srcConfig)) {
1494
1495             if (!(kDontFlush_PixelOpsFlag & pixelOpsFlags) &&
1496                 surface->surfacePriv().hasPendingIO()) {
1497                 this->flush();
1498             }
1499             return fGpu->writeTexturePixels(texture, left, top, width, height,
1500                                             srcConfig, buffer, rowBytes);
1501             // Don't need to check kFlushWrites_PixelOp here, we just did a direct write so the
1502             // upload is already flushed.
1503         }
1504     }
1505
1506     // If we didn't do a direct texture write then we upload the pixels to a texture and draw.
1507     GrRenderTarget* renderTarget = surface->asRenderTarget();
1508     if (NULL == renderTarget) {
1509         return false;
1510     }
1511
1512     // We ignore the preferred config unless it is a R/B swap of the src config. In that case
1513     // we will upload the original src data to a scratch texture but we will spoof it as the swapped
1514     // config. This scratch will then have R and B swapped. We correct for this by swapping again
1515     // when drawing the scratch to the dst using a conversion effect.
1516     bool swapRAndB = false;
1517     GrPixelConfig writeConfig = srcConfig;
1518     if (GrPixelConfigSwapRAndB(srcConfig) ==
1519         fGpu->preferredWritePixelsConfig(srcConfig, renderTarget->config())) {
1520         writeConfig = GrPixelConfigSwapRAndB(srcConfig);
1521         swapRAndB = true;
1522     }
1523
1524     GrSurfaceDesc desc;
1525     desc.fWidth = width;
1526     desc.fHeight = height;
1527     desc.fConfig = writeConfig;
1528     SkAutoTUnref<GrTexture> texture(this->refScratchTexture(desc, kApprox_ScratchTexMatch));
1529     if (!texture) {
1530         return false;
1531     }
1532
1533     SkAutoTUnref<const GrFragmentProcessor> fp;
1534     SkMatrix textureMatrix;
1535     textureMatrix.setIDiv(texture->width(), texture->height());
1536
1537     // allocate a tmp buffer and sw convert the pixels to premul
1538     SkAutoSTMalloc<128 * 128, uint32_t> tmpPixels(0);
1539
1540     if (kUnpremul_PixelOpsFlag & pixelOpsFlags) {
1541         if (!GrPixelConfigIs8888(srcConfig)) {
1542             return false;
1543         }
1544         fp.reset(this->createUPMToPMEffect(texture, swapRAndB, textureMatrix));
1545         // handle the unpremul step on the CPU if we couldn't create an effect to do it.
1546         if (NULL == fp) {
1547             size_t tmpRowBytes = 4 * width;
1548             tmpPixels.reset(width * height);
1549             if (!sw_convert_to_premul(srcConfig, width, height, rowBytes, buffer, tmpRowBytes,
1550                                       tmpPixels.get())) {
1551                 return false;
1552             }
1553             rowBytes = tmpRowBytes;
1554             buffer = tmpPixels.get();
1555         }
1556     }
1557     if (NULL == fp) {
1558         fp.reset(GrConfigConversionEffect::Create(texture,
1559                                                   swapRAndB,
1560                                                   GrConfigConversionEffect::kNone_PMConversion,
1561                                                   textureMatrix));
1562     }
1563
1564     // Even if the client told us not to flush, we still flush here. The client may have known that
1565     // writes to the original surface caused no data hazards, but they can't know that the scratch
1566     // we just got is safe.
1567     if (texture->surfacePriv().hasPendingIO()) {
1568         this->flush();
1569     }
1570     if (!fGpu->writeTexturePixels(texture, 0, 0, width, height,
1571                                   writeConfig, buffer, rowBytes)) {
1572         return false;
1573     }
1574
1575     SkMatrix matrix;
1576     matrix.setTranslate(SkIntToScalar(left), SkIntToScalar(top));
1577
1578     // This function can be called in the midst of drawing another object (e.g., when uploading a
1579     // SW-rasterized clip while issuing a draw). So we push the current geometry state before
1580     // drawing a rect to the render target.
1581     // The bracket ensures we pop the stack if we wind up flushing below.
1582     {
1583         GrDrawTarget* drawTarget = this->prepareToDraw();
1584         if (!drawTarget) {
1585             return false;
1586         }
1587         GrDrawTarget::AutoGeometryPush agp(drawTarget);
1588
1589         GrPipelineBuilder pipelineBuilder;
1590         pipelineBuilder.addColorProcessor(fp);
1591         pipelineBuilder.setRenderTarget(renderTarget);
1592         drawTarget->drawSimpleRect(&pipelineBuilder,
1593                                    GrColor_WHITE,
1594                                    matrix,
1595                                    SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)));
1596     }
1597
1598     if (kFlushWrites_PixelOp & pixelOpsFlags) {
1599         this->flushSurfaceWrites(surface);
1600     }
1601
1602     return true;
1603 }
1604
1605 // toggles between RGBA and BGRA
1606 static SkColorType toggle_colortype32(SkColorType ct) {
1607     if (kRGBA_8888_SkColorType == ct) {
1608         return kBGRA_8888_SkColorType;
1609     } else {
1610         SkASSERT(kBGRA_8888_SkColorType == ct);
1611         return kRGBA_8888_SkColorType;
1612     }
1613 }
1614
1615 bool GrContext::readRenderTargetPixels(GrRenderTarget* target,
1616                                        int left, int top, int width, int height,
1617                                        GrPixelConfig dstConfig, void* buffer, size_t rowBytes,
1618                                        uint32_t flags) {
1619     RETURN_FALSE_IF_ABANDONED
1620     ASSERT_OWNED_RESOURCE(target);
1621     SkASSERT(target);
1622
1623     if (!(kDontFlush_PixelOpsFlag & flags) && target->surfacePriv().hasPendingWrite()) {
1624         this->flush();
1625     }
1626
1627     // Determine which conversions have to be applied: flipY, swapRAnd, and/or unpremul.
1628
1629     // If fGpu->readPixels would incur a y-flip cost then we will read the pixels upside down. We'll
1630     // either do the flipY by drawing into a scratch with a matrix or on the cpu after the read.
1631     bool flipY = fGpu->readPixelsWillPayForYFlip(target, left, top,
1632                                                  width, height, dstConfig,
1633                                                  rowBytes);
1634     // We ignore the preferred config if it is different than our config unless it is an R/B swap.
1635     // In that case we'll perform an R and B swap while drawing to a scratch texture of the swapped
1636     // config. Then we will call readPixels on the scratch with the swapped config. The swaps during
1637     // the draw cancels out the fact that we call readPixels with a config that is R/B swapped from
1638     // dstConfig.
1639     GrPixelConfig readConfig = dstConfig;
1640     bool swapRAndB = false;
1641     if (GrPixelConfigSwapRAndB(dstConfig) ==
1642         fGpu->preferredReadPixelsConfig(dstConfig, target->config())) {
1643         readConfig = GrPixelConfigSwapRAndB(readConfig);
1644         swapRAndB = true;
1645     }
1646
1647     bool unpremul = SkToBool(kUnpremul_PixelOpsFlag & flags);
1648
1649     if (unpremul && !GrPixelConfigIs8888(dstConfig)) {
1650         // The unpremul flag is only allowed for these two configs.
1651         return false;
1652     }
1653
1654     SkAutoTUnref<GrTexture> tempTexture;
1655
1656     // If the src is a texture and we would have to do conversions after read pixels, we instead
1657     // do the conversions by drawing the src to a scratch texture. If we handle any of the
1658     // conversions in the draw we set the corresponding bool to false so that we don't reapply it
1659     // on the read back pixels.
1660     GrTexture* src = target->asTexture();
1661     if (src && (swapRAndB || unpremul || flipY)) {
1662         // Make the scratch a render so we can read its pixels.
1663         GrSurfaceDesc desc;
1664         desc.fFlags = kRenderTarget_GrSurfaceFlag;
1665         desc.fWidth = width;
1666         desc.fHeight = height;
1667         desc.fConfig = readConfig;
1668         desc.fOrigin = kTopLeft_GrSurfaceOrigin;
1669
1670         // When a full read back is faster than a partial we could always make the scratch exactly
1671         // match the passed rect. However, if we see many different size rectangles we will trash
1672         // our texture cache and pay the cost of creating and destroying many textures. So, we only
1673         // request an exact match when the caller is reading an entire RT.
1674         ScratchTexMatch match = kApprox_ScratchTexMatch;
1675         if (0 == left &&
1676             0 == top &&
1677             target->width() == width &&
1678             target->height() == height &&
1679             fGpu->fullReadPixelsIsFasterThanPartial()) {
1680             match = kExact_ScratchTexMatch;
1681         }
1682         tempTexture.reset(this->refScratchTexture(desc, match));
1683         if (tempTexture) {
1684             // compute a matrix to perform the draw
1685             SkMatrix textureMatrix;
1686             textureMatrix.setTranslate(SK_Scalar1 *left, SK_Scalar1 *top);
1687             textureMatrix.postIDiv(src->width(), src->height());
1688
1689             SkAutoTUnref<const GrFragmentProcessor> fp;
1690             if (unpremul) {
1691                 fp.reset(this->createPMToUPMEffect(src, swapRAndB, textureMatrix));
1692                 if (fp) {
1693                     unpremul = false; // we no longer need to do this on CPU after the read back.
1694                 }
1695             }
1696             // If we failed to create a PM->UPM effect and have no other conversions to perform then
1697             // there is no longer any point to using the scratch.
1698             if (fp || flipY || swapRAndB) {
1699                 if (!fp) {
1700                     fp.reset(GrConfigConversionEffect::Create(
1701                             src, swapRAndB, GrConfigConversionEffect::kNone_PMConversion,
1702                             textureMatrix));
1703                 }
1704                 swapRAndB = false; // we will handle the swap in the draw.
1705
1706                 // We protect the existing geometry here since it may not be
1707                 // clear to the caller that a draw operation (i.e., drawSimpleRect)
1708                 // can be invoked in this method
1709                 {
1710                     GrDrawTarget::AutoGeometryPush agp(fDrawBuffer);
1711                     GrPipelineBuilder pipelineBuilder;
1712                     SkASSERT(fp);
1713                     pipelineBuilder.addColorProcessor(fp);
1714
1715                     pipelineBuilder.setRenderTarget(tempTexture->asRenderTarget());
1716                     SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
1717                     fDrawBuffer->drawSimpleRect(&pipelineBuilder,
1718                                                 GrColor_WHITE,
1719                                                 SkMatrix::I(),
1720                                                 rect);
1721                     // we want to read back from the scratch's origin
1722                     left = 0;
1723                     top = 0;
1724                     target = tempTexture->asRenderTarget();
1725                 }
1726                 this->flushSurfaceWrites(target);
1727             }
1728         }
1729     }
1730
1731     if (!fGpu->readPixels(target,
1732                           left, top, width, height,
1733                           readConfig, buffer, rowBytes)) {
1734         return false;
1735     }
1736     // Perform any conversions we weren't able to perform using a scratch texture.
1737     if (unpremul || swapRAndB) {
1738         SkDstPixelInfo dstPI;
1739         if (!GrPixelConfig2ColorAndProfileType(dstConfig, &dstPI.fColorType, NULL)) {
1740             return false;
1741         }
1742         dstPI.fAlphaType = kUnpremul_SkAlphaType;
1743         dstPI.fPixels = buffer;
1744         dstPI.fRowBytes = rowBytes;
1745
1746         SkSrcPixelInfo srcPI;
1747         srcPI.fColorType = swapRAndB ? toggle_colortype32(dstPI.fColorType) : dstPI.fColorType;
1748         srcPI.fAlphaType = kPremul_SkAlphaType;
1749         srcPI.fPixels = buffer;
1750         srcPI.fRowBytes = rowBytes;
1751
1752         return srcPI.convertPixelsTo(&dstPI, width, height);
1753     }
1754     return true;
1755 }
1756
1757 void GrContext::prepareSurfaceForExternalRead(GrSurface* surface) {
1758     RETURN_IF_ABANDONED
1759     SkASSERT(surface);
1760     ASSERT_OWNED_RESOURCE(surface);
1761     if (surface->surfacePriv().hasPendingIO()) {
1762         this->flush();
1763     }
1764     GrRenderTarget* rt = surface->asRenderTarget();
1765     if (fGpu && rt) {
1766         fGpu->resolveRenderTarget(rt);
1767     }
1768 }
1769
1770 void GrContext::discardRenderTarget(GrRenderTarget* renderTarget) {
1771     RETURN_IF_ABANDONED
1772     SkASSERT(renderTarget);
1773     ASSERT_OWNED_RESOURCE(renderTarget);
1774     AutoCheckFlush acf(this);
1775     GrDrawTarget* target = this->prepareToDraw();
1776     if (NULL == target) {
1777         return;
1778     }
1779     target->discard(renderTarget);
1780 }
1781
1782 void GrContext::copySurface(GrSurface* dst, GrSurface* src, const SkIRect& srcRect,
1783                             const SkIPoint& dstPoint, uint32_t pixelOpsFlags) {
1784     RETURN_IF_ABANDONED
1785     if (NULL == src || NULL == dst) {
1786         return;
1787     }
1788     ASSERT_OWNED_RESOURCE(src);
1789     ASSERT_OWNED_RESOURCE(dst);
1790
1791     // Since we're going to the draw target and not GPU, no need to check kNoFlush
1792     // here.
1793
1794     GrDrawTarget* target = this->prepareToDraw();
1795     if (NULL == target) {
1796         return;
1797     }
1798     target->copySurface(dst, src, srcRect, dstPoint);
1799
1800     if (kFlushWrites_PixelOp & pixelOpsFlags) {
1801         this->flush();
1802     }
1803 }
1804
1805 void GrContext::flushSurfaceWrites(GrSurface* surface) {
1806     RETURN_IF_ABANDONED
1807     if (surface->surfacePriv().hasPendingWrite()) {
1808         this->flush();
1809     }
1810 }
1811
1812 GrDrawTarget* GrContext::prepareToDraw(GrPipelineBuilder* pipelineBuilder,
1813                                        GrRenderTarget* rt,
1814                                        const GrClip& clip,
1815                                        const GrPaint* paint,
1816                                        const AutoCheckFlush* acf) {
1817     if (NULL == fGpu || NULL == fDrawBuffer) {
1818         return NULL;
1819     }
1820
1821     ASSERT_OWNED_RESOURCE(rt);
1822     SkASSERT(rt && paint && acf);
1823     pipelineBuilder->setFromPaint(*paint, rt, clip);
1824     return fDrawBuffer;
1825 }
1826
1827 GrDrawTarget* GrContext::prepareToDraw() {
1828     if (NULL == fGpu) {
1829         return NULL;
1830     }
1831     return fDrawBuffer;
1832 }
1833
1834 /*
1835  * This method finds a path renderer that can draw the specified path on
1836  * the provided target.
1837  * Due to its expense, the software path renderer has split out so it can
1838  * can be individually allowed/disallowed via the "allowSW" boolean.
1839  */
1840 GrPathRenderer* GrContext::getPathRenderer(const GrDrawTarget* target,
1841                                            const GrPipelineBuilder* pipelineBuilder,
1842                                            const SkMatrix& viewMatrix,
1843                                            const SkPath& path,
1844                                            const SkStrokeRec& stroke,
1845                                            bool allowSW,
1846                                            GrPathRendererChain::DrawType drawType,
1847                                            GrPathRendererChain::StencilSupport* stencilSupport) {
1848
1849     if (NULL == fPathRendererChain) {
1850         fPathRendererChain = SkNEW_ARGS(GrPathRendererChain, (this));
1851     }
1852
1853     GrPathRenderer* pr = fPathRendererChain->getPathRenderer(target,
1854                                                              pipelineBuilder,
1855                                                              viewMatrix,
1856                                                              path,
1857                                                              stroke,
1858                                                              drawType,
1859                                                              stencilSupport);
1860
1861     if (NULL == pr && allowSW) {
1862         if (NULL == fSoftwarePathRenderer) {
1863             fSoftwarePathRenderer = SkNEW_ARGS(GrSoftwarePathRenderer, (this));
1864         }
1865         pr = fSoftwarePathRenderer;
1866     }
1867
1868     return pr;
1869 }
1870
1871 ////////////////////////////////////////////////////////////////////////////////
1872 bool GrContext::isConfigRenderable(GrPixelConfig config, bool withMSAA) const {
1873     return fGpu->caps()->isConfigRenderable(config, withMSAA);
1874 }
1875
1876 int GrContext::getRecommendedSampleCount(GrPixelConfig config,
1877                                          SkScalar dpi) const {
1878     if (!this->isConfigRenderable(config, true)) {
1879         return 0;
1880     }
1881     int chosenSampleCount = 0;
1882     if (fGpu->caps()->pathRenderingSupport()) {
1883         if (dpi >= 250.0f) {
1884             chosenSampleCount = 4;
1885         } else {
1886             chosenSampleCount = 16;
1887         }
1888     }
1889     return chosenSampleCount <= fGpu->caps()->maxSampleCount() ?
1890         chosenSampleCount : 0;
1891 }
1892
1893 void GrContext::setupDrawBuffer() {
1894     SkASSERT(NULL == fDrawBuffer);
1895     SkASSERT(NULL == fDrawBufferVBAllocPool);
1896     SkASSERT(NULL == fDrawBufferIBAllocPool);
1897
1898     fDrawBufferVBAllocPool =
1899         SkNEW_ARGS(GrVertexBufferAllocPool, (fGpu, false,
1900                                     DRAW_BUFFER_VBPOOL_BUFFER_SIZE,
1901                                     DRAW_BUFFER_VBPOOL_PREALLOC_BUFFERS));
1902     fDrawBufferIBAllocPool =
1903         SkNEW_ARGS(GrIndexBufferAllocPool, (fGpu, false,
1904                                    DRAW_BUFFER_IBPOOL_BUFFER_SIZE,
1905                                    DRAW_BUFFER_IBPOOL_PREALLOC_BUFFERS));
1906
1907     fDrawBuffer = SkNEW_ARGS(GrInOrderDrawBuffer, (fGpu,
1908                                                    fDrawBufferVBAllocPool,
1909                                                    fDrawBufferIBAllocPool));
1910 }
1911
1912 GrDrawTarget* GrContext::getTextTarget() {
1913     return this->prepareToDraw();
1914 }
1915
1916 const GrIndexBuffer* GrContext::getQuadIndexBuffer() const {
1917     return fGpu->getQuadIndexBuffer();
1918 }
1919
1920 namespace {
1921 void test_pm_conversions(GrContext* ctx, int* pmToUPMValue, int* upmToPMValue) {
1922     GrConfigConversionEffect::PMConversion pmToUPM;
1923     GrConfigConversionEffect::PMConversion upmToPM;
1924     GrConfigConversionEffect::TestForPreservingPMConversions(ctx, &pmToUPM, &upmToPM);
1925     *pmToUPMValue = pmToUPM;
1926     *upmToPMValue = upmToPM;
1927 }
1928 }
1929
1930 const GrFragmentProcessor* GrContext::createPMToUPMEffect(GrTexture* texture,
1931                                                           bool swapRAndB,
1932                                                           const SkMatrix& matrix) {
1933     if (!fDidTestPMConversions) {
1934         test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
1935         fDidTestPMConversions = true;
1936     }
1937     GrConfigConversionEffect::PMConversion pmToUPM =
1938         static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
1939     if (GrConfigConversionEffect::kNone_PMConversion != pmToUPM) {
1940         return GrConfigConversionEffect::Create(texture, swapRAndB, pmToUPM, matrix);
1941     } else {
1942         return NULL;
1943     }
1944 }
1945
1946 const GrFragmentProcessor* GrContext::createUPMToPMEffect(GrTexture* texture,
1947                                                           bool swapRAndB,
1948                                                           const SkMatrix& matrix) {
1949     if (!fDidTestPMConversions) {
1950         test_pm_conversions(this, &fPMToUPMConversion, &fUPMToPMConversion);
1951         fDidTestPMConversions = true;
1952     }
1953     GrConfigConversionEffect::PMConversion upmToPM =
1954         static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
1955     if (GrConfigConversionEffect::kNone_PMConversion != upmToPM) {
1956         return GrConfigConversionEffect::Create(texture, swapRAndB, upmToPM, matrix);
1957     } else {
1958         return NULL;
1959     }
1960 }
1961
1962 //////////////////////////////////////////////////////////////////////////////
1963
1964 void GrContext::getResourceCacheLimits(int* maxTextures, size_t* maxTextureBytes) const {
1965     if (maxTextures) {
1966         *maxTextures = fResourceCache->getMaxResourceCount();
1967     }
1968     if (maxTextureBytes) {
1969         *maxTextureBytes = fResourceCache->getMaxResourceBytes();
1970     }
1971 }
1972
1973 void GrContext::setResourceCacheLimits(int maxTextures, size_t maxTextureBytes) {
1974     fResourceCache->setLimits(maxTextures, maxTextureBytes);
1975 }
1976
1977 void GrContext::addResourceToCache(const GrUniqueKey& key, GrGpuResource* resource) {
1978     ASSERT_OWNED_RESOURCE(resource);
1979     if (!resource) {
1980         return;
1981     }
1982     resource->resourcePriv().setUniqueKey(key);
1983 }
1984
1985 bool GrContext::isResourceInCache(const GrUniqueKey& key) const {
1986     return fResourceCache->hasUniqueKey(key);
1987 }
1988
1989 GrGpuResource* GrContext::findAndRefCachedResource(const GrUniqueKey& key) {
1990     return fResourceCache->findAndRefUniqueResource(key);
1991 }
1992
1993 //////////////////////////////////////////////////////////////////////////////
1994
1995 void GrContext::addGpuTraceMarker(const GrGpuTraceMarker* marker) {
1996     fGpu->addGpuTraceMarker(marker);
1997     if (fDrawBuffer) {
1998         fDrawBuffer->addGpuTraceMarker(marker);
1999     }
2000 }
2001
2002 void GrContext::removeGpuTraceMarker(const GrGpuTraceMarker* marker) {
2003     fGpu->removeGpuTraceMarker(marker);
2004     if (fDrawBuffer) {
2005         fDrawBuffer->removeGpuTraceMarker(marker);
2006     }
2007 }
2008