1 
2 /*
3  * Copyright 2015 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 "GrBatchTest.h"
10 #include "GrColor.h"
11 #include "GrDrawContext.h"
12 #include "GrDrawingManager.h"
13 #include "GrOvalRenderer.h"
14 #include "GrPathRenderer.h"
15 #include "GrRenderTarget.h"
16 #include "GrRenderTargetPriv.h"
17 #include "GrResourceProvider.h"
18 #include "SkSurfacePriv.h"
19 
20 #include "batches/GrBatch.h"
21 #include "batches/GrDrawAtlasBatch.h"
22 #include "batches/GrDrawVerticesBatch.h"
23 #include "batches/GrRectBatchFactory.h"
24 #include "batches/GrNinePatch.h" // TODO Factory
25 
26 #include "text/GrAtlasTextContext.h"
27 #include "text/GrStencilAndCoverTextContext.h"
28 
29 #include "../private/GrAuditTrail.h"
30 
31 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fDrawingManager->getContext())
32 #define ASSERT_SINGLE_OWNER \
33     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
34 #define RETURN_IF_ABANDONED        if (fDrawingManager->abandoned()) { return; }
35 #define RETURN_FALSE_IF_ABANDONED  if (fDrawingManager->abandoned()) { return false; }
36 #define RETURN_NULL_IF_ABANDONED   if (fDrawingManager->abandoned()) { return nullptr; }
37 
38 class AutoCheckFlush {
39 public:
AutoCheckFlush(GrDrawingManager * drawingManager)40     AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
41         SkASSERT(fDrawingManager);
42     }
~AutoCheckFlush()43     ~AutoCheckFlush() { fDrawingManager->getContext()->flushIfNecessary(); }
44 
45 private:
46     GrDrawingManager* fDrawingManager;
47 };
48 
49 // In MDB mode the reffing of the 'getLastDrawTarget' call's result allows in-progress
50 // drawTargets to be picked up and added to by drawContexts lower in the call
51 // stack. When this occurs with a closed drawTarget, a new one will be allocated
52 // when the drawContext attempts to use it (via getDrawTarget).
GrDrawContext(GrContext * context,GrDrawingManager * drawingMgr,GrRenderTarget * rt,const SkSurfaceProps * surfaceProps,GrAuditTrail * auditTrail,GrSingleOwner * singleOwner)53 GrDrawContext::GrDrawContext(GrContext* context,
54                              GrDrawingManager* drawingMgr,
55                              GrRenderTarget* rt,
56                              const SkSurfaceProps* surfaceProps,
57                              GrAuditTrail* auditTrail,
58                              GrSingleOwner* singleOwner)
59     : fDrawingManager(drawingMgr)
60     , fRenderTarget(rt)
61     , fDrawTarget(SkSafeRef(rt->getLastDrawTarget()))
62     , fContext(context)
63     , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
64     , fAuditTrail(auditTrail)
65 #ifdef SK_DEBUG
66     , fSingleOwner(singleOwner)
67 #endif
68 {
69     SkDEBUGCODE(this->validate();)
70 }
71 
72 #ifdef SK_DEBUG
validate() const73 void GrDrawContext::validate() const {
74     SkASSERT(fRenderTarget);
75     ASSERT_OWNED_RESOURCE(fRenderTarget);
76 
77     if (fDrawTarget && !fDrawTarget->isClosed()) {
78         SkASSERT(fRenderTarget->getLastDrawTarget() == fDrawTarget);
79     }
80 }
81 #endif
82 
~GrDrawContext()83 GrDrawContext::~GrDrawContext() {
84     ASSERT_SINGLE_OWNER
85     SkSafeUnref(fDrawTarget);
86 }
87 
getDrawTarget()88 GrDrawTarget* GrDrawContext::getDrawTarget() {
89     ASSERT_SINGLE_OWNER
90     SkDEBUGCODE(this->validate();)
91 
92     if (!fDrawTarget || fDrawTarget->isClosed()) {
93         fDrawTarget = fDrawingManager->newDrawTarget(fRenderTarget);
94     }
95 
96     return fDrawTarget;
97 }
98 
copySurface(GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)99 bool GrDrawContext::copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) {
100     ASSERT_SINGLE_OWNER
101     RETURN_FALSE_IF_ABANDONED
102     SkDEBUGCODE(this->validate();)
103     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::copySurface");
104 
105     return this->getDrawTarget()->copySurface(fRenderTarget, src, srcRect, dstPoint);
106 }
107 
drawText(const GrClip & clip,const GrPaint & grPaint,const SkPaint & skPaint,const SkMatrix & viewMatrix,const char text[],size_t byteLength,SkScalar x,SkScalar y,const SkIRect & clipBounds)108 void GrDrawContext::drawText(const GrClip& clip, const GrPaint& grPaint,
109                              const SkPaint& skPaint,
110                              const SkMatrix& viewMatrix,
111                              const char text[], size_t byteLength,
112                              SkScalar x, SkScalar y, const SkIRect& clipBounds) {
113     ASSERT_SINGLE_OWNER
114     RETURN_IF_ABANDONED
115     SkDEBUGCODE(this->validate();)
116     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawText");
117 
118     if (!fAtlasTextContext) {
119         fAtlasTextContext.reset(GrAtlasTextContext::Create());
120     }
121 
122     fAtlasTextContext->drawText(fContext, this, clip, grPaint, skPaint, viewMatrix, fSurfaceProps,
123                                 text, byteLength, x, y, clipBounds);
124 }
125 
drawPosText(const GrClip & clip,const GrPaint & grPaint,const SkPaint & skPaint,const SkMatrix & viewMatrix,const char text[],size_t byteLength,const SkScalar pos[],int scalarsPerPosition,const SkPoint & offset,const SkIRect & clipBounds)126 void GrDrawContext::drawPosText(const GrClip& clip, const GrPaint& grPaint,
127                                 const SkPaint& skPaint,
128                                 const SkMatrix& viewMatrix,
129                                 const char text[], size_t byteLength,
130                                 const SkScalar pos[], int scalarsPerPosition,
131                                 const SkPoint& offset, const SkIRect& clipBounds) {
132     ASSERT_SINGLE_OWNER
133     RETURN_IF_ABANDONED
134     SkDEBUGCODE(this->validate();)
135     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPosText");
136 
137     if (!fAtlasTextContext) {
138         fAtlasTextContext.reset(GrAtlasTextContext::Create());
139     }
140 
141     fAtlasTextContext->drawPosText(fContext, this, clip, grPaint, skPaint, viewMatrix,
142                                    fSurfaceProps, text, byteLength, pos, scalarsPerPosition,
143                                    offset, clipBounds);
144 
145 }
146 
drawTextBlob(const GrClip & clip,const SkPaint & skPaint,const SkMatrix & viewMatrix,const SkTextBlob * blob,SkScalar x,SkScalar y,SkDrawFilter * filter,const SkIRect & clipBounds)147 void GrDrawContext::drawTextBlob(const GrClip& clip, const SkPaint& skPaint,
148                                  const SkMatrix& viewMatrix, const SkTextBlob* blob,
149                                  SkScalar x, SkScalar y,
150                                  SkDrawFilter* filter, const SkIRect& clipBounds) {
151     ASSERT_SINGLE_OWNER
152     RETURN_IF_ABANDONED
153     SkDEBUGCODE(this->validate();)
154     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawTextBlob");
155 
156     if (!fAtlasTextContext) {
157         fAtlasTextContext.reset(GrAtlasTextContext::Create());
158     }
159 
160     fAtlasTextContext->drawTextBlob(fContext, this, clip, skPaint, viewMatrix, fSurfaceProps, blob,
161                                     x, y, filter, clipBounds);
162 }
163 
discard()164 void GrDrawContext::discard() {
165     ASSERT_SINGLE_OWNER
166     RETURN_IF_ABANDONED
167     SkDEBUGCODE(this->validate();)
168     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::discard");
169 
170     AutoCheckFlush acf(fDrawingManager);
171     this->getDrawTarget()->discard(fRenderTarget);
172 }
173 
clear(const SkIRect * rect,const GrColor color,bool canIgnoreRect)174 void GrDrawContext::clear(const SkIRect* rect,
175                           const GrColor color,
176                           bool canIgnoreRect) {
177     ASSERT_SINGLE_OWNER
178     RETURN_IF_ABANDONED
179     SkDEBUGCODE(this->validate();)
180     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::clear");
181 
182     AutoCheckFlush acf(fDrawingManager);
183     this->getDrawTarget()->clear(rect, color, canIgnoreRect, fRenderTarget);
184 }
185 
186 
drawPaint(const GrClip & clip,const GrPaint & origPaint,const SkMatrix & viewMatrix)187 void GrDrawContext::drawPaint(const GrClip& clip,
188                               const GrPaint& origPaint,
189                               const SkMatrix& viewMatrix) {
190     ASSERT_SINGLE_OWNER
191     RETURN_IF_ABANDONED
192     SkDEBUGCODE(this->validate();)
193     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPaint");
194 
195     // set rect to be big enough to fill the space, but not super-huge, so we
196     // don't overflow fixed-point implementations
197     SkRect r;
198     r.setLTRB(0, 0,
199               SkIntToScalar(fRenderTarget->width()),
200               SkIntToScalar(fRenderTarget->height()));
201     SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
202 
203     // by definition this fills the entire clip, no need for AA
204     if (paint->isAntiAlias()) {
205         paint.writable()->setAntiAlias(false);
206     }
207 
208     bool isPerspective = viewMatrix.hasPerspective();
209 
210     // We attempt to map r by the inverse matrix and draw that. mapRect will
211     // map the four corners and bound them with a new rect. This will not
212     // produce a correct result for some perspective matrices.
213     if (!isPerspective) {
214         SkMatrix inverse;
215         if (!viewMatrix.invert(&inverse)) {
216             SkDebugf("Could not invert matrix\n");
217             return;
218         }
219         inverse.mapRect(&r);
220         this->drawRect(clip, *paint, viewMatrix, r);
221     } else {
222         SkMatrix localMatrix;
223         if (!viewMatrix.invert(&localMatrix)) {
224             SkDebugf("Could not invert matrix\n");
225             return;
226         }
227 
228         AutoCheckFlush acf(fDrawingManager);
229 
230         GrPipelineBuilder pipelineBuilder(*paint, fRenderTarget, clip);
231         SkAutoTUnref<GrDrawBatch> batch(
232                 GrRectBatchFactory::CreateNonAAFill(paint->getColor(), SkMatrix::I(), r, nullptr,
233                                                     &localMatrix));
234         this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
235     }
236 }
237 
rect_contains_inclusive(const SkRect & rect,const SkPoint & point)238 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
239     return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
240            point.fY >= rect.fTop && point.fY <= rect.fBottom;
241 }
242 
view_matrix_ok_for_aa_fill_rect(const SkMatrix & viewMatrix)243 static bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) {
244     return viewMatrix.preservesRightAngles();
245 }
246 
should_apply_coverage_aa(const GrPaint & paint,GrRenderTarget * rt)247 static bool should_apply_coverage_aa(const GrPaint& paint, GrRenderTarget* rt) {
248     return paint.isAntiAlias() && !rt->isUnifiedMultisampled();
249 }
250 
drawRect(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & rect,const GrStrokeInfo * strokeInfo)251 void GrDrawContext::drawRect(const GrClip& clip,
252                              const GrPaint& paint,
253                              const SkMatrix& viewMatrix,
254                              const SkRect& rect,
255                              const GrStrokeInfo* strokeInfo) {
256     ASSERT_SINGLE_OWNER
257     RETURN_IF_ABANDONED
258     SkDEBUGCODE(this->validate();)
259     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRect");
260 
261     // Dashing should've been devolved to a path in SkGpuDevice
262     SkASSERT(!strokeInfo || !strokeInfo->isDashed());
263 
264     AutoCheckFlush acf(fDrawingManager);
265 
266     SkScalar width = nullptr == strokeInfo ? -1 : strokeInfo->getWidth();
267 
268     // Check if this is a full RT draw and can be replaced with a clear. We don't bother checking
269     // cases where the RT is fully inside a stroke.
270     if (width < 0) {
271         SkRect rtRect;
272         fRenderTarget->getBoundsRect(&rtRect);
273         SkRect clipSpaceRTRect = rtRect;
274         bool checkClip = GrClip::kWideOpen_ClipType != clip.clipType();
275         if (checkClip) {
276             clipSpaceRTRect.offset(SkIntToScalar(clip.origin().fX),
277                                    SkIntToScalar(clip.origin().fY));
278         }
279         // Does the clip contain the entire RT?
280         if (!checkClip || clip.quickContains(clipSpaceRTRect)) {
281             SkMatrix invM;
282             if (!viewMatrix.invert(&invM)) {
283                 return;
284             }
285             // Does the rect bound the RT?
286             SkPoint srcSpaceRTQuad[4];
287             invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
288             if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
289                 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
290                 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
291                 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
292                 // Will it blend?
293                 GrColor clearColor;
294                 if (paint.isConstantBlendedColor(&clearColor)) {
295                     this->getDrawTarget()->clear(nullptr, clearColor, true, fRenderTarget);
296                     return;
297                 }
298             }
299         }
300     }
301 
302     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
303     GrColor color = paint.getColor();
304 
305     SkAutoTUnref<GrDrawBatch> batch;
306     if (should_apply_coverage_aa(paint, fRenderTarget)) {
307         if (width >= 0) {
308             // The stroke path needs the rect to remain axis aligned (no rotation or skew).
309             if (viewMatrix.rectStaysRect()) {
310                 batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect,
311                                                                *strokeInfo));
312             }
313         } else {
314             // The fill path can handle rotation but not skew.
315             if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
316                 SkRect devBoundRect;
317                 viewMatrix.mapRect(&devBoundRect, rect);
318                 batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect,
319                                                              devBoundRect));
320             }
321         }
322         if (!batch) {
323             SkPath path;
324             path.setIsVolatile(true);
325             path.addRect(rect);
326             this->internalDrawPath(&pipelineBuilder, viewMatrix, color, true, path, *strokeInfo);
327             SkASSERT(paint.isAntiAlias());
328             return;
329         }
330     } else if (width >= 0) {
331         // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
332         bool snapToPixelCenters = (0 == width && !fRenderTarget->isUnifiedMultisampled());
333         batch.reset(GrRectBatchFactory::CreateNonAAStroke(color, viewMatrix, rect, width,
334                                                           snapToPixelCenters));
335 
336         // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
337         // hairline rects. We jam all the vertices to pixel centers to avoid this, but not when MSAA
338         // is enabled because it can cause ugly artifacts.
339         pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
340                                  snapToPixelCenters);
341     } else {
342         // filled BW rect
343         batch.reset(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect, nullptr, nullptr));
344     }
345     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
346 }
347 
fillRectToRect(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & rectToDraw,const SkRect & localRect)348 void GrDrawContext::fillRectToRect(const GrClip& clip,
349                                    const GrPaint& paint,
350                                    const SkMatrix& viewMatrix,
351                                    const SkRect& rectToDraw,
352                                    const SkRect& localRect) {
353     ASSERT_SINGLE_OWNER
354     RETURN_IF_ABANDONED
355     SkDEBUGCODE(this->validate();)
356     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectToRect");
357 
358     AutoCheckFlush acf(fDrawingManager);
359 
360     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
361     SkAutoTUnref<GrDrawBatch> batch;
362     if (should_apply_coverage_aa(paint, fRenderTarget) &&
363         view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
364         batch.reset(GrAAFillRectBatch::CreateWithLocalRect(paint.getColor(), viewMatrix, rectToDraw,
365                                                            localRect));
366     } else {
367         batch.reset(GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rectToDraw,
368                                                         &localRect, nullptr));
369     }
370 
371     if (batch) {
372         this->drawBatch(&pipelineBuilder, batch);
373     }
374 }
375 
fillRectWithLocalMatrix(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & rectToDraw,const SkMatrix & localMatrix)376 void GrDrawContext::fillRectWithLocalMatrix(const GrClip& clip,
377                                             const GrPaint& paint,
378                                             const SkMatrix& viewMatrix,
379                                             const SkRect& rectToDraw,
380                                             const SkMatrix& localMatrix) {
381     ASSERT_SINGLE_OWNER
382     RETURN_IF_ABANDONED
383     SkDEBUGCODE(this->validate();)
384     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectWithLocalMatrix");
385 
386     AutoCheckFlush acf(fDrawingManager);
387 
388     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
389 
390     SkAutoTUnref<GrDrawBatch> batch;
391     if (should_apply_coverage_aa(paint, fRenderTarget) &&
392         view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
393         batch.reset(GrAAFillRectBatch::Create(paint.getColor(), viewMatrix, localMatrix,
394                                               rectToDraw));
395     } else {
396         batch.reset(GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rectToDraw,
397                                                         nullptr, &localMatrix));
398     }
399     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
400 }
401 
drawVertices(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)402 void GrDrawContext::drawVertices(const GrClip& clip,
403                                  const GrPaint& paint,
404                                  const SkMatrix& viewMatrix,
405                                  GrPrimitiveType primitiveType,
406                                  int vertexCount,
407                                  const SkPoint positions[],
408                                  const SkPoint texCoords[],
409                                  const GrColor colors[],
410                                  const uint16_t indices[],
411                                  int indexCount) {
412     ASSERT_SINGLE_OWNER
413     RETURN_IF_ABANDONED
414     SkDEBUGCODE(this->validate();)
415     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawVertices");
416 
417     AutoCheckFlush acf(fDrawingManager);
418 
419     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
420 
421     // TODO clients should give us bounds
422     SkRect bounds;
423     if (!bounds.setBoundsCheck(positions, vertexCount)) {
424         SkDebugf("drawVertices call empty bounds\n");
425         return;
426     }
427 
428     viewMatrix.mapRect(&bounds);
429 
430     // If we don't have AA then we outset for a half pixel in each direction to account for
431     // snapping. We also do this for the "hair" primitive types: lines and points since they have
432     // a 1 pixel thickness in device space.
433     if (!paint.isAntiAlias() || GrIsPrimTypeLines(primitiveType) ||
434         kPoints_GrPrimitiveType == primitiveType) {
435         bounds.outset(0.5f, 0.5f);
436     }
437 
438     GrDrawVerticesBatch::Geometry geometry;
439     geometry.fColor = paint.getColor();
440     SkAutoTUnref<GrDrawBatch> batch(GrDrawVerticesBatch::Create(geometry, primitiveType, viewMatrix,
441                                                                 positions, vertexCount, indices,
442                                                                 indexCount, colors, texCoords,
443                                                                 bounds));
444 
445     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
446 }
447 
448 ///////////////////////////////////////////////////////////////////////////////
449 
drawAtlas(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,int spriteCount,const SkRSXform xform[],const SkRect texRect[],const SkColor colors[])450 void GrDrawContext::drawAtlas(const GrClip& clip,
451                               const GrPaint& paint,
452                               const SkMatrix& viewMatrix,
453                               int spriteCount,
454                               const SkRSXform xform[],
455                               const SkRect texRect[],
456                               const SkColor colors[]) {
457     ASSERT_SINGLE_OWNER
458     RETURN_IF_ABANDONED
459     SkDEBUGCODE(this->validate();)
460     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawAtlas");
461 
462     AutoCheckFlush acf(fDrawingManager);
463 
464     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
465 
466     GrDrawAtlasBatch::Geometry geometry;
467     geometry.fColor = paint.getColor();
468     SkAutoTUnref<GrDrawBatch> batch(GrDrawAtlasBatch::Create(geometry, viewMatrix, spriteCount,
469                                                              xform, texRect, colors));
470 
471     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
472 }
473 
474 ///////////////////////////////////////////////////////////////////////////////
475 
drawRRect(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRRect & rrect,const GrStrokeInfo & strokeInfo)476 void GrDrawContext::drawRRect(const GrClip& clip,
477                               const GrPaint& paint,
478                               const SkMatrix& viewMatrix,
479                               const SkRRect& rrect,
480                               const GrStrokeInfo& strokeInfo) {
481     ASSERT_SINGLE_OWNER
482     RETURN_IF_ABANDONED
483     SkDEBUGCODE(this->validate();)
484     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRRect");
485 
486     if (rrect.isEmpty()) {
487        return;
488     }
489 
490     SkASSERT(!strokeInfo.isDashed()); // this should've been devolved to a path in SkGpuDevice
491 
492     AutoCheckFlush acf(fDrawingManager);
493 
494     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
495     GrColor color = paint.getColor();
496 
497     if (should_apply_coverage_aa(paint, fRenderTarget)) {
498         GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
499 
500         SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateRRectBatch(color,
501                                                                          viewMatrix,
502                                                                          rrect,
503                                                                          strokeInfo,
504                                                                          shaderCaps));
505         if (batch) {
506             this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
507             return;
508         }
509     }
510 
511     SkPath path;
512     path.setIsVolatile(true);
513     path.addRRect(rrect);
514     this->internalDrawPath(&pipelineBuilder, viewMatrix, color,
515                            paint.isAntiAlias(), path, strokeInfo);
516 }
517 
518 ///////////////////////////////////////////////////////////////////////////////
519 
drawOval(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & oval,const GrStrokeInfo & strokeInfo)520 void GrDrawContext::drawOval(const GrClip& clip,
521                              const GrPaint& paint,
522                              const SkMatrix& viewMatrix,
523                              const SkRect& oval,
524                              const GrStrokeInfo& strokeInfo) {
525     ASSERT_SINGLE_OWNER
526     RETURN_IF_ABANDONED
527     SkDEBUGCODE(this->validate();)
528     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawOval");
529 
530     if (oval.isEmpty()) {
531        return;
532     }
533 
534     SkASSERT(!strokeInfo.isDashed()); // this should've been devolved to a path in SkGpuDevice
535 
536     AutoCheckFlush acf(fDrawingManager);
537 
538     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
539     GrColor color = paint.getColor();
540 
541     if (should_apply_coverage_aa(paint, fRenderTarget)) {
542         GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
543         SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(color,
544                                                                         viewMatrix,
545                                                                         oval,
546                                                                         strokeInfo,
547                                                                         shaderCaps));
548         if (batch) {
549             this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
550             return;
551         }
552     }
553 
554     SkPath path;
555     path.setIsVolatile(true);
556     path.addOval(oval);
557     this->internalDrawPath(&pipelineBuilder, viewMatrix, color,
558                            paint.isAntiAlias(), path, strokeInfo);
559 }
560 
drawImageNine(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,int imageWidth,int imageHeight,const SkIRect & center,const SkRect & dst)561 void GrDrawContext::drawImageNine(const GrClip& clip,
562                                   const GrPaint& paint,
563                                   const SkMatrix& viewMatrix,
564                                   int imageWidth,
565                                   int imageHeight,
566                                   const SkIRect& center,
567                                   const SkRect& dst) {
568     ASSERT_SINGLE_OWNER
569     RETURN_IF_ABANDONED
570     SkDEBUGCODE(this->validate();)
571     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawImageNine");
572 
573     AutoCheckFlush acf(fDrawingManager);
574 
575     SkAutoTUnref<GrDrawBatch> batch(GrNinePatch::CreateNonAA(paint.getColor(), viewMatrix,
576                                                              imageWidth, imageHeight,
577                                                              center, dst));
578 
579     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
580     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
581 }
582 
583 
584 // Can 'path' be drawn as a pair of filled nested rectangles?
is_nested_rects(const SkMatrix & viewMatrix,const SkPath & path,const SkStrokeRec & stroke,SkRect rects[2])585 static bool is_nested_rects(const SkMatrix& viewMatrix,
586                             const SkPath& path,
587                             const SkStrokeRec& stroke,
588                             SkRect rects[2]) {
589     SkASSERT(stroke.isFillStyle());
590 
591     if (path.isInverseFillType()) {
592         return false;
593     }
594 
595     // TODO: this restriction could be lifted if we were willing to apply
596     // the matrix to all the points individually rather than just to the rect
597     if (!viewMatrix.rectStaysRect()) {
598         return false;
599     }
600 
601     SkPath::Direction dirs[2];
602     if (!path.isNestedFillRects(rects, dirs)) {
603         return false;
604     }
605 
606     if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
607         // The two rects need to be wound opposite to each other
608         return false;
609     }
610 
611     // Right now, nested rects where the margin is not the same width
612     // all around do not render correctly
613     const SkScalar* outer = rects[0].asScalars();
614     const SkScalar* inner = rects[1].asScalars();
615 
616     bool allEq = true;
617 
618     SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
619     bool allGoE1 = margin >= SK_Scalar1;
620 
621     for (int i = 1; i < 4; ++i) {
622         SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
623         if (temp < SK_Scalar1) {
624             allGoE1 = false;
625         }
626         if (!SkScalarNearlyEqual(margin, temp)) {
627             allEq = false;
628         }
629     }
630 
631     return allEq || allGoE1;
632 }
633 
drawBatch(const GrClip & clip,const GrPaint & paint,GrDrawBatch * batch)634 void GrDrawContext::drawBatch(const GrClip& clip,
635                               const GrPaint& paint, GrDrawBatch* batch) {
636     ASSERT_SINGLE_OWNER
637     RETURN_IF_ABANDONED
638     SkDEBUGCODE(this->validate();)
639     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawBatch");
640 
641     AutoCheckFlush acf(fDrawingManager);
642 
643     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
644     this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
645 }
646 
drawPathBatch(const GrPipelineBuilder & pipelineBuilder,GrDrawPathBatchBase * batch)647 void GrDrawContext::drawPathBatch(const GrPipelineBuilder& pipelineBuilder,
648                                   GrDrawPathBatchBase* batch) {
649     ASSERT_SINGLE_OWNER
650     RETURN_IF_ABANDONED
651     SkDEBUGCODE(this->validate();)
652     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPathBatch");
653 
654     AutoCheckFlush acf(fDrawingManager);
655 
656     this->getDrawTarget()->drawPathBatch(pipelineBuilder, batch);
657 }
658 
drawPath(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkPath & path,const GrStrokeInfo & strokeInfo)659 void GrDrawContext::drawPath(const GrClip& clip,
660                              const GrPaint& paint,
661                              const SkMatrix& viewMatrix,
662                              const SkPath& path,
663                              const GrStrokeInfo& strokeInfo) {
664     ASSERT_SINGLE_OWNER
665     RETURN_IF_ABANDONED
666     SkDEBUGCODE(this->validate();)
667     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPath");
668 
669     if (path.isEmpty()) {
670        if (path.isInverseFillType()) {
671            this->drawPaint(clip, paint, viewMatrix);
672        }
673        return;
674     }
675 
676     GrColor color = paint.getColor();
677 
678     // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
679     // Scratch textures can be recycled after they are returned to the texture
680     // cache. This presents a potential hazard for buffered drawing. However,
681     // the writePixels that uploads to the scratch will perform a flush so we're
682     // OK.
683     AutoCheckFlush acf(fDrawingManager);
684 
685     GrPipelineBuilder pipelineBuilder(paint, fRenderTarget, clip);
686     if (should_apply_coverage_aa(paint, fRenderTarget) && !strokeInfo.isDashed()) {
687         if (strokeInfo.getWidth() < 0 && !path.isConvex()) {
688             // Concave AA paths are expensive - try to avoid them for special cases
689             SkRect rects[2];
690 
691             if (is_nested_rects(viewMatrix, path, strokeInfo, rects)) {
692                 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFillNestedRects(
693                     color, viewMatrix, rects));
694                 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
695                 return;
696             }
697         }
698         SkRect ovalRect;
699         bool isOval = path.isOval(&ovalRect);
700 
701         if (isOval && !path.isInverseFillType()) {
702             GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
703             SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(color,
704                                                                             viewMatrix,
705                                                                             ovalRect,
706                                                                             strokeInfo,
707                                                                             shaderCaps));
708             if (batch) {
709                 this->getDrawTarget()->drawBatch(pipelineBuilder, batch);
710                 return;
711             }
712         }
713     }
714     this->internalDrawPath(&pipelineBuilder, viewMatrix, color,
715                            paint.isAntiAlias(), path, strokeInfo);
716 }
717 
internalDrawPath(GrPipelineBuilder * pipelineBuilder,const SkMatrix & viewMatrix,GrColor color,bool useAA,const SkPath & path,const GrStrokeInfo & strokeInfo)718 void GrDrawContext::internalDrawPath(GrPipelineBuilder* pipelineBuilder,
719                                      const SkMatrix& viewMatrix,
720                                      GrColor color,
721                                      bool useAA,
722                                      const SkPath& path,
723                                      const GrStrokeInfo& strokeInfo) {
724     ASSERT_SINGLE_OWNER
725     RETURN_IF_ABANDONED
726     SkASSERT(!path.isEmpty());
727 
728     // An Assumption here is that path renderer would use some form of tweaking
729     // the src color (either the input alpha or in the frag shader) to implement
730     // aa. If we have some future driver-mojo path AA that can do the right
731     // thing WRT to the blend then we'll need some query on the PR.
732     bool useCoverageAA = useAA &&
733         !pipelineBuilder->getRenderTarget()->isUnifiedMultisampled();
734     bool isStencilDisabled = pipelineBuilder->getStencil().isDisabled();
735     bool isStencilBufferMSAA = pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled();
736 
737     const GrPathRendererChain::DrawType type =
738         useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType
739                       : GrPathRendererChain::kColor_DrawType;
740 
741     const SkPath* pathPtr = &path;
742     SkTLazy<SkPath> tmpPath;
743     const GrStrokeInfo* strokeInfoPtr = &strokeInfo;
744 
745     GrPathRenderer::CanDrawPathArgs canDrawArgs;
746     canDrawArgs.fShaderCaps = fDrawingManager->getContext()->caps()->shaderCaps();
747     canDrawArgs.fViewMatrix = &viewMatrix;
748     canDrawArgs.fPath = pathPtr;
749     canDrawArgs.fStroke = strokeInfoPtr;
750     canDrawArgs.fAntiAlias = useCoverageAA;
751     canDrawArgs.fIsStencilDisabled = isStencilDisabled;
752     canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
753 
754     // Try a 1st time without stroking the path and without allowing the SW renderer
755     GrPathRenderer* pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
756 
757     GrStrokeInfo dashlessStrokeInfo(strokeInfo, false);
758     if (nullptr == pr && strokeInfo.isDashed()) {
759         // It didn't work above, so try again with dashed stroke converted to a dashless stroke.
760         if (!strokeInfo.applyDashToPath(tmpPath.init(), &dashlessStrokeInfo, *pathPtr)) {
761             return;
762         }
763         pathPtr = tmpPath.get();
764         if (pathPtr->isEmpty()) {
765             return;
766         }
767         strokeInfoPtr = &dashlessStrokeInfo;
768 
769         canDrawArgs.fPath = pathPtr;
770         canDrawArgs.fStroke = strokeInfoPtr;
771 
772         pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
773     }
774 
775     if (nullptr == pr) {
776         if (!GrPathRenderer::IsStrokeHairlineOrEquivalent(*strokeInfoPtr, viewMatrix, nullptr) &&
777             !strokeInfoPtr->isFillStyle()) {
778             // It didn't work above, so try again with stroke converted to a fill.
779             if (!tmpPath.isValid()) {
780                 tmpPath.init();
781             }
782             dashlessStrokeInfo.setResScale(SkScalarAbs(viewMatrix.getMaxScale()));
783             if (!dashlessStrokeInfo.applyToPath(tmpPath.get(), *pathPtr)) {
784                 return;
785             }
786             pathPtr = tmpPath.get();
787             if (pathPtr->isEmpty()) {
788                 return;
789             }
790             dashlessStrokeInfo.setFillStyle();
791             strokeInfoPtr = &dashlessStrokeInfo;
792         }
793 
794         canDrawArgs.fPath = pathPtr;
795         canDrawArgs.fStroke = strokeInfoPtr;
796 
797         // This time, allow SW renderer
798         pr = fDrawingManager->getPathRenderer(canDrawArgs, true, type);
799     }
800 
801     if (nullptr == pr) {
802 #ifdef SK_DEBUG
803         SkDebugf("Unable to find path renderer compatible with path.\n");
804 #endif
805         return;
806     }
807 
808     GrPathRenderer::DrawPathArgs args;
809     args.fTarget = this->getDrawTarget();
810     args.fResourceProvider = fDrawingManager->getContext()->resourceProvider();
811     args.fPipelineBuilder = pipelineBuilder;
812     args.fColor = color;
813     args.fViewMatrix = &viewMatrix;
814     args.fPath = pathPtr;
815     args.fStroke = strokeInfoPtr;
816     args.fAntiAlias = useCoverageAA;
817     pr->drawPath(args);
818 }
819 
drawBatch(GrPipelineBuilder * pipelineBuilder,GrDrawBatch * batch)820 void GrDrawContext::drawBatch(GrPipelineBuilder* pipelineBuilder, GrDrawBatch* batch) {
821     ASSERT_SINGLE_OWNER
822     RETURN_IF_ABANDONED
823     SkDEBUGCODE(this->validate();)
824     GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawBatch");
825 
826     this->getDrawTarget()->drawBatch(*pipelineBuilder, batch);
827 }
828