1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "GrBatchTest.h"
9 #include "GrColor.h"
10 #include "GrDrawContext.h"
11 #include "GrDrawContextPriv.h"
12 #include "GrDrawingManager.h"
13 #include "GrFixedClip.h"
14 #include "GrGpuResourcePriv.h"
15 #include "GrOvalRenderer.h"
16 #include "GrPathRenderer.h"
17 #include "GrPipelineBuilder.h"
18 #include "GrRenderTarget.h"
19 #include "GrRenderTargetPriv.h"
20 #include "GrResourceProvider.h"
21 #include "SkSurfacePriv.h"
22
23 #include "batches/GrBatch.h"
24 #include "batches/GrClearBatch.h"
25 #include "batches/GrDrawAtlasBatch.h"
26 #include "batches/GrDrawVerticesBatch.h"
27 #include "batches/GrRectBatchFactory.h"
28 #include "batches/GrNinePatch.h" // TODO Factory
29 #include "batches/GrRegionBatch.h"
30
31 #include "effects/GrRRectEffect.h"
32
33 #include "instanced/InstancedRendering.h"
34
35 #include "text/GrAtlasTextContext.h"
36 #include "text/GrStencilAndCoverTextContext.h"
37
38 #include "../private/GrAuditTrail.h"
39
40 #include "SkGr.h"
41 #include "SkLatticeIter.h"
42 #include "SkMatrixPriv.h"
43
44 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fDrawingManager->getContext())
45 #define ASSERT_SINGLE_OWNER \
46 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
47 #define ASSERT_SINGLE_OWNER_PRIV \
48 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fDrawContext->fSingleOwner);)
49 #define RETURN_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return; }
50 #define RETURN_IF_ABANDONED_PRIV if (fDrawContext->fDrawingManager->wasAbandoned()) { return; }
51 #define RETURN_FALSE_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return false; }
52 #define RETURN_FALSE_IF_ABANDONED_PRIV if (fDrawContext->fDrawingManager->wasAbandoned()) { return false; }
53 #define RETURN_NULL_IF_ABANDONED if (fDrawingManager->wasAbandoned()) { return nullptr; }
54
55 using gr_instanced::InstancedRendering;
56
57 class AutoCheckFlush {
58 public:
AutoCheckFlush(GrDrawingManager * drawingManager)59 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
60 SkASSERT(fDrawingManager);
61 }
~AutoCheckFlush()62 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
63
64 private:
65 GrDrawingManager* fDrawingManager;
66 };
67
wasAbandoned() const68 bool GrDrawContext::wasAbandoned() const {
69 return fDrawingManager->wasAbandoned();
70 }
71
72 // In MDB mode the reffing of the 'getLastDrawTarget' call's result allows in-progress
73 // drawTargets to be picked up and added to by drawContexts lower in the call
74 // stack. When this occurs with a closed drawTarget, a new one will be allocated
75 // when the drawContext attempts to use it (via getDrawTarget).
GrDrawContext(GrContext * context,GrDrawingManager * drawingMgr,sk_sp<GrRenderTarget> rt,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps,GrAuditTrail * auditTrail,GrSingleOwner * singleOwner)76 GrDrawContext::GrDrawContext(GrContext* context,
77 GrDrawingManager* drawingMgr,
78 sk_sp<GrRenderTarget> rt,
79 sk_sp<SkColorSpace> colorSpace,
80 const SkSurfaceProps* surfaceProps,
81 GrAuditTrail* auditTrail,
82 GrSingleOwner* singleOwner)
83 : fDrawingManager(drawingMgr)
84 , fRenderTarget(std::move(rt))
85 , fDrawTarget(SkSafeRef(fRenderTarget->getLastDrawTarget()))
86 , fContext(context)
87 , fInstancedPipelineInfo(fRenderTarget.get())
88 , fColorSpace(std::move(colorSpace))
89 , fColorXformFromSRGB(nullptr)
90 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
91 , fAuditTrail(auditTrail)
92 #ifdef SK_DEBUG
93 , fSingleOwner(singleOwner)
94 #endif
95 {
96 if (fColorSpace) {
97 // sRGB sources are very common (SkColor, etc...), so we cache that gamut transformation
98 auto srgbColorSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named);
99 fColorXformFromSRGB = GrColorSpaceXform::Make(srgbColorSpace.get(), fColorSpace.get());
100 }
101 SkDEBUGCODE(this->validate();)
102 }
103
104 #ifdef SK_DEBUG
validate() const105 void GrDrawContext::validate() const {
106 SkASSERT(fRenderTarget);
107 ASSERT_OWNED_RESOURCE(fRenderTarget);
108
109 if (fDrawTarget && !fDrawTarget->isClosed()) {
110 SkASSERT(fRenderTarget->getLastDrawTarget() == fDrawTarget);
111 }
112 }
113 #endif
114
~GrDrawContext()115 GrDrawContext::~GrDrawContext() {
116 ASSERT_SINGLE_OWNER
117 SkSafeUnref(fDrawTarget);
118 }
119
getDrawTarget()120 GrDrawTarget* GrDrawContext::getDrawTarget() {
121 ASSERT_SINGLE_OWNER
122 SkDEBUGCODE(this->validate();)
123
124 if (!fDrawTarget || fDrawTarget->isClosed()) {
125 fDrawTarget = fDrawingManager->newDrawTarget(fRenderTarget.get());
126 }
127
128 return fDrawTarget;
129 }
130
copySurface(GrSurface * src,const SkIRect & srcRect,const SkIPoint & dstPoint)131 bool GrDrawContext::copySurface(GrSurface* src, const SkIRect& srcRect, const SkIPoint& dstPoint) {
132 ASSERT_SINGLE_OWNER
133 RETURN_FALSE_IF_ABANDONED
134 SkDEBUGCODE(this->validate();)
135 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::copySurface");
136
137 return this->getDrawTarget()->copySurface(fRenderTarget.get(), src, srcRect, dstPoint);
138 }
139
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)140 void GrDrawContext::drawText(const GrClip& clip, const GrPaint& grPaint,
141 const SkPaint& skPaint,
142 const SkMatrix& viewMatrix,
143 const char text[], size_t byteLength,
144 SkScalar x, SkScalar y, const SkIRect& clipBounds) {
145 ASSERT_SINGLE_OWNER
146 RETURN_IF_ABANDONED
147 SkDEBUGCODE(this->validate();)
148 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawText");
149
150 GrAtlasTextContext* atlasTextContext = fDrawingManager->getAtlasTextContext();
151 atlasTextContext->drawText(fContext, this, clip, grPaint, skPaint, viewMatrix, fSurfaceProps,
152 text, byteLength, x, y, clipBounds);
153 }
154
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)155 void GrDrawContext::drawPosText(const GrClip& clip, const GrPaint& grPaint,
156 const SkPaint& skPaint,
157 const SkMatrix& viewMatrix,
158 const char text[], size_t byteLength,
159 const SkScalar pos[], int scalarsPerPosition,
160 const SkPoint& offset, const SkIRect& clipBounds) {
161 ASSERT_SINGLE_OWNER
162 RETURN_IF_ABANDONED
163 SkDEBUGCODE(this->validate();)
164 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPosText");
165
166 GrAtlasTextContext* atlasTextContext = fDrawingManager->getAtlasTextContext();
167 atlasTextContext->drawPosText(fContext, this, clip, grPaint, skPaint, viewMatrix,
168 fSurfaceProps, text, byteLength, pos, scalarsPerPosition,
169 offset, clipBounds);
170
171 }
172
drawTextBlob(const GrClip & clip,const SkPaint & skPaint,const SkMatrix & viewMatrix,const SkTextBlob * blob,SkScalar x,SkScalar y,SkDrawFilter * filter,const SkIRect & clipBounds)173 void GrDrawContext::drawTextBlob(const GrClip& clip, const SkPaint& skPaint,
174 const SkMatrix& viewMatrix, const SkTextBlob* blob,
175 SkScalar x, SkScalar y,
176 SkDrawFilter* filter, const SkIRect& clipBounds) {
177 ASSERT_SINGLE_OWNER
178 RETURN_IF_ABANDONED
179 SkDEBUGCODE(this->validate();)
180 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawTextBlob");
181
182 GrAtlasTextContext* atlasTextContext = fDrawingManager->getAtlasTextContext();
183 atlasTextContext->drawTextBlob(fContext, this, clip, skPaint, viewMatrix, fSurfaceProps, blob,
184 x, y, filter, clipBounds);
185 }
186
discard()187 void GrDrawContext::discard() {
188 ASSERT_SINGLE_OWNER
189 RETURN_IF_ABANDONED
190 SkDEBUGCODE(this->validate();)
191 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::discard");
192
193 AutoCheckFlush acf(fDrawingManager);
194 this->getDrawTarget()->discard(fRenderTarget.get());
195 }
196
clear(const SkIRect * rect,const GrColor color,bool canIgnoreRect)197 void GrDrawContext::clear(const SkIRect* rect,
198 const GrColor color,
199 bool canIgnoreRect) {
200 ASSERT_SINGLE_OWNER
201 RETURN_IF_ABANDONED
202 SkDEBUGCODE(this->validate();)
203 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::clear");
204
205 AutoCheckFlush acf(fDrawingManager);
206 this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color, canIgnoreRect);
207 }
208
clear(const GrFixedClip & clip,const GrColor color,bool canIgnoreClip)209 void GrDrawContextPriv::clear(const GrFixedClip& clip,
210 const GrColor color,
211 bool canIgnoreClip) {
212 ASSERT_SINGLE_OWNER_PRIV
213 RETURN_IF_ABANDONED_PRIV
214 SkDEBUGCODE(fDrawContext->validate();)
215 GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContextPriv::clear");
216
217 AutoCheckFlush acf(fDrawContext->fDrawingManager);
218 fDrawContext->internalClear(clip, color, canIgnoreClip);
219 }
220
internalClear(const GrFixedClip & clip,const GrColor color,bool canIgnoreClip)221 void GrDrawContext::internalClear(const GrFixedClip& clip,
222 const GrColor color,
223 bool canIgnoreClip) {
224 bool isFull = false;
225 if (!clip.hasWindowRectangles()) {
226 isFull = !clip.scissorEnabled() ||
227 (canIgnoreClip && fContext->caps()->fullClearIsFree()) ||
228 clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
229 }
230
231 if (fContext->caps()->useDrawInsteadOfClear()) {
232 // This works around a driver bug with clear by drawing a rect instead.
233 // The driver will ignore a clear if it is the only thing rendered to a
234 // target before the target is read.
235 SkRect clearRect = SkRect::MakeIWH(this->width(), this->height());
236 if (isFull) {
237 this->discard();
238 } else if (!clearRect.intersect(SkRect::Make(clip.scissorRect()))) {
239 return;
240 }
241
242 GrPaint paint;
243 paint.setColor4f(GrColor4f::FromGrColor(color));
244 paint.setXPFactory(GrPorterDuffXPFactory::Make(SkXfermode::Mode::kSrc_Mode));
245
246 this->drawRect(clip, paint, SkMatrix::I(), clearRect);
247 } else if (isFull) {
248 this->getDrawTarget()->fullClear(this->accessRenderTarget(), color);
249 } else {
250 sk_sp<GrBatch> batch(GrClearBatch::Make(clip, color, this->accessRenderTarget()));
251 if (!batch) {
252 return;
253 }
254 this->getDrawTarget()->addBatch(std::move(batch));
255 }
256 }
257
drawPaint(const GrClip & clip,const GrPaint & origPaint,const SkMatrix & viewMatrix)258 void GrDrawContext::drawPaint(const GrClip& clip,
259 const GrPaint& origPaint,
260 const SkMatrix& viewMatrix) {
261 ASSERT_SINGLE_OWNER
262 RETURN_IF_ABANDONED
263 SkDEBUGCODE(this->validate();)
264 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPaint");
265
266 // set rect to be big enough to fill the space, but not super-huge, so we
267 // don't overflow fixed-point implementations
268
269 SkRect r = fRenderTarget->getBoundsRect();
270 SkTCopyOnFirstWrite<GrPaint> paint(origPaint);
271
272 SkRRect rrect;
273 bool aaRRect;
274 // Check if we can replace a clipRRect()/drawPaint() with a drawRRect(). We only do the
275 // transformation for non-rect rrects. Rects caused a performance regression on an Android
276 // test that needs investigation. We also skip cases where there are fragment processors
277 // because they may depend on having correct local coords and this path draws in device space
278 // without a local matrix.
279 if (!paint->numTotalFragmentProcessors() &&
280 clip.isRRect(r, &rrect, &aaRRect) && !rrect.isRect()) {
281 paint.writable()->setAntiAlias(aaRRect);
282 this->drawRRect(GrNoClip(), *paint, SkMatrix::I(), rrect, GrStyle::SimpleFill());
283 return;
284 }
285
286 // by definition this fills the entire clip, no need for AA
287 if (paint->isAntiAlias()) {
288 paint.writable()->setAntiAlias(false);
289 }
290
291 bool isPerspective = viewMatrix.hasPerspective();
292
293 // We attempt to map r by the inverse matrix and draw that. mapRect will
294 // map the four corners and bound them with a new rect. This will not
295 // produce a correct result for some perspective matrices.
296 if (!isPerspective) {
297 if (!SkMatrixPriv::InverseMapRect(viewMatrix, &r, r)) {
298 SkDebugf("Could not invert matrix\n");
299 return;
300 }
301 this->drawRect(clip, *paint, viewMatrix, r);
302 } else {
303 SkMatrix localMatrix;
304 if (!viewMatrix.invert(&localMatrix)) {
305 SkDebugf("Could not invert matrix\n");
306 return;
307 }
308
309 AutoCheckFlush acf(fDrawingManager);
310
311 this->drawNonAAFilledRect(clip, *paint, SkMatrix::I(), r, nullptr, &localMatrix, nullptr,
312 false /* useHWAA */);
313 }
314 }
315
rect_contains_inclusive(const SkRect & rect,const SkPoint & point)316 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
317 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
318 point.fY >= rect.fTop && point.fY <= rect.fBottom;
319 }
320
view_matrix_ok_for_aa_fill_rect(const SkMatrix & viewMatrix)321 static bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) {
322 return viewMatrix.preservesRightAngles();
323 }
324
should_apply_coverage_aa(const GrPaint & paint,GrRenderTarget * rt,bool * useHWAA=nullptr)325 static bool should_apply_coverage_aa(const GrPaint& paint, GrRenderTarget* rt,
326 bool* useHWAA = nullptr) {
327 if (!paint.isAntiAlias()) {
328 if (useHWAA) {
329 *useHWAA = false;
330 }
331 return false;
332 } else {
333 if (useHWAA) {
334 *useHWAA = rt->isUnifiedMultisampled();
335 }
336 return !rt->isUnifiedMultisampled();
337 }
338 }
339
340 // Attempts to crop a rect and optional local rect to the clip boundaries.
341 // Returns false if the draw can be skipped entirely.
crop_filled_rect(int width,int height,const GrClip & clip,const SkMatrix & viewMatrix,SkRect * rect,SkRect * localRect=nullptr)342 static bool crop_filled_rect(int width, int height, const GrClip& clip,
343 const SkMatrix& viewMatrix, SkRect* rect,
344 SkRect* localRect = nullptr) {
345 if (!viewMatrix.rectStaysRect()) {
346 return true;
347 }
348
349 SkIRect clipDevBounds;
350 SkRect clipBounds;
351
352 clip.getConservativeBounds(width, height, &clipDevBounds);
353 if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) {
354 return false;
355 }
356
357 if (localRect) {
358 if (!rect->intersects(clipBounds)) {
359 return false;
360 }
361 const SkScalar dx = localRect->width() / rect->width();
362 const SkScalar dy = localRect->height() / rect->height();
363 if (clipBounds.fLeft > rect->fLeft) {
364 localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx;
365 rect->fLeft = clipBounds.fLeft;
366 }
367 if (clipBounds.fTop > rect->fTop) {
368 localRect->fTop += (clipBounds.fTop - rect->fTop) * dy;
369 rect->fTop = clipBounds.fTop;
370 }
371 if (clipBounds.fRight < rect->fRight) {
372 localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx;
373 rect->fRight = clipBounds.fRight;
374 }
375 if (clipBounds.fBottom < rect->fBottom) {
376 localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy;
377 rect->fBottom = clipBounds.fBottom;
378 }
379 return true;
380 }
381
382 return rect->intersect(clipBounds);
383 }
384
drawFilledRect(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & rect,const GrUserStencilSettings * ss)385 bool GrDrawContext::drawFilledRect(const GrClip& clip,
386 const GrPaint& paint,
387 const SkMatrix& viewMatrix,
388 const SkRect& rect,
389 const GrUserStencilSettings* ss) {
390 SkRect croppedRect = rect;
391 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
392 return true;
393 }
394
395 SkAutoTUnref<GrDrawBatch> batch;
396 bool useHWAA;
397
398 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
399 InstancedRendering* ir = this->getDrawTarget()->instancedRendering();
400 batch.reset(ir->recordRect(croppedRect, viewMatrix, paint.getColor(),
401 paint.isAntiAlias(), fInstancedPipelineInfo,
402 &useHWAA));
403 if (batch) {
404 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
405 if (ss) {
406 pipelineBuilder.setUserStencil(ss);
407 }
408 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
409 return true;
410 }
411 }
412
413 if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) {
414 // The fill path can handle rotation but not skew.
415 if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
416 SkRect devBoundRect;
417 viewMatrix.mapRect(&devBoundRect, croppedRect);
418
419 batch.reset(GrRectBatchFactory::CreateAAFill(paint, viewMatrix, rect, croppedRect,
420 devBoundRect));
421 if (batch) {
422 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
423 if (ss) {
424 pipelineBuilder.setUserStencil(ss);
425 }
426 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
427 return true;
428 }
429 }
430 } else {
431 this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, nullptr, nullptr, ss,
432 useHWAA);
433 return true;
434 }
435
436 return false;
437 }
438
drawRect(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & rect,const GrStyle * style)439 void GrDrawContext::drawRect(const GrClip& clip,
440 const GrPaint& paint,
441 const SkMatrix& viewMatrix,
442 const SkRect& rect,
443 const GrStyle* style) {
444 if (!style) {
445 style = &GrStyle::SimpleFill();
446 }
447 ASSERT_SINGLE_OWNER
448 RETURN_IF_ABANDONED
449 SkDEBUGCODE(this->validate();)
450 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRect");
451
452 // Path effects should've been devolved to a path in SkGpuDevice
453 SkASSERT(!style->pathEffect());
454
455 AutoCheckFlush acf(fDrawingManager);
456
457 const SkStrokeRec& stroke = style->strokeRec();
458 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
459
460 if (!fContext->caps()->useDrawInsteadOfClear()) {
461 // Check if this is a full RT draw and can be replaced with a clear. We don't bother
462 // checking cases where the RT is fully inside a stroke.
463 SkRect rtRect = fRenderTarget->getBoundsRect();
464 // Does the clip contain the entire RT?
465 if (clip.quickContains(rtRect)) {
466 SkMatrix invM;
467 if (!viewMatrix.invert(&invM)) {
468 return;
469 }
470 // Does the rect bound the RT?
471 SkPoint srcSpaceRTQuad[4];
472 invM.mapRectToQuad(srcSpaceRTQuad, rtRect);
473 if (rect_contains_inclusive(rect, srcSpaceRTQuad[0]) &&
474 rect_contains_inclusive(rect, srcSpaceRTQuad[1]) &&
475 rect_contains_inclusive(rect, srcSpaceRTQuad[2]) &&
476 rect_contains_inclusive(rect, srcSpaceRTQuad[3])) {
477 // Will it blend?
478 GrColor clearColor;
479 if (paint.isConstantBlendedColor(&clearColor)) {
480 this->clear(nullptr, clearColor, true);
481 return;
482 }
483 }
484 }
485 }
486
487 if (this->drawFilledRect(clip, paint, viewMatrix, rect, nullptr)) {
488 return;
489 }
490 } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
491 stroke.getStyle() == SkStrokeRec::kHairline_Style) {
492 if ((!rect.width() || !rect.height()) &&
493 SkStrokeRec::kHairline_Style != stroke.getStyle()) {
494 SkScalar r = stroke.getWidth() / 2;
495 // TODO: Move these stroke->fill fallbacks to GrShape?
496 switch (stroke.getJoin()) {
497 case SkPaint::kMiter_Join:
498 this->drawRect(clip, paint, viewMatrix,
499 {rect.fLeft - r, rect.fTop - r,
500 rect.fRight + r, rect.fBottom + r},
501 &GrStyle::SimpleFill());
502 return;
503 case SkPaint::kRound_Join:
504 // Raster draws nothing when both dimensions are empty.
505 if (rect.width() || rect.height()){
506 SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
507 this->drawRRect(clip, paint, viewMatrix, rrect, GrStyle::SimpleFill());
508 return;
509 }
510 case SkPaint::kBevel_Join:
511 if (!rect.width()) {
512 this->drawRect(clip, paint, viewMatrix,
513 {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
514 &GrStyle::SimpleFill());
515 } else {
516 this->drawRect(clip, paint, viewMatrix,
517 {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
518 &GrStyle::SimpleFill());
519 }
520 return;
521 }
522 }
523
524 bool useHWAA;
525 bool snapToPixelCenters = false;
526 SkAutoTUnref<GrDrawBatch> batch;
527
528 GrColor color = paint.getColor();
529 if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) {
530 // The stroke path needs the rect to remain axis aligned (no rotation or skew).
531 if (viewMatrix.rectStaysRect()) {
532 batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, stroke));
533 }
534 } else {
535 // Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
536 // hairline rects. We jam all the vertices to pixel centers to avoid this, but not
537 // when MSAA is enabled because it can cause ugly artifacts.
538 snapToPixelCenters = stroke.getStyle() == SkStrokeRec::kHairline_Style &&
539 !fRenderTarget->isUnifiedMultisampled();
540 batch.reset(GrRectBatchFactory::CreateNonAAStroke(color, viewMatrix, rect,
541 stroke, snapToPixelCenters));
542 }
543
544 if (batch) {
545 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
546
547 if (snapToPixelCenters) {
548 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
549 snapToPixelCenters);
550 }
551
552 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
553 return;
554 }
555 }
556
557 SkPath path;
558 path.setIsVolatile(true);
559 path.addRect(rect);
560 this->internalDrawPath(clip, paint, viewMatrix, path, *style);
561 }
562
clearStencilClip(const GrFixedClip & clip,bool insideStencilMask)563 void GrDrawContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
564 ASSERT_SINGLE_OWNER_PRIV
565 RETURN_IF_ABANDONED_PRIV
566 SkDEBUGCODE(fDrawContext->validate();)
567 GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContextPriv::clearStencilClip");
568
569 AutoCheckFlush acf(fDrawContext->fDrawingManager);
570 fDrawContext->getDrawTarget()->clearStencilClip(clip, insideStencilMask,
571 fDrawContext->accessRenderTarget());
572 }
573
stencilPath(const GrClip & clip,bool useHWAA,const SkMatrix & viewMatrix,const GrPath * path)574 void GrDrawContextPriv::stencilPath(const GrClip& clip,
575 bool useHWAA,
576 const SkMatrix& viewMatrix,
577 const GrPath* path) {
578 fDrawContext->getDrawTarget()->stencilPath(fDrawContext, clip, useHWAA, viewMatrix, path);
579 }
580
stencilRect(const GrClip & clip,const GrUserStencilSettings * ss,bool useHWAA,const SkMatrix & viewMatrix,const SkRect & rect)581 void GrDrawContextPriv::stencilRect(const GrClip& clip,
582 const GrUserStencilSettings* ss,
583 bool useHWAA,
584 const SkMatrix& viewMatrix,
585 const SkRect& rect) {
586 ASSERT_SINGLE_OWNER_PRIV
587 RETURN_IF_ABANDONED_PRIV
588 SkDEBUGCODE(fDrawContext->validate();)
589 GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContext::stencilRect");
590
591 AutoCheckFlush acf(fDrawContext->fDrawingManager);
592
593 GrPaint paint;
594 paint.setAntiAlias(useHWAA);
595 paint.setXPFactory(GrDisableColorXPFactory::Make());
596
597 fDrawContext->drawNonAAFilledRect(clip, paint, viewMatrix, rect, nullptr, nullptr, ss, useHWAA);
598 }
599
drawAndStencilRect(const GrClip & clip,const GrUserStencilSettings * ss,SkRegion::Op op,bool invert,bool doAA,const SkMatrix & viewMatrix,const SkRect & rect)600 bool GrDrawContextPriv::drawAndStencilRect(const GrClip& clip,
601 const GrUserStencilSettings* ss,
602 SkRegion::Op op,
603 bool invert,
604 bool doAA,
605 const SkMatrix& viewMatrix,
606 const SkRect& rect) {
607 ASSERT_SINGLE_OWNER_PRIV
608 RETURN_FALSE_IF_ABANDONED_PRIV
609 SkDEBUGCODE(fDrawContext->validate();)
610 GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContext::drawAndStencilRect");
611
612 AutoCheckFlush acf(fDrawContext->fDrawingManager);
613
614 GrPaint paint;
615 paint.setAntiAlias(doAA);
616 paint.setCoverageSetOpXPFactory(op, invert);
617
618 if (fDrawContext->drawFilledRect(clip, paint, viewMatrix, rect, ss)) {
619 return true;
620 }
621
622 SkPath path;
623 path.setIsVolatile(true);
624 path.addRect(rect);
625 return this->drawAndStencilPath(clip, ss, op, invert, doAA, viewMatrix, path);
626 }
627
fillRectToRect(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & rectToDraw,const SkRect & localRect)628 void GrDrawContext::fillRectToRect(const GrClip& clip,
629 const GrPaint& paint,
630 const SkMatrix& viewMatrix,
631 const SkRect& rectToDraw,
632 const SkRect& localRect) {
633 ASSERT_SINGLE_OWNER
634 RETURN_IF_ABANDONED
635 SkDEBUGCODE(this->validate();)
636 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectToRect");
637
638 SkRect croppedRect = rectToDraw;
639 SkRect croppedLocalRect = localRect;
640 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix,
641 &croppedRect, &croppedLocalRect)) {
642 return;
643 }
644
645 AutoCheckFlush acf(fDrawingManager);
646 bool useHWAA;
647
648 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
649 InstancedRendering* ir = this->getDrawTarget()->instancedRendering();
650 SkAutoTUnref<GrDrawBatch> batch(ir->recordRect(croppedRect, viewMatrix, paint.getColor(),
651 croppedLocalRect, paint.isAntiAlias(),
652 fInstancedPipelineInfo, &useHWAA));
653 if (batch) {
654 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
655 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
656 return;
657 }
658 }
659
660 if (!should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) {
661 this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, &croppedLocalRect,
662 nullptr, nullptr, useHWAA);
663 return;
664 }
665
666 if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
667 SkAutoTUnref<GrDrawBatch> batch(GrAAFillRectBatch::CreateWithLocalRect(paint.getColor(),
668 viewMatrix,
669 croppedRect,
670 croppedLocalRect));
671 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
672 this->drawBatch(pipelineBuilder, clip, batch);
673 return;
674 }
675
676 SkMatrix viewAndUnLocalMatrix;
677 if (!viewAndUnLocalMatrix.setRectToRect(localRect, rectToDraw, SkMatrix::kFill_ScaleToFit)) {
678 SkDebugf("fillRectToRect called with empty local matrix.\n");
679 return;
680 }
681 viewAndUnLocalMatrix.postConcat(viewMatrix);
682
683 SkPath path;
684 path.setIsVolatile(true);
685 path.addRect(localRect);
686 this->internalDrawPath(clip, paint, viewAndUnLocalMatrix, path, GrStyle());
687 }
688
fillRectWithLocalMatrix(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & rectToDraw,const SkMatrix & localMatrix)689 void GrDrawContext::fillRectWithLocalMatrix(const GrClip& clip,
690 const GrPaint& paint,
691 const SkMatrix& viewMatrix,
692 const SkRect& rectToDraw,
693 const SkMatrix& localMatrix) {
694 ASSERT_SINGLE_OWNER
695 RETURN_IF_ABANDONED
696 SkDEBUGCODE(this->validate();)
697 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::fillRectWithLocalMatrix");
698
699 SkRect croppedRect = rectToDraw;
700 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
701 return;
702 }
703
704 AutoCheckFlush acf(fDrawingManager);
705 bool useHWAA;
706
707 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
708 InstancedRendering* ir = this->getDrawTarget()->instancedRendering();
709 SkAutoTUnref<GrDrawBatch> batch(ir->recordRect(croppedRect, viewMatrix, paint.getColor(),
710 localMatrix, paint.isAntiAlias(),
711 fInstancedPipelineInfo, &useHWAA));
712 if (batch) {
713 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
714 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
715 return;
716 }
717 }
718
719 if (!should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) {
720 this->drawNonAAFilledRect(clip, paint, viewMatrix, croppedRect, nullptr,
721 &localMatrix, nullptr, useHWAA);
722 return;
723 }
724
725 if (view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
726 SkAutoTUnref<GrDrawBatch> batch(GrAAFillRectBatch::Create(paint.getColor(), viewMatrix,
727 localMatrix, croppedRect));
728 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
729 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
730 return;
731 }
732
733 SkMatrix viewAndUnLocalMatrix;
734 if (!localMatrix.invert(&viewAndUnLocalMatrix)) {
735 SkDebugf("fillRectWithLocalMatrix called with degenerate local matrix.\n");
736 return;
737 }
738 viewAndUnLocalMatrix.postConcat(viewMatrix);
739
740 SkPath path;
741 path.setIsVolatile(true);
742 path.addRect(rectToDraw);
743 path.transform(localMatrix);
744 this->internalDrawPath(clip, paint, viewAndUnLocalMatrix, path, GrStyle());
745 }
746
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)747 void GrDrawContext::drawVertices(const GrClip& clip,
748 const GrPaint& paint,
749 const SkMatrix& viewMatrix,
750 GrPrimitiveType primitiveType,
751 int vertexCount,
752 const SkPoint positions[],
753 const SkPoint texCoords[],
754 const GrColor colors[],
755 const uint16_t indices[],
756 int indexCount) {
757 ASSERT_SINGLE_OWNER
758 RETURN_IF_ABANDONED
759 SkDEBUGCODE(this->validate();)
760 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawVertices");
761
762 AutoCheckFlush acf(fDrawingManager);
763
764 // TODO clients should give us bounds
765 SkRect bounds;
766 if (!bounds.setBoundsCheck(positions, vertexCount)) {
767 SkDebugf("drawVertices call empty bounds\n");
768 return;
769 }
770
771 viewMatrix.mapRect(&bounds);
772
773 SkAutoTUnref<GrDrawBatch> batch(new GrDrawVerticesBatch(paint.getColor(),
774 primitiveType, viewMatrix, positions,
775 vertexCount, indices, indexCount,
776 colors, texCoords, bounds));
777
778 GrPipelineBuilder pipelineBuilder(paint, this->mustUseHWAA(paint));
779 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
780 }
781
782 ///////////////////////////////////////////////////////////////////////////////
783
drawAtlas(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,int spriteCount,const SkRSXform xform[],const SkRect texRect[],const SkColor colors[])784 void GrDrawContext::drawAtlas(const GrClip& clip,
785 const GrPaint& paint,
786 const SkMatrix& viewMatrix,
787 int spriteCount,
788 const SkRSXform xform[],
789 const SkRect texRect[],
790 const SkColor colors[]) {
791 ASSERT_SINGLE_OWNER
792 RETURN_IF_ABANDONED
793 SkDEBUGCODE(this->validate();)
794 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawAtlas");
795
796 AutoCheckFlush acf(fDrawingManager);
797
798 SkAutoTUnref<GrDrawBatch> batch(new GrDrawAtlasBatch(paint.getColor(), viewMatrix, spriteCount,
799 xform, texRect, colors));
800
801 GrPipelineBuilder pipelineBuilder(paint, this->mustUseHWAA(paint));
802 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
803 }
804
805 ///////////////////////////////////////////////////////////////////////////////
806
drawRRect(const GrClip & origClip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRRect & rrect,const GrStyle & style)807 void GrDrawContext::drawRRect(const GrClip& origClip,
808 const GrPaint& paint,
809 const SkMatrix& viewMatrix,
810 const SkRRect& rrect,
811 const GrStyle& style) {
812 ASSERT_SINGLE_OWNER
813 RETURN_IF_ABANDONED
814 SkDEBUGCODE(this->validate();)
815 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRRect");
816 if (rrect.isEmpty()) {
817 return;
818 }
819
820 GrNoClip noclip;
821 const GrClip* clip = &origClip;
822 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
823 // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
824 // draw is aa. Since our lower level clip code works from batch bounds, which are SkRects, it
825 // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
826 // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
827 // can be ignored. We'd prefer to fix this in the framework by removing the clips calls.
828 SkRRect devRRect;
829 if (rrect.transform(viewMatrix, &devRRect) && clip->quickContains(devRRect)) {
830 clip = &noclip;
831 }
832 #endif
833 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
834
835 AutoCheckFlush acf(fDrawingManager);
836 const SkStrokeRec stroke = style.strokeRec();
837 bool useHWAA;
838
839 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() &&
840 stroke.isFillStyle()) {
841 InstancedRendering* ir = this->getDrawTarget()->instancedRendering();
842 SkAutoTUnref<GrDrawBatch> batch(ir->recordRRect(rrect, viewMatrix, paint.getColor(),
843 paint.isAntiAlias(), fInstancedPipelineInfo,
844 &useHWAA));
845 if (batch) {
846 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
847 this->getDrawTarget()->drawBatch(pipelineBuilder, this, *clip, batch);
848 return;
849 }
850 }
851
852 if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) {
853 GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
854 SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateRRectBatch(paint.getColor(),
855 viewMatrix,
856 rrect,
857 stroke,
858 shaderCaps));
859 if (batch) {
860 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
861 this->getDrawTarget()->drawBatch(pipelineBuilder, this, *clip, batch);
862 return;
863 }
864 }
865
866 SkPath path;
867 path.setIsVolatile(true);
868 path.addRRect(rrect);
869 this->internalDrawPath(*clip, paint, viewMatrix, path, style);
870 }
871
drawFilledDRRect(const GrClip & clip,const GrPaint & paintIn,const SkMatrix & viewMatrix,const SkRRect & origOuter,const SkRRect & origInner)872 bool GrDrawContext::drawFilledDRRect(const GrClip& clip,
873 const GrPaint& paintIn,
874 const SkMatrix& viewMatrix,
875 const SkRRect& origOuter,
876 const SkRRect& origInner) {
877 SkASSERT(!origInner.isEmpty());
878 SkASSERT(!origOuter.isEmpty());
879
880 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport()) {
881 bool useHWAA;
882 InstancedRendering* ir = this->getDrawTarget()->instancedRendering();
883 SkAutoTUnref<GrDrawBatch> batch(ir->recordDRRect(origOuter, origInner, viewMatrix,
884 paintIn.getColor(), paintIn.isAntiAlias(),
885 fInstancedPipelineInfo, &useHWAA));
886 if (batch) {
887 GrPipelineBuilder pipelineBuilder(paintIn, useHWAA);
888 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
889 return true;
890 }
891 }
892
893 bool applyAA = paintIn.isAntiAlias() && !fRenderTarget->isUnifiedMultisampled();
894
895 GrPrimitiveEdgeType innerEdgeType = applyAA ? kInverseFillAA_GrProcessorEdgeType :
896 kInverseFillBW_GrProcessorEdgeType;
897 GrPrimitiveEdgeType outerEdgeType = applyAA ? kFillAA_GrProcessorEdgeType :
898 kFillBW_GrProcessorEdgeType;
899
900 SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
901 SkMatrix inverseVM;
902 if (!viewMatrix.isIdentity()) {
903 if (!origInner.transform(viewMatrix, inner.writable())) {
904 return false;
905 }
906 if (!origOuter.transform(viewMatrix, outer.writable())) {
907 return false;
908 }
909 if (!viewMatrix.invert(&inverseVM)) {
910 return false;
911 }
912 } else {
913 inverseVM.reset();
914 }
915
916 GrPaint grPaint(paintIn);
917 grPaint.setAntiAlias(false);
918
919 // TODO these need to be a geometry processors
920 sk_sp<GrFragmentProcessor> innerEffect(GrRRectEffect::Make(innerEdgeType, *inner));
921 if (!innerEffect) {
922 return false;
923 }
924
925 sk_sp<GrFragmentProcessor> outerEffect(GrRRectEffect::Make(outerEdgeType, *outer));
926 if (!outerEffect) {
927 return false;
928 }
929
930 grPaint.addCoverageFragmentProcessor(std::move(innerEffect));
931 grPaint.addCoverageFragmentProcessor(std::move(outerEffect));
932
933 SkRect bounds = outer->getBounds();
934 if (applyAA) {
935 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
936 }
937
938 this->fillRectWithLocalMatrix(clip, grPaint, SkMatrix::I(), bounds, inverseVM);
939 return true;
940 }
941
drawDRRect(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRRect & outer,const SkRRect & inner)942 void GrDrawContext::drawDRRect(const GrClip& clip,
943 const GrPaint& paint,
944 const SkMatrix& viewMatrix,
945 const SkRRect& outer,
946 const SkRRect& inner) {
947 ASSERT_SINGLE_OWNER
948 RETURN_IF_ABANDONED
949 SkDEBUGCODE(this->validate();)
950 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawDRRect");
951
952 SkASSERT(!outer.isEmpty());
953 SkASSERT(!inner.isEmpty());
954
955 AutoCheckFlush acf(fDrawingManager);
956
957 if (this->drawFilledDRRect(clip, paint, viewMatrix, outer, inner)) {
958 return;
959 }
960
961 SkPath path;
962 path.setIsVolatile(true);
963 path.addRRect(inner);
964 path.addRRect(outer);
965 path.setFillType(SkPath::kEvenOdd_FillType);
966
967 this->internalDrawPath(clip, paint, viewMatrix, path, GrStyle::SimpleFill());
968 }
969
970 ///////////////////////////////////////////////////////////////////////////////
971
is_int(float x)972 static inline bool is_int(float x) {
973 return x == (float) sk_float_round2int(x);
974 }
975
drawRegion(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRegion & region,const GrStyle & style)976 void GrDrawContext::drawRegion(const GrClip& clip,
977 const GrPaint& paint,
978 const SkMatrix& viewMatrix,
979 const SkRegion& region,
980 const GrStyle& style) {
981 ASSERT_SINGLE_OWNER
982 RETURN_IF_ABANDONED
983 SkDEBUGCODE(this->validate();)
984 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawRegion");
985
986 bool isNonTranslate = SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask));
987 bool complexStyle = !style.isSimpleFill();
988 bool antiAlias = paint.isAntiAlias() && (!is_int(viewMatrix.getTranslateX()) ||
989 !is_int(viewMatrix.getTranslateY()));
990 if (isNonTranslate || complexStyle || antiAlias) {
991 SkPath path;
992 region.getBoundaryPath(&path);
993 return this->drawPath(clip, paint, viewMatrix, path, style);
994 }
995
996 SkAutoTUnref<GrDrawBatch> batch(GrRegionBatch::Create(paint.getColor(), viewMatrix, region));
997 GrPipelineBuilder pipelineBuilder(paint, false);
998 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
999 }
1000
drawOval(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & oval,const GrStyle & style)1001 void GrDrawContext::drawOval(const GrClip& clip,
1002 const GrPaint& paint,
1003 const SkMatrix& viewMatrix,
1004 const SkRect& oval,
1005 const GrStyle& style) {
1006 ASSERT_SINGLE_OWNER
1007 RETURN_IF_ABANDONED
1008 SkDEBUGCODE(this->validate();)
1009 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawOval");
1010
1011 if (oval.isEmpty()) {
1012 return;
1013 }
1014
1015 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
1016
1017 AutoCheckFlush acf(fDrawingManager);
1018 const SkStrokeRec& stroke = style.strokeRec();
1019 bool useHWAA;
1020
1021 if (GrCaps::InstancedSupport::kNone != fContext->caps()->instancedSupport() &&
1022 stroke.isFillStyle()) {
1023 InstancedRendering* ir = this->getDrawTarget()->instancedRendering();
1024 SkAutoTUnref<GrDrawBatch> batch(ir->recordOval(oval, viewMatrix, paint.getColor(),
1025 paint.isAntiAlias(), fInstancedPipelineInfo,
1026 &useHWAA));
1027 if (batch) {
1028 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
1029 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
1030 return;
1031 }
1032 }
1033
1034 if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) {
1035 GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
1036 SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(paint.getColor(),
1037 viewMatrix,
1038 oval,
1039 stroke,
1040 shaderCaps));
1041 if (batch) {
1042 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
1043 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
1044 return;
1045 }
1046 }
1047
1048 SkPath path;
1049 path.setIsVolatile(true);
1050 path.addOval(oval);
1051 this->internalDrawPath(clip, paint, viewMatrix, path, style);
1052 }
1053
drawArc(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const GrStyle & style)1054 void GrDrawContext::drawArc(const GrClip& clip,
1055 const GrPaint& paint,
1056 const SkMatrix& viewMatrix,
1057 const SkRect& oval,
1058 SkScalar startAngle,
1059 SkScalar sweepAngle,
1060 bool useCenter,
1061 const GrStyle& style) {
1062 bool useHWAA;
1063 if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA)) {
1064 GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
1065 SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateArcBatch(paint.getColor(),
1066 viewMatrix,
1067 oval,
1068 startAngle,
1069 sweepAngle,
1070 useCenter,
1071 style,
1072 shaderCaps));
1073 if (batch) {
1074 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
1075 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
1076 return;
1077 }
1078 }
1079 SkPath path;
1080 SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter,
1081 style.isSimpleFill());
1082 this->internalDrawPath(clip, paint, viewMatrix, path, style);
1083 return;
1084 }
1085
drawImageLattice(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,int imageWidth,int imageHeight,std::unique_ptr<SkLatticeIter> iter,const SkRect & dst)1086 void GrDrawContext::drawImageLattice(const GrClip& clip,
1087 const GrPaint& paint,
1088 const SkMatrix& viewMatrix,
1089 int imageWidth,
1090 int imageHeight,
1091 std::unique_ptr<SkLatticeIter> iter,
1092 const SkRect& dst) {
1093 ASSERT_SINGLE_OWNER
1094 RETURN_IF_ABANDONED
1095 SkDEBUGCODE(this->validate();)
1096 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawImageLattice");
1097
1098 AutoCheckFlush acf(fDrawingManager);
1099
1100 SkAutoTUnref<GrDrawBatch> batch(GrNinePatch::CreateNonAA(paint.getColor(), viewMatrix,
1101 imageWidth, imageHeight,
1102 std::move(iter), dst));
1103
1104 GrPipelineBuilder pipelineBuilder(paint, this->mustUseHWAA(paint));
1105 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
1106 }
1107
prepareForExternalIO()1108 void GrDrawContext::prepareForExternalIO() {
1109 ASSERT_SINGLE_OWNER
1110 RETURN_IF_ABANDONED
1111 SkDEBUGCODE(this->validate();)
1112 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::prepareForExternalIO");
1113
1114 ASSERT_OWNED_RESOURCE(fRenderTarget);
1115
1116 fDrawingManager->prepareSurfaceForExternalIO(fRenderTarget.get());
1117 }
1118
drawNonAAFilledRect(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect,const SkMatrix * localMatrix,const GrUserStencilSettings * ss,bool useHWAA)1119 void GrDrawContext::drawNonAAFilledRect(const GrClip& clip,
1120 const GrPaint& paint,
1121 const SkMatrix& viewMatrix,
1122 const SkRect& rect,
1123 const SkRect* localRect,
1124 const SkMatrix* localMatrix,
1125 const GrUserStencilSettings* ss,
1126 bool useHWAA) {
1127 SkASSERT(!useHWAA || this->isStencilBufferMultisampled());
1128 SkAutoTUnref<GrDrawBatch> batch(
1129 GrRectBatchFactory::CreateNonAAFill(paint.getColor(), viewMatrix, rect, localRect,
1130 localMatrix));
1131 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
1132 if (ss) {
1133 pipelineBuilder.setUserStencil(ss);
1134 }
1135 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
1136 }
1137
readPixels(const SkImageInfo & dstInfo,void * dstBuffer,size_t dstRowBytes,int x,int y)1138 bool GrDrawContext::readPixels(const SkImageInfo& dstInfo, void* dstBuffer, size_t dstRowBytes,
1139 int x, int y) {
1140 // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
1141 GrPixelConfig config = SkImageInfo2GrPixelConfig(dstInfo, *fContext->caps());
1142 if (kUnknown_GrPixelConfig == config) {
1143 return false;
1144 }
1145
1146 uint32_t flags = 0;
1147 if (kUnpremul_SkAlphaType == dstInfo.alphaType()) {
1148 flags = GrContext::kUnpremul_PixelOpsFlag;
1149 }
1150
1151 return fRenderTarget->readPixels(x, y, dstInfo.width(), dstInfo.height(),
1152 config, dstBuffer, dstRowBytes, flags);
1153 }
1154
writePixels(const SkImageInfo & srcInfo,const void * srcBuffer,size_t srcRowBytes,int x,int y)1155 bool GrDrawContext::writePixels(const SkImageInfo& srcInfo, const void* srcBuffer,
1156 size_t srcRowBytes, int x, int y) {
1157 // TODO: teach fRenderTarget to take ImageInfo directly to specify the src pixels
1158 GrPixelConfig config = SkImageInfo2GrPixelConfig(srcInfo, *fContext->caps());
1159 if (kUnknown_GrPixelConfig == config) {
1160 return false;
1161 }
1162 uint32_t flags = 0;
1163 if (kUnpremul_SkAlphaType == srcInfo.alphaType()) {
1164 flags = GrContext::kUnpremul_PixelOpsFlag;
1165 }
1166
1167 return fRenderTarget->writePixels(x, y, srcInfo.width(), srcInfo.height(),
1168 config, srcBuffer, srcRowBytes, flags);
1169 }
1170
1171 // Can 'path' be drawn as a pair of filled nested rectangles?
fills_as_nested_rects(const SkMatrix & viewMatrix,const SkPath & path,SkRect rects[2])1172 static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) {
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.rectStaysRect()) {
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(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkPath & path,const GrStyle & style)1217 void GrDrawContext::drawPath(const GrClip& clip,
1218 const GrPaint& paint,
1219 const SkMatrix& viewMatrix,
1220 const SkPath& path,
1221 const GrStyle& style) {
1222 ASSERT_SINGLE_OWNER
1223 RETURN_IF_ABANDONED
1224 SkDEBUGCODE(this->validate();)
1225 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawPath");
1226
1227 if (path.isEmpty()) {
1228 if (path.isInverseFillType()) {
1229 this->drawPaint(clip, paint, viewMatrix);
1230 }
1231 return;
1232 }
1233
1234 AutoCheckFlush acf(fDrawingManager);
1235
1236 bool useHWAA;
1237 if (should_apply_coverage_aa(paint, fRenderTarget.get(), &useHWAA) && !style.pathEffect()) {
1238 if (style.isSimpleFill() && !path.isConvex()) {
1239 // Concave AA paths are expensive - try to avoid them for special cases
1240 SkRect rects[2];
1241
1242 if (fills_as_nested_rects(viewMatrix, path, rects)) {
1243 SkAutoTUnref<GrDrawBatch> batch(GrRectBatchFactory::CreateAAFillNestedRects(
1244 paint.getColor(), viewMatrix, rects));
1245 if (batch) {
1246 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
1247 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
1248 }
1249 return;
1250 }
1251 }
1252 SkRect ovalRect;
1253 bool isOval = path.isOval(&ovalRect);
1254
1255 if (isOval && !path.isInverseFillType()) {
1256 GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
1257 SkAutoTUnref<GrDrawBatch> batch(GrOvalRenderer::CreateOvalBatch(paint.getColor(),
1258 viewMatrix,
1259 ovalRect,
1260 style.strokeRec(),
1261 shaderCaps));
1262 if (batch) {
1263 GrPipelineBuilder pipelineBuilder(paint, useHWAA);
1264 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
1265 return;
1266 }
1267 }
1268 }
1269
1270 // Note that internalDrawPath may sw-rasterize the path into a scratch texture.
1271 // Scratch textures can be recycled after they are returned to the texture
1272 // cache. This presents a potential hazard for buffered drawing. However,
1273 // the writePixels that uploads to the scratch will perform a flush so we're
1274 // OK.
1275 this->internalDrawPath(clip, paint, viewMatrix, path, style);
1276 }
1277
drawAndStencilPath(const GrClip & clip,const GrUserStencilSettings * ss,SkRegion::Op op,bool invert,bool doAA,const SkMatrix & viewMatrix,const SkPath & path)1278 bool GrDrawContextPriv::drawAndStencilPath(const GrClip& clip,
1279 const GrUserStencilSettings* ss,
1280 SkRegion::Op op,
1281 bool invert,
1282 bool doAA,
1283 const SkMatrix& viewMatrix,
1284 const SkPath& path) {
1285 ASSERT_SINGLE_OWNER_PRIV
1286 RETURN_FALSE_IF_ABANDONED_PRIV
1287 SkDEBUGCODE(fDrawContext->validate();)
1288 GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContext::drawPath");
1289
1290 if (path.isEmpty() && path.isInverseFillType()) {
1291 this->drawAndStencilRect(clip, ss, op, invert, false, SkMatrix::I(),
1292 SkRect::MakeIWH(fDrawContext->width(),
1293 fDrawContext->height()));
1294 return true;
1295 }
1296
1297 AutoCheckFlush acf(fDrawContext->fDrawingManager);
1298
1299 // An Assumption here is that path renderer would use some form of tweaking
1300 // the src color (either the input alpha or in the frag shader) to implement
1301 // aa. If we have some future driver-mojo path AA that can do the right
1302 // thing WRT to the blend then we'll need some query on the PR.
1303 bool useCoverageAA = doAA && !fDrawContext->isUnifiedMultisampled();
1304 bool hasUserStencilSettings = !ss->isUnused();
1305 bool isStencilBufferMSAA = fDrawContext->isStencilBufferMultisampled();
1306
1307 const GrPathRendererChain::DrawType type =
1308 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType
1309 : GrPathRendererChain::kColor_DrawType;
1310
1311 GrShape shape(path, GrStyle::SimpleFill());
1312 GrPathRenderer::CanDrawPathArgs canDrawArgs;
1313 canDrawArgs.fShaderCaps = fDrawContext->fDrawingManager->getContext()->caps()->shaderCaps();
1314 canDrawArgs.fViewMatrix = &viewMatrix;
1315 canDrawArgs.fShape = &shape;
1316 canDrawArgs.fAntiAlias = useCoverageAA;
1317 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
1318 canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
1319
1320 // Don't allow the SW renderer
1321 GrPathRenderer* pr = fDrawContext->fDrawingManager->getPathRenderer(canDrawArgs, false, type);
1322 if (!pr) {
1323 return false;
1324 }
1325
1326 GrPaint paint;
1327 paint.setCoverageSetOpXPFactory(op, invert);
1328
1329 GrPathRenderer::DrawPathArgs args;
1330 args.fResourceProvider = fDrawContext->fDrawingManager->getContext()->resourceProvider();
1331 args.fPaint = &paint;
1332 args.fUserStencilSettings = ss;
1333 args.fDrawContext = fDrawContext;
1334 args.fClip = &clip;
1335 args.fViewMatrix = &viewMatrix;
1336 args.fShape = &shape;
1337 args.fAntiAlias = useCoverageAA;
1338 args.fGammaCorrect = fDrawContext->isGammaCorrect();
1339 pr->drawPath(args);
1340 return true;
1341 }
1342
isBudgeted() const1343 SkBudgeted GrDrawContextPriv::isBudgeted() const {
1344 ASSERT_SINGLE_OWNER_PRIV
1345
1346 if (fDrawContext->wasAbandoned()) {
1347 return SkBudgeted::kNo;
1348 }
1349
1350 SkDEBUGCODE(fDrawContext->validate();)
1351
1352 return fDrawContext->fRenderTarget->resourcePriv().isBudgeted();
1353 }
1354
internalDrawPath(const GrClip & clip,const GrPaint & paint,const SkMatrix & viewMatrix,const SkPath & path,const GrStyle & style)1355 void GrDrawContext::internalDrawPath(const GrClip& clip,
1356 const GrPaint& paint,
1357 const SkMatrix& viewMatrix,
1358 const SkPath& path,
1359 const GrStyle& style) {
1360 ASSERT_SINGLE_OWNER
1361 RETURN_IF_ABANDONED
1362 SkASSERT(!path.isEmpty());
1363
1364 bool useCoverageAA = should_apply_coverage_aa(paint, fRenderTarget.get());
1365 constexpr bool kHasUserStencilSettings = false;
1366 bool isStencilBufferMSAA = this->isStencilBufferMultisampled();
1367
1368 const GrPathRendererChain::DrawType type =
1369 useCoverageAA ? GrPathRendererChain::kColorAntiAlias_DrawType
1370 : GrPathRendererChain::kColor_DrawType;
1371
1372 GrShape shape(path, style);
1373 if (shape.isEmpty()) {
1374 return;
1375 }
1376 GrPathRenderer::CanDrawPathArgs canDrawArgs;
1377 canDrawArgs.fShaderCaps = fDrawingManager->getContext()->caps()->shaderCaps();
1378 canDrawArgs.fViewMatrix = &viewMatrix;
1379 canDrawArgs.fShape = &shape;
1380 canDrawArgs.fAntiAlias = useCoverageAA;
1381 canDrawArgs.fHasUserStencilSettings = kHasUserStencilSettings;
1382 canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
1383
1384 // Try a 1st time without applying any of the style to the geometry (and barring sw)
1385 GrPathRenderer* pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
1386 SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
1387
1388 if (!pr && shape.style().pathEffect()) {
1389 // It didn't work above, so try again with the path effect applied.
1390 shape = shape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
1391 if (shape.isEmpty()) {
1392 return;
1393 }
1394 pr = fDrawingManager->getPathRenderer(canDrawArgs, false, type);
1395 }
1396 if (!pr) {
1397 if (shape.style().applies()) {
1398 shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, styleScale);
1399 if (shape.isEmpty()) {
1400 return;
1401 }
1402 }
1403 // This time, allow SW renderer
1404 pr = fDrawingManager->getPathRenderer(canDrawArgs, true, type);
1405 }
1406
1407 if (!pr) {
1408 #ifdef SK_DEBUG
1409 SkDebugf("Unable to find path renderer compatible with path.\n");
1410 #endif
1411 return;
1412 }
1413
1414 GrPathRenderer::DrawPathArgs args;
1415 args.fResourceProvider = fDrawingManager->getContext()->resourceProvider();
1416 args.fPaint = &paint;
1417 args.fUserStencilSettings = &GrUserStencilSettings::kUnused;
1418 args.fDrawContext = this;
1419 args.fClip = &clip;
1420 args.fViewMatrix = &viewMatrix;
1421 args.fShape = canDrawArgs.fShape;
1422 args.fAntiAlias = useCoverageAA;
1423 args.fGammaCorrect = this->isGammaCorrect();
1424 pr->drawPath(args);
1425 }
1426
drawBatch(const GrPipelineBuilder & pipelineBuilder,const GrClip & clip,GrDrawBatch * batch)1427 void GrDrawContext::drawBatch(const GrPipelineBuilder& pipelineBuilder, const GrClip& clip,
1428 GrDrawBatch* batch) {
1429 ASSERT_SINGLE_OWNER
1430 RETURN_IF_ABANDONED
1431 SkDEBUGCODE(this->validate();)
1432 GR_AUDIT_TRAIL_AUTO_FRAME(fAuditTrail, "GrDrawContext::drawBatch");
1433
1434 this->getDrawTarget()->drawBatch(pipelineBuilder, this, clip, batch);
1435 }
1436