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