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