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 "GrRenderTargetContext.h"
9 #include "../private/GrAuditTrail.h"
10 #include "../private/SkShadowFlags.h"
11 #include "GrAppliedClip.h"
12 #include "GrBackendSemaphore.h"
13 #include "GrBlurUtils.h"
14 #include "GrColor.h"
15 #include "GrContextPriv.h"
16 #include "GrDrawingManager.h"
17 #include "GrFixedClip.h"
18 #include "GrGpuResourcePriv.h"
19 #include "GrOpList.h"
20 #include "GrPathRenderer.h"
21 #include "GrQuad.h"
22 #include "GrRenderTarget.h"
23 #include "GrRenderTargetContextPriv.h"
24 #include "GrResourceProvider.h"
25 #include "GrStencilAttachment.h"
26 #include "GrTracing.h"
27 #include "SkDrawShadowInfo.h"
28 #include "SkGr.h"
29 #include "SkLatticeIter.h"
30 #include "SkMatrixPriv.h"
31 #include "SkShadowUtils.h"
32 #include "SkSurfacePriv.h"
33 #include "effects/GrRRectEffect.h"
34 #include "ops/GrAtlasTextOp.h"
35 #include "ops/GrClearOp.h"
36 #include "ops/GrClearStencilClipOp.h"
37 #include "ops/GrDebugMarkerOp.h"
38 #include "ops/GrDrawAtlasOp.h"
39 #include "ops/GrDrawOp.h"
40 #include "ops/GrDrawVerticesOp.h"
41 #include "ops/GrLatticeOp.h"
42 #include "ops/GrOp.h"
43 #include "ops/GrOvalOpFactory.h"
44 #include "ops/GrRectOpFactory.h"
45 #include "ops/GrRegionOp.h"
46 #include "ops/GrSemaphoreOp.h"
47 #include "ops/GrShadowRRectOp.h"
48 #include "ops/GrStencilPathOp.h"
49 #include "ops/GrTextureOp.h"
50 #include "text/GrAtlasTextContext.h"
51 #include "text/GrStencilAndCoverTextContext.h"
52 #include "text/GrTextUtils.h"
53
54 class GrRenderTargetContext::TextTarget : public GrTextUtils::Target {
55 public:
TextTarget(GrRenderTargetContext * renderTargetContext)56 TextTarget(GrRenderTargetContext* renderTargetContext)
57 : Target(renderTargetContext->width(), renderTargetContext->height(),
58 renderTargetContext->colorSpaceInfo())
59 , fRenderTargetContext(renderTargetContext) {}
60
addDrawOp(const GrClip & clip,std::unique_ptr<GrAtlasTextOp> op)61 void addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) {
62 fRenderTargetContext->addDrawOp(clip, std::move(op));
63 }
64
drawPath(const GrClip & clip,const SkPath & path,const SkPaint & paint,const SkMatrix & viewMatrix,const SkMatrix * pathMatrix,const SkIRect & clipBounds)65 void drawPath(const GrClip& clip, const SkPath& path, const SkPaint& paint,
66 const SkMatrix& viewMatrix, const SkMatrix* pathMatrix,
67 const SkIRect& clipBounds) {
68 GrBlurUtils::drawPathWithMaskFilter(fRenderTargetContext->fContext, fRenderTargetContext,
69 clip, path, paint, viewMatrix, pathMatrix, clipBounds,
70 false);
71 }
72
makeGrPaint(GrMaskFormat maskFormat,const SkPaint & skPaint,const SkMatrix & viewMatrix,GrPaint * grPaint)73 void makeGrPaint(GrMaskFormat maskFormat, const SkPaint& skPaint, const SkMatrix& viewMatrix,
74 GrPaint* grPaint) {
75 GrContext* context = fRenderTargetContext->fContext;
76 const GrColorSpaceInfo& colorSpaceInfo = fRenderTargetContext->colorSpaceInfo();
77 if (kARGB_GrMaskFormat == maskFormat) {
78 SkPaintToGrPaintWithPrimitiveColor(context, colorSpaceInfo, skPaint, grPaint);
79 } else {
80 SkPaintToGrPaint(context, colorSpaceInfo, skPaint, viewMatrix, grPaint);
81 }
82 }
83
84 private:
85 GrRenderTargetContext* fRenderTargetContext;
86 };
87
88 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
89 #define ASSERT_SINGLE_OWNER \
90 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
91 #define ASSERT_SINGLE_OWNER_PRIV \
92 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
93 #define RETURN_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return; }
94 #define RETURN_IF_ABANDONED_PRIV if (fRenderTargetContext->drawingManager()->wasAbandoned()) { return; }
95 #define RETURN_FALSE_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return false; }
96 #define RETURN_FALSE_IF_ABANDONED_PRIV if (fRenderTargetContext->drawingManager()->wasAbandoned()) { return false; }
97 #define RETURN_NULL_IF_ABANDONED if (this->drawingManager()->wasAbandoned()) { return nullptr; }
98
99 //////////////////////////////////////////////////////////////////////////////
100
GrChooseAAType(GrAA aa,GrFSAAType fsaaType,GrAllowMixedSamples allowMixedSamples,const GrCaps & caps)101 GrAAType GrChooseAAType(GrAA aa, GrFSAAType fsaaType, GrAllowMixedSamples allowMixedSamples,
102 const GrCaps& caps) {
103 if (GrAA::kNo == aa) {
104 // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
105 // that.
106 if (fsaaType == GrFSAAType::kUnifiedMSAA && !caps.multisampleDisableSupport()) {
107 return GrAAType::kMSAA;
108 }
109 return GrAAType::kNone;
110 }
111 switch (fsaaType) {
112 case GrFSAAType::kNone:
113 return GrAAType::kCoverage;
114 case GrFSAAType::kUnifiedMSAA:
115 return GrAAType::kMSAA;
116 case GrFSAAType::kMixedSamples:
117 return GrAllowMixedSamples::kYes == allowMixedSamples ? GrAAType::kMixedSamples
118 : GrAAType::kCoverage;
119 }
120 SK_ABORT("Unexpected fsaa type");
121 return GrAAType::kNone;
122 }
123
124 //////////////////////////////////////////////////////////////////////////////
125
126 class AutoCheckFlush {
127 public:
AutoCheckFlush(GrDrawingManager * drawingManager)128 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
129 SkASSERT(fDrawingManager);
130 }
~AutoCheckFlush()131 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
132
133 private:
134 GrDrawingManager* fDrawingManager;
135 };
136
wasAbandoned() const137 bool GrRenderTargetContext::wasAbandoned() const {
138 return this->drawingManager()->wasAbandoned();
139 }
140
141 // In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress
142 // GrOpLists to be picked up and added to by renderTargetContexts lower in the call
143 // stack. When this occurs with a closed GrOpList, a new one will be allocated
144 // when the renderTargetContext attempts to use it (via getOpList).
GrRenderTargetContext(GrContext * context,GrDrawingManager * drawingMgr,sk_sp<GrRenderTargetProxy> rtp,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps,GrAuditTrail * auditTrail,GrSingleOwner * singleOwner,bool managedOpList)145 GrRenderTargetContext::GrRenderTargetContext(GrContext* context,
146 GrDrawingManager* drawingMgr,
147 sk_sp<GrRenderTargetProxy> rtp,
148 sk_sp<SkColorSpace> colorSpace,
149 const SkSurfaceProps* surfaceProps,
150 GrAuditTrail* auditTrail,
151 GrSingleOwner* singleOwner,
152 bool managedOpList)
153 : GrSurfaceContext(context, drawingMgr, rtp->config(), std::move(colorSpace), auditTrail,
154 singleOwner)
155 , fRenderTargetProxy(std::move(rtp))
156 , fOpList(sk_ref_sp(fRenderTargetProxy->getLastRenderTargetOpList()))
157 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
158 , fManagedOpList(managedOpList) {
159 #ifdef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION
160 // MDB TODO: to ensure all resources still get allocated in the correct order in the hybrid
161 // world we need to get the correct opList here so that it, in turn, can grab and hold
162 // its rendertarget.
163 this->getRTOpList();
164 #endif
165 fTextTarget.reset(new TextTarget(this));
166 SkDEBUGCODE(this->validate();)
167 }
168
169 #ifdef SK_DEBUG
validate() const170 void GrRenderTargetContext::validate() const {
171 SkASSERT(fRenderTargetProxy);
172 fRenderTargetProxy->validate(fContext);
173
174 if (fOpList && !fOpList->isClosed()) {
175 SkASSERT(fRenderTargetProxy->getLastOpList() == fOpList.get());
176 }
177 }
178 #endif
179
~GrRenderTargetContext()180 GrRenderTargetContext::~GrRenderTargetContext() {
181 ASSERT_SINGLE_OWNER
182 }
183
asTextureProxy()184 GrTextureProxy* GrRenderTargetContext::asTextureProxy() {
185 return fRenderTargetProxy->asTextureProxy();
186 }
187
asTextureProxy() const188 const GrTextureProxy* GrRenderTargetContext::asTextureProxy() const {
189 return fRenderTargetProxy->asTextureProxy();
190 }
191
asTextureProxyRef()192 sk_sp<GrTextureProxy> GrRenderTargetContext::asTextureProxyRef() {
193 return sk_ref_sp(fRenderTargetProxy->asTextureProxy());
194 }
195
mipMapped() const196 GrMipMapped GrRenderTargetContext::mipMapped() const {
197 if (const GrTextureProxy* proxy = this->asTextureProxy()) {
198 return proxy->mipMapped();
199 }
200 return GrMipMapped::kNo;
201 }
202
getRTOpList()203 GrRenderTargetOpList* GrRenderTargetContext::getRTOpList() {
204 ASSERT_SINGLE_OWNER
205 SkDEBUGCODE(this->validate();)
206
207 if (!fOpList || fOpList->isClosed()) {
208 fOpList = this->drawingManager()->newRTOpList(fRenderTargetProxy.get(), fManagedOpList);
209 }
210
211 return fOpList.get();
212 }
213
getOpList()214 GrOpList* GrRenderTargetContext::getOpList() {
215 return this->getRTOpList();
216 }
217
drawText(const GrClip & clip,const SkPaint & skPaint,const SkMatrix & viewMatrix,const char text[],size_t byteLength,SkScalar x,SkScalar y,const SkIRect & clipBounds)218 void GrRenderTargetContext::drawText(const GrClip& clip, const SkPaint& skPaint,
219 const SkMatrix& viewMatrix, const char text[],
220 size_t byteLength, SkScalar x, SkScalar y,
221 const SkIRect& clipBounds) {
222 ASSERT_SINGLE_OWNER
223 RETURN_IF_ABANDONED
224 SkDEBUGCODE(this->validate();)
225 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawText", fContext);
226
227 GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext();
228 atlasTextContext->drawText(fContext, fTextTarget.get(), clip, skPaint, viewMatrix,
229 fSurfaceProps, text, byteLength, x, y, clipBounds);
230 }
231
drawPosText(const GrClip & clip,const SkPaint & paint,const SkMatrix & viewMatrix,const char text[],size_t byteLength,const SkScalar pos[],int scalarsPerPosition,const SkPoint & offset,const SkIRect & clipBounds)232 void GrRenderTargetContext::drawPosText(const GrClip& clip, const SkPaint& paint,
233 const SkMatrix& viewMatrix, const char text[],
234 size_t byteLength, const SkScalar pos[],
235 int scalarsPerPosition, const SkPoint& offset,
236 const SkIRect& clipBounds) {
237 ASSERT_SINGLE_OWNER
238 RETURN_IF_ABANDONED
239 SkDEBUGCODE(this->validate();)
240 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPosText", fContext);
241
242 GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext();
243 atlasTextContext->drawPosText(fContext, fTextTarget.get(), clip, paint, viewMatrix,
244 fSurfaceProps, text, byteLength, pos, scalarsPerPosition, offset,
245 clipBounds);
246 }
247
drawTextBlob(const GrClip & clip,const SkPaint & paint,const SkMatrix & viewMatrix,const SkTextBlob * blob,SkScalar x,SkScalar y,SkDrawFilter * filter,const SkIRect & clipBounds)248 void GrRenderTargetContext::drawTextBlob(const GrClip& clip, const SkPaint& paint,
249 const SkMatrix& viewMatrix, const SkTextBlob* blob,
250 SkScalar x, SkScalar y, SkDrawFilter* filter,
251 const SkIRect& clipBounds) {
252 ASSERT_SINGLE_OWNER
253 RETURN_IF_ABANDONED
254 SkDEBUGCODE(this->validate();)
255 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextBlob", fContext);
256
257 GrAtlasTextContext* atlasTextContext = this->drawingManager()->getAtlasTextContext();
258 atlasTextContext->drawTextBlob(fContext, fTextTarget.get(), clip, paint, viewMatrix,
259 fSurfaceProps, blob, x, y, filter, clipBounds);
260 }
261
discard()262 void GrRenderTargetContext::discard() {
263 ASSERT_SINGLE_OWNER
264 RETURN_IF_ABANDONED
265 SkDEBUGCODE(this->validate();)
266 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext);
267
268 AutoCheckFlush acf(this->drawingManager());
269
270 this->getRTOpList()->discard();
271 }
272
clear(const SkIRect * rect,const GrColor color,CanClearFullscreen canClearFullscreen)273 void GrRenderTargetContext::clear(const SkIRect* rect,
274 const GrColor color,
275 CanClearFullscreen canClearFullscreen) {
276 ASSERT_SINGLE_OWNER
277 RETURN_IF_ABANDONED
278 SkDEBUGCODE(this->validate();)
279 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext);
280
281 AutoCheckFlush acf(this->drawingManager());
282 this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color,
283 canClearFullscreen);
284 }
285
absClear(const SkIRect * clearRect,const GrColor color)286 void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const GrColor color) {
287 ASSERT_SINGLE_OWNER_PRIV
288 RETURN_IF_ABANDONED_PRIV
289 SkDEBUGCODE(fRenderTargetContext->validate();)
290 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "absClear",
291 fRenderTargetContext->fContext);
292
293 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
294
295 SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth(),
296 fRenderTargetContext->fRenderTargetProxy->worstCaseHeight());
297
298 if (clearRect) {
299 if (clearRect->contains(rtRect)) {
300 clearRect = nullptr; // full screen
301 } else {
302 if (!rtRect.intersect(*clearRect)) {
303 return;
304 }
305 }
306 }
307
308 // TODO: in a post-MDB world this should be handled at the OpList level.
309 // An op-list that is initially cleared and has no other ops should receive an
310 // extra draw.
311 // This path doesn't handle coalescing of full screen clears b.c. it
312 // has to clear the entire render target - not just the content area.
313 // It could be done but will take more finagling.
314 std::unique_ptr<GrOp> op(GrClearOp::Make(rtRect, color, !clearRect));
315 if (!op) {
316 return;
317 }
318 fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
319 }
320
clear(const GrFixedClip & clip,const GrColor color,CanClearFullscreen canClearFullscreen)321 void GrRenderTargetContextPriv::clear(const GrFixedClip& clip,
322 const GrColor color,
323 CanClearFullscreen canClearFullscreen) {
324 ASSERT_SINGLE_OWNER_PRIV
325 RETURN_IF_ABANDONED_PRIV
326 SkDEBUGCODE(fRenderTargetContext->validate();)
327 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clear",
328 fRenderTargetContext->fContext);
329
330 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
331 fRenderTargetContext->internalClear(clip, color, canClearFullscreen);
332 }
333
internalClear(const GrFixedClip & clip,const GrColor color,CanClearFullscreen canClearFullscreen)334 void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
335 const GrColor color,
336 CanClearFullscreen canClearFullscreen) {
337 bool isFull = false;
338 if (!clip.hasWindowRectangles()) {
339 isFull = !clip.scissorEnabled() ||
340 (CanClearFullscreen::kYes == canClearFullscreen &&
341 fContext->caps()->preferFullscreenClears()) ||
342 clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
343 }
344
345 if (isFull) {
346 this->getRTOpList()->fullClear(*this->caps(), color);
347 } else {
348 std::unique_ptr<GrOp> op(GrClearOp::Make(clip, color, this->asSurfaceProxy()));
349 if (!op) {
350 return;
351 }
352 this->getRTOpList()->addOp(std::move(op), *this->caps());
353 }
354 }
355
drawPaint(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix)356 void GrRenderTargetContext::drawPaint(const GrClip& clip,
357 GrPaint&& paint,
358 const SkMatrix& viewMatrix) {
359 ASSERT_SINGLE_OWNER
360 RETURN_IF_ABANDONED
361 SkDEBUGCODE(this->validate();)
362 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPaint", fContext);
363
364 // set rect to be big enough to fill the space, but not super-huge, so we
365 // don't overflow fixed-point implementations
366
367 SkRect r = fRenderTargetProxy->getBoundsRect();
368
369 SkRRect rrect;
370 GrAA aa;
371 // Check if we can replace a clipRRect()/drawPaint() with a drawRRect(). We only do the
372 // transformation for non-rect rrects. Rects caused a performance regression on an Android
373 // test that needs investigation. We also skip cases where there are fragment processors
374 // because they may depend on having correct local coords and this path draws in device space
375 // without a local matrix.
376 if (!paint.numTotalFragmentProcessors() && clip.isRRect(r, &rrect, &aa) && !rrect.isRect()) {
377 this->drawRRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect,
378 GrStyle::SimpleFill());
379 return;
380 }
381
382
383 bool isPerspective = viewMatrix.hasPerspective();
384
385 // We attempt to map r by the inverse matrix and draw that. mapRect will
386 // map the four corners and bound them with a new rect. This will not
387 // produce a correct result for some perspective matrices.
388 if (!isPerspective) {
389 if (!SkMatrixPriv::InverseMapRect(viewMatrix, &r, r)) {
390 SkDebugf("Could not invert matrix\n");
391 return;
392 }
393 this->drawRect(clip, std::move(paint), GrAA::kNo, viewMatrix, r);
394 } else {
395 SkMatrix localMatrix;
396 if (!viewMatrix.invert(&localMatrix)) {
397 SkDebugf("Could not invert matrix\n");
398 return;
399 }
400
401 AutoCheckFlush acf(this->drawingManager());
402
403 std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
404 std::move(paint), SkMatrix::I(), localMatrix, r, GrAAType::kNone);
405 this->addDrawOp(clip, std::move(op));
406 }
407 }
408
rect_contains_inclusive(const SkRect & rect,const SkPoint & point)409 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
410 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
411 point.fY >= rect.fTop && point.fY <= rect.fBottom;
412 }
413
414 // Attempts to crop a rect and optional local rect to the clip boundaries.
415 // 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)416 static bool crop_filled_rect(int width, int height, const GrClip& clip,
417 const SkMatrix& viewMatrix, SkRect* rect,
418 SkRect* localRect = nullptr) {
419 if (!viewMatrix.rectStaysRect()) {
420 return true;
421 }
422
423 SkIRect clipDevBounds;
424 SkRect clipBounds;
425
426 clip.getConservativeBounds(width, height, &clipDevBounds);
427 if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) {
428 return false;
429 }
430
431 if (localRect) {
432 if (!rect->intersects(clipBounds)) {
433 return false;
434 }
435 const SkScalar dx = localRect->width() / rect->width();
436 const SkScalar dy = localRect->height() / rect->height();
437 if (clipBounds.fLeft > rect->fLeft) {
438 localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx;
439 rect->fLeft = clipBounds.fLeft;
440 }
441 if (clipBounds.fTop > rect->fTop) {
442 localRect->fTop += (clipBounds.fTop - rect->fTop) * dy;
443 rect->fTop = clipBounds.fTop;
444 }
445 if (clipBounds.fRight < rect->fRight) {
446 localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx;
447 rect->fRight = clipBounds.fRight;
448 }
449 if (clipBounds.fBottom < rect->fBottom) {
450 localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy;
451 rect->fBottom = clipBounds.fBottom;
452 }
453 return true;
454 }
455
456 return rect->intersect(clipBounds);
457 }
458
drawFilledRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect,const GrUserStencilSettings * ss)459 bool GrRenderTargetContext::drawFilledRect(const GrClip& clip,
460 GrPaint&& paint,
461 GrAA aa,
462 const SkMatrix& viewMatrix,
463 const SkRect& rect,
464 const GrUserStencilSettings* ss) {
465 SkRect croppedRect = rect;
466 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
467 return true;
468 }
469
470 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
471 std::unique_ptr<GrDrawOp> op;
472 if (GrAAType::kCoverage == aaType) {
473 op = GrRectOpFactory::MakeAAFill(std::move(paint), viewMatrix, croppedRect, ss);
474 } else {
475 op = GrRectOpFactory::MakeNonAAFill(std::move(paint), viewMatrix, croppedRect, aaType, ss);
476 }
477 if (!op) {
478 return false;
479 }
480 this->addDrawOp(clip, std::move(op));
481 return true;
482 }
483
drawRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect,const GrStyle * style)484 void GrRenderTargetContext::drawRect(const GrClip& clip,
485 GrPaint&& paint,
486 GrAA aa,
487 const SkMatrix& viewMatrix,
488 const SkRect& rect,
489 const GrStyle* style) {
490 if (!style) {
491 style = &GrStyle::SimpleFill();
492 }
493 ASSERT_SINGLE_OWNER
494 RETURN_IF_ABANDONED
495 SkDEBUGCODE(this->validate();)
496 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRect", fContext);
497
498 // Path effects should've been devolved to a path in SkGpuDevice
499 SkASSERT(!style->pathEffect());
500
501 AutoCheckFlush acf(this->drawingManager());
502
503 const SkStrokeRec& stroke = style->strokeRec();
504 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
505 // Check if this is a full RT draw and can be replaced with a clear. We don't bother
506 // checking cases where the RT is fully inside a stroke.
507 SkRect rtRect = fRenderTargetProxy->getBoundsRect();
508 // Does the clip contain the entire RT?
509 if (clip.quickContains(rtRect)) {
510 SkMatrix invM;
511 if (!viewMatrix.invert(&invM)) {
512 return;
513 }
514 // Does the rect bound the RT?
515 GrQuad quad;
516 quad.setFromMappedRect(rtRect, invM);
517 if (rect_contains_inclusive(rect, quad.point(0)) &&
518 rect_contains_inclusive(rect, quad.point(1)) &&
519 rect_contains_inclusive(rect, quad.point(2)) &&
520 rect_contains_inclusive(rect, quad.point(3))) {
521 // Will it blend?
522 GrColor clearColor;
523 if (paint.isConstantBlendedColor(&clearColor)) {
524 this->clear(nullptr, clearColor,
525 GrRenderTargetContext::CanClearFullscreen::kYes);
526 return;
527 }
528 }
529 }
530
531 if (this->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect, nullptr)) {
532 return;
533 }
534 } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
535 stroke.getStyle() == SkStrokeRec::kHairline_Style) {
536 if ((!rect.width() || !rect.height()) &&
537 SkStrokeRec::kHairline_Style != stroke.getStyle()) {
538 SkScalar r = stroke.getWidth() / 2;
539 // TODO: Move these stroke->fill fallbacks to GrShape?
540 switch (stroke.getJoin()) {
541 case SkPaint::kMiter_Join:
542 this->drawRect(
543 clip, std::move(paint), aa, viewMatrix,
544 {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r},
545 &GrStyle::SimpleFill());
546 return;
547 case SkPaint::kRound_Join:
548 // Raster draws nothing when both dimensions are empty.
549 if (rect.width() || rect.height()){
550 SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
551 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect,
552 GrStyle::SimpleFill());
553 return;
554 }
555 case SkPaint::kBevel_Join:
556 if (!rect.width()) {
557 this->drawRect(clip, std::move(paint), aa, viewMatrix,
558 {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
559 &GrStyle::SimpleFill());
560 } else {
561 this->drawRect(clip, std::move(paint), aa, viewMatrix,
562 {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
563 &GrStyle::SimpleFill());
564 }
565 return;
566 }
567 }
568
569 std::unique_ptr<GrDrawOp> op;
570
571 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
572 if (GrAAType::kCoverage == aaType) {
573 // The stroke path needs the rect to remain axis aligned (no rotation or skew).
574 if (viewMatrix.rectStaysRect()) {
575 op = GrRectOpFactory::MakeAAStroke(std::move(paint), viewMatrix, rect, stroke);
576 }
577 } else {
578 op = GrRectOpFactory::MakeNonAAStroke(std::move(paint), viewMatrix, rect, stroke,
579 aaType);
580 }
581
582 if (op) {
583 this->addDrawOp(clip, std::move(op));
584 return;
585 }
586 }
587 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style));
588 }
589
maxWindowRectangles() const590 int GrRenderTargetContextPriv::maxWindowRectangles() const {
591 return fRenderTargetContext->fRenderTargetProxy->maxWindowRectangles(
592 *fRenderTargetContext->fContext->caps());
593 }
594
clearStencilClip(const GrFixedClip & clip,bool insideStencilMask)595 void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
596 ASSERT_SINGLE_OWNER_PRIV
597 RETURN_IF_ABANDONED_PRIV
598 SkDEBUGCODE(fRenderTargetContext->validate();)
599 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clearStencilClip",
600 fRenderTargetContext->fContext);
601
602 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
603
604 std::unique_ptr<GrOp> op(GrClearStencilClipOp::Make(
605 clip, insideStencilMask,
606 fRenderTargetContext->fRenderTargetProxy.get()));
607 if (!op) {
608 return;
609 }
610 fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
611 }
612
stencilPath(const GrHardClip & clip,GrAAType aaType,const SkMatrix & viewMatrix,const GrPath * path)613 void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
614 GrAAType aaType,
615 const SkMatrix& viewMatrix,
616 const GrPath* path) {
617 ASSERT_SINGLE_OWNER_PRIV
618 RETURN_IF_ABANDONED_PRIV
619 SkDEBUGCODE(fRenderTargetContext->validate();)
620 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilPath",
621 fRenderTargetContext->fContext);
622
623 SkASSERT(aaType != GrAAType::kCoverage);
624
625 bool useHWAA = GrAATypeIsHW(aaType);
626 // TODO: extract portions of checkDraw that are relevant to path stenciling.
627 SkASSERT(path);
628 SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
629
630 // FIXME: Use path bounds instead of this WAR once
631 // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
632 SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height());
633
634 // Setup clip
635 GrAppliedHardClip appliedClip;
636 if (!clip.apply(fRenderTargetContext->width(), fRenderTargetContext->height(), &appliedClip,
637 &bounds)) {
638 return;
639 }
640
641 fRenderTargetContext->setNeedsStencil();
642
643 std::unique_ptr<GrOp> op = GrStencilPathOp::Make(viewMatrix,
644 useHWAA,
645 path->getFillType(),
646 appliedClip.hasStencilClip(),
647 appliedClip.scissorState(),
648 path);
649 if (!op) {
650 return;
651 }
652 op->setClippedBounds(bounds);
653 fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
654 }
655
stencilRect(const GrHardClip & clip,const GrUserStencilSettings * ss,GrAAType aaType,const SkMatrix & viewMatrix,const SkRect & rect)656 void GrRenderTargetContextPriv::stencilRect(const GrHardClip& clip,
657 const GrUserStencilSettings* ss,
658 GrAAType aaType,
659 const SkMatrix& viewMatrix,
660 const SkRect& rect) {
661 ASSERT_SINGLE_OWNER_PRIV
662 RETURN_IF_ABANDONED_PRIV
663 SkDEBUGCODE(fRenderTargetContext->validate();)
664 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilRect",
665 fRenderTargetContext->fContext);
666
667 SkASSERT(GrAAType::kCoverage != aaType);
668 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
669
670 GrPaint paint;
671 paint.setXPFactory(GrDisableColorXPFactory::Get());
672 std::unique_ptr<GrDrawOp> op =
673 GrRectOpFactory::MakeNonAAFill(std::move(paint), viewMatrix, rect, aaType, ss);
674 fRenderTargetContext->addDrawOp(clip, std::move(op));
675 }
676
drawAndStencilRect(const GrHardClip & clip,const GrUserStencilSettings * ss,SkRegion::Op op,bool invert,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect)677 bool GrRenderTargetContextPriv::drawAndStencilRect(const GrHardClip& clip,
678 const GrUserStencilSettings* ss,
679 SkRegion::Op op,
680 bool invert,
681 GrAA aa,
682 const SkMatrix& viewMatrix,
683 const SkRect& rect) {
684 ASSERT_SINGLE_OWNER_PRIV
685 RETURN_FALSE_IF_ABANDONED_PRIV
686 SkDEBUGCODE(fRenderTargetContext->validate();)
687 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilRect",
688 fRenderTargetContext->fContext);
689
690 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
691
692 GrPaint paint;
693 paint.setCoverageSetOpXPFactory(op, invert);
694
695 if (fRenderTargetContext->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect, ss)) {
696 return true;
697 }
698 SkPath path;
699 path.setIsVolatile(true);
700 path.addRect(rect);
701 return this->drawAndStencilPath(clip, ss, op, invert, aa, viewMatrix, path);
702 }
703
fillRectToRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rectToDraw,const SkRect & localRect)704 void GrRenderTargetContext::fillRectToRect(const GrClip& clip,
705 GrPaint&& paint,
706 GrAA aa,
707 const SkMatrix& viewMatrix,
708 const SkRect& rectToDraw,
709 const SkRect& localRect) {
710 ASSERT_SINGLE_OWNER
711 RETURN_IF_ABANDONED
712 SkDEBUGCODE(this->validate();)
713 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectToRect", fContext);
714
715 SkRect croppedRect = rectToDraw;
716 SkRect croppedLocalRect = localRect;
717 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix,
718 &croppedRect, &croppedLocalRect)) {
719 return;
720 }
721
722 AutoCheckFlush acf(this->drawingManager());
723
724 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
725 if (GrAAType::kCoverage != aaType) {
726 std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalRect(
727 std::move(paint), viewMatrix, croppedRect, croppedLocalRect, aaType);
728 this->addDrawOp(clip, std::move(op));
729 return;
730 }
731
732 std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeAAFillWithLocalRect(
733 std::move(paint), viewMatrix, croppedRect, croppedLocalRect);
734 if (op) {
735 this->addDrawOp(clip, std::move(op));
736 return;
737 }
738
739 SkMatrix viewAndUnLocalMatrix;
740 if (!viewAndUnLocalMatrix.setRectToRect(localRect, rectToDraw, SkMatrix::kFill_ScaleToFit)) {
741 SkDebugf("fillRectToRect called with empty local matrix.\n");
742 return;
743 }
744 viewAndUnLocalMatrix.postConcat(viewMatrix);
745
746 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewAndUnLocalMatrix,
747 GrShape(localRect));
748 }
749
must_filter(const SkRect & src,const SkRect & dst,const SkMatrix & ctm)750 static bool must_filter(const SkRect& src, const SkRect& dst, const SkMatrix& ctm) {
751 // We don't currently look for 90 degree rotations, mirroring, or downscales that sample at
752 // texel centers.
753 if (!ctm.isTranslate()) {
754 return true;
755 }
756 if (src.width() != dst.width() || src.height() != dst.height()) {
757 return true;
758 }
759 // Check that the device space rectangle's fractional offset is the same as the src rectangle,
760 // and that therefore integers in the src image fall on integers in device space.
761 SkScalar x = ctm.getTranslateX(), y = ctm.getTranslateY();
762 x += dst.fLeft; y += dst.fTop;
763 x -= src.fLeft; y -= src.fTop;
764 return !SkScalarIsInt(x) || !SkScalarIsInt(y);
765 }
766
drawTextureAffine(const GrClip & clip,sk_sp<GrTextureProxy> proxy,GrSamplerState::Filter filter,GrColor color,const SkRect & srcRect,const SkRect & dstRect,GrAA aa,const SkMatrix & viewMatrix,sk_sp<GrColorSpaceXform> colorSpaceXform)767 void GrRenderTargetContext::drawTextureAffine(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
768 GrSamplerState::Filter filter, GrColor color,
769 const SkRect& srcRect, const SkRect& dstRect, GrAA aa,
770 const SkMatrix& viewMatrix,
771 sk_sp<GrColorSpaceXform> colorSpaceXform) {
772 ASSERT_SINGLE_OWNER
773 RETURN_IF_ABANDONED
774 SkDEBUGCODE(this->validate();)
775 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureAffine", fContext);
776 SkASSERT(!viewMatrix.hasPerspective());
777 if (filter != GrSamplerState::Filter::kNearest && !must_filter(srcRect, dstRect, viewMatrix)) {
778 filter = GrSamplerState::Filter::kNearest;
779 }
780 SkRect clippedDstRect = dstRect;
781 SkRect clippedSrcRect = srcRect;
782 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &clippedDstRect,
783 &clippedSrcRect)) {
784 return;
785 }
786 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
787 bool allowSRGB = SkToBool(this->colorSpaceInfo().colorSpace());
788 this->addDrawOp(
789 clip, GrTextureOp::Make(std::move(proxy), filter, color, clippedSrcRect, clippedDstRect,
790 aaType, viewMatrix, std::move(colorSpaceXform), allowSRGB));
791 }
792
fillRectWithLocalMatrix(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rectToDraw,const SkMatrix & localMatrix)793 void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,
794 GrPaint&& paint,
795 GrAA aa,
796 const SkMatrix& viewMatrix,
797 const SkRect& rectToDraw,
798 const SkMatrix& localMatrix) {
799 ASSERT_SINGLE_OWNER
800 RETURN_IF_ABANDONED
801 SkDEBUGCODE(this->validate();)
802 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithLocalMatrix", fContext);
803
804 SkRect croppedRect = rectToDraw;
805 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
806 return;
807 }
808
809 AutoCheckFlush acf(this->drawingManager());
810
811 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
812 if (GrAAType::kCoverage != aaType) {
813 std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
814 std::move(paint), viewMatrix, localMatrix, croppedRect, aaType);
815 this->addDrawOp(clip, std::move(op));
816 return;
817 }
818
819 std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeAAFillWithLocalMatrix(
820 std::move(paint), viewMatrix, localMatrix, croppedRect);
821 if (op) {
822 this->addDrawOp(clip, std::move(op));
823 return;
824 }
825
826 SkMatrix viewAndUnLocalMatrix;
827 if (!localMatrix.invert(&viewAndUnLocalMatrix)) {
828 SkDebugf("fillRectWithLocalMatrix called with degenerate local matrix.\n");
829 return;
830 }
831 viewAndUnLocalMatrix.postConcat(viewMatrix);
832
833 SkPath path;
834 path.setIsVolatile(true);
835 path.addRect(rectToDraw);
836 path.transform(localMatrix);
837 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewAndUnLocalMatrix,
838 GrShape(path));
839 }
840
drawVertices(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,sk_sp<SkVertices> vertices,GrPrimitiveType * overridePrimType)841 void GrRenderTargetContext::drawVertices(const GrClip& clip,
842 GrPaint&& paint,
843 const SkMatrix& viewMatrix,
844 sk_sp<SkVertices> vertices,
845 GrPrimitiveType* overridePrimType) {
846 ASSERT_SINGLE_OWNER
847 RETURN_IF_ABANDONED
848 SkDEBUGCODE(this->validate();)
849 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawVertices", fContext);
850
851 AutoCheckFlush acf(this->drawingManager());
852
853 SkASSERT(vertices);
854 GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
855 std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
856 std::move(paint), std::move(vertices), viewMatrix, aaType,
857 this->colorSpaceInfo().isGammaCorrect(),
858 this->colorSpaceInfo().refColorSpaceXformFromSRGB(), overridePrimType);
859 this->addDrawOp(clip, std::move(op));
860 }
861
862 ///////////////////////////////////////////////////////////////////////////////
863
drawAtlas(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,int spriteCount,const SkRSXform xform[],const SkRect texRect[],const SkColor colors[])864 void GrRenderTargetContext::drawAtlas(const GrClip& clip,
865 GrPaint&& paint,
866 const SkMatrix& viewMatrix,
867 int spriteCount,
868 const SkRSXform xform[],
869 const SkRect texRect[],
870 const SkColor colors[]) {
871 ASSERT_SINGLE_OWNER
872 RETURN_IF_ABANDONED
873 SkDEBUGCODE(this->validate();)
874 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawAtlas", fContext);
875
876 AutoCheckFlush acf(this->drawingManager());
877
878 GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
879 std::unique_ptr<GrDrawOp> op = GrDrawAtlasOp::Make(std::move(paint), viewMatrix, aaType,
880 spriteCount, xform, texRect, colors);
881 this->addDrawOp(clip, std::move(op));
882 }
883
884 ///////////////////////////////////////////////////////////////////////////////
885
drawRRect(const GrClip & origClip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & rrect,const GrStyle & style)886 void GrRenderTargetContext::drawRRect(const GrClip& origClip,
887 GrPaint&& paint,
888 GrAA aa,
889 const SkMatrix& viewMatrix,
890 const SkRRect& rrect,
891 const GrStyle& style) {
892 ASSERT_SINGLE_OWNER
893 RETURN_IF_ABANDONED
894 SkDEBUGCODE(this->validate();)
895 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRRect", fContext);
896 if (rrect.isEmpty()) {
897 return;
898 }
899
900 GrNoClip noclip;
901 const GrClip* clip = &origClip;
902 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
903 // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
904 // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it
905 // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
906 // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
907 // can be ignored. We'd prefer to fix this in the framework by removing the clips calls.
908 SkRRect devRRect;
909 if (rrect.transform(viewMatrix, &devRRect) && clip->quickContains(devRRect)) {
910 clip = &noclip;
911 }
912 #endif
913 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
914
915 AutoCheckFlush acf(this->drawingManager());
916 const SkStrokeRec stroke = style.strokeRec();
917
918 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
919 if (GrAAType::kCoverage == aaType) {
920 const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
921 std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeRRectOp(std::move(paint),
922 viewMatrix,
923 rrect,
924 stroke,
925 shaderCaps);
926 if (op) {
927 this->addDrawOp(*clip, std::move(op));
928 return;
929 }
930 }
931
932 this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix,
933 GrShape(rrect, style));
934 }
935
936 ///////////////////////////////////////////////////////////////////////////////
937
map(const SkMatrix & m,const SkPoint3 & pt)938 static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
939 SkPoint3 result;
940 m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
941 result.fZ = pt.fZ;
942 return result;
943 }
944
drawFastShadow(const GrClip & clip,const SkMatrix & viewMatrix,const SkPath & path,const SkDrawShadowRec & rec)945 bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
946 const SkMatrix& viewMatrix,
947 const SkPath& path,
948 const SkDrawShadowRec& rec) {
949 ASSERT_SINGLE_OWNER
950 if (this->drawingManager()->wasAbandoned()) {
951 return true;
952 }
953 SkDEBUGCODE(this->validate();)
954 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFastShadow", fContext);
955
956 // check z plane
957 bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
958 !SkScalarNearlyZero(rec.fZPlaneParams.fY));
959 bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
960 if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
961 return false;
962 }
963
964 SkRRect rrect;
965 SkRect rect;
966 // we can only handle rects, circles, and rrects with circular corners
967 bool isRRect = path.isRRect(&rrect) && rrect.isSimpleCircular() &&
968 rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero;
969 if (!isRRect &&
970 path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
971 rect.width() > SK_ScalarNearlyZero) {
972 rrect.setOval(rect);
973 isRRect = true;
974 }
975 if (!isRRect && path.isRect(&rect)) {
976 rrect.setRect(rect);
977 isRRect = true;
978 }
979
980 if (!isRRect) {
981 return false;
982 }
983
984 if (rrect.isEmpty()) {
985 return true;
986 }
987
988 AutoCheckFlush acf(this->drawingManager());
989
990 // transform light
991 SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
992
993 // 1/scale
994 SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
995 SkScalarInvert(viewMatrix[SkMatrix::kMScaleX]) :
996 sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
997 viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
998
999 SkScalar occluderHeight = rec.fZPlaneParams.fZ;
1000 bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1001
1002 if (SkColorGetA(rec.fAmbientColor) > 0) {
1003 SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1004 const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1005 const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
1006
1007 // Outset the shadow rrect to the border of the penumbra
1008 SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1009 SkRRect ambientRRect;
1010 SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1011 // If the rrect was an oval then its outset will also be one.
1012 // We set it explicitly to avoid errors.
1013 if (rrect.isOval()) {
1014 ambientRRect = SkRRect::MakeOval(outsetRect);
1015 } else {
1016 SkScalar outsetRad = rrect.getSimpleRadii().fX + ambientPathOutset;
1017 ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1018 }
1019
1020 GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
1021 if (transparent) {
1022 // set a large inset to force a fill
1023 devSpaceInsetWidth = ambientRRect.width();
1024 }
1025 // the fraction of the blur we want to apply is devSpaceInsetWidth/devSpaceAmbientBlur,
1026 // which is just 1/umbraRecipAlpha.
1027 SkScalar blurClamp = SkScalarInvert(umbraRecipAlpha);
1028
1029 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(ambientColor, viewMatrix,
1030 ambientRRect,
1031 devSpaceAmbientBlur,
1032 devSpaceInsetWidth,
1033 blurClamp);
1034 SkASSERT(op);
1035 this->addDrawOp(clip, std::move(op));
1036 }
1037
1038 if (SkColorGetA(rec.fSpotColor) > 0) {
1039 SkScalar devSpaceSpotBlur;
1040 SkScalar spotScale;
1041 SkVector spotOffset;
1042 SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1043 devLightPos.fZ, rec.fLightRadius,
1044 &devSpaceSpotBlur, &spotScale, &spotOffset);
1045 // handle scale of radius due to CTM
1046 const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1047
1048 // Adjust translate for the effect of the scale.
1049 spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1050 spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1051 // This offset is in dev space, need to transform it into source space.
1052 SkMatrix ctmInverse;
1053 if (viewMatrix.invert(&ctmInverse)) {
1054 ctmInverse.mapPoints(&spotOffset, 1);
1055 } else {
1056 // Since the matrix is a similarity, this should never happen, but just in case...
1057 SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1058 SkASSERT(false);
1059 }
1060
1061 // Compute the transformed shadow rrect
1062 SkRRect spotShadowRRect;
1063 SkMatrix shadowTransform;
1064 shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1065 rrect.transform(shadowTransform, &spotShadowRRect);
1066 SkScalar spotRadius = spotShadowRRect.getSimpleRadii().fX;
1067
1068 // Compute the insetWidth
1069 SkScalar blurOutset = srcSpaceSpotBlur;
1070 SkScalar insetWidth = blurOutset;
1071 if (transparent) {
1072 // If transparent, just do a fill
1073 insetWidth += spotShadowRRect.width();
1074 } else {
1075 // For shadows, instead of using a stroke we specify an inset from the penumbra
1076 // border. We want to extend this inset area so that it meets up with the caster
1077 // geometry. The inset geometry will by default already be inset by the blur width.
1078 //
1079 // We compare the min and max corners inset by the radius between the original
1080 // rrect and the shadow rrect. The distance between the two plus the difference
1081 // between the scaled radius and the original radius gives the distance from the
1082 // transformed shadow shape to the original shape in that corner. The max
1083 // of these gives the maximum distance we need to cover.
1084 //
1085 // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1086 // that to get the full insetWidth.
1087 SkScalar maxOffset;
1088 if (rrect.isRect()) {
1089 // Manhattan distance works better for rects
1090 maxOffset = SkTMax(SkTMax(SkTAbs(spotShadowRRect.rect().fLeft -
1091 rrect.rect().fLeft),
1092 SkTAbs(spotShadowRRect.rect().fTop -
1093 rrect.rect().fTop)),
1094 SkTMax(SkTAbs(spotShadowRRect.rect().fRight -
1095 rrect.rect().fRight),
1096 SkTAbs(spotShadowRRect.rect().fBottom -
1097 rrect.rect().fBottom)));
1098 } else {
1099 SkScalar dr = spotRadius - rrect.getSimpleRadii().fX;
1100 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1101 rrect.rect().fLeft + dr,
1102 spotShadowRRect.rect().fTop -
1103 rrect.rect().fTop + dr);
1104 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1105 rrect.rect().fRight - dr,
1106 spotShadowRRect.rect().fBottom -
1107 rrect.rect().fBottom - dr);
1108 maxOffset = SkScalarSqrt(SkTMax(SkPointPriv::LengthSqd(upperLeftOffset),
1109 SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
1110 }
1111 insetWidth += maxOffset;
1112 }
1113
1114 // Outset the shadow rrect to the border of the penumbra
1115 SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1116 if (spotShadowRRect.isOval()) {
1117 spotShadowRRect = SkRRect::MakeOval(outsetRect);
1118 } else {
1119 SkScalar outsetRad = spotRadius + blurOutset;
1120 spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1121 }
1122
1123 GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
1124
1125 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(spotColor, viewMatrix,
1126 spotShadowRRect,
1127 2.0f * devSpaceSpotBlur,
1128 insetWidth);
1129 SkASSERT(op);
1130 this->addDrawOp(clip, std::move(op));
1131 }
1132
1133 return true;
1134 }
1135
1136 ///////////////////////////////////////////////////////////////////////////////
1137
drawFilledDRRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & origOuter,const SkRRect & origInner)1138 bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
1139 GrPaint&& paint,
1140 GrAA aa,
1141 const SkMatrix& viewMatrix,
1142 const SkRRect& origOuter,
1143 const SkRRect& origInner) {
1144 SkASSERT(!origInner.isEmpty());
1145 SkASSERT(!origOuter.isEmpty());
1146
1147 SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
1148
1149 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1150
1151 if (GrAAType::kMSAA == aaType) {
1152 return false;
1153 }
1154
1155 if (GrAAType::kCoverage == aaType && inner->isCircle() && outer->isCircle()) {
1156 auto outerR = outer->width() / 2.f;
1157 auto innerR = inner->width() / 2.f;
1158 auto cx = outer->getBounds().fLeft + outerR;
1159 auto cy = outer->getBounds().fTop + outerR;
1160 if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) &&
1161 SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) {
1162 auto avgR = (innerR + outerR) / 2.f;
1163 auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR);
1164 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
1165 stroke.setStrokeStyle(outerR - innerR);
1166 auto op = GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, circleBounds,
1167 stroke, this->caps()->shaderCaps());
1168 if (op) {
1169 this->addDrawOp(clip, std::move(op));
1170 return true;
1171 }
1172 }
1173 }
1174
1175 GrClipEdgeType innerEdgeType, outerEdgeType;
1176 if (GrAAType::kCoverage == aaType) {
1177 innerEdgeType = GrClipEdgeType::kInverseFillAA;
1178 outerEdgeType = GrClipEdgeType::kFillAA;
1179 } else {
1180 innerEdgeType = GrClipEdgeType::kInverseFillBW;
1181 outerEdgeType = GrClipEdgeType::kFillBW;
1182 }
1183
1184 SkMatrix inverseVM;
1185 if (!viewMatrix.isIdentity()) {
1186 if (!origInner.transform(viewMatrix, inner.writable())) {
1187 return false;
1188 }
1189 if (!origOuter.transform(viewMatrix, outer.writable())) {
1190 return false;
1191 }
1192 if (!viewMatrix.invert(&inverseVM)) {
1193 return false;
1194 }
1195 } else {
1196 inverseVM.reset();
1197 }
1198
1199 const auto& caps = *this->caps()->shaderCaps();
1200 // TODO these need to be a geometry processors
1201 auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps);
1202 if (!innerEffect) {
1203 return false;
1204 }
1205
1206 auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps);
1207 if (!outerEffect) {
1208 return false;
1209 }
1210
1211 paint.addCoverageFragmentProcessor(std::move(innerEffect));
1212 paint.addCoverageFragmentProcessor(std::move(outerEffect));
1213
1214 SkRect bounds = outer->getBounds();
1215 if (GrAAType::kCoverage == aaType) {
1216 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1217 }
1218
1219 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds,
1220 inverseVM);
1221 return true;
1222 }
1223
drawDRRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & outer,const SkRRect & inner)1224 void GrRenderTargetContext::drawDRRect(const GrClip& clip,
1225 GrPaint&& paint,
1226 GrAA aa,
1227 const SkMatrix& viewMatrix,
1228 const SkRRect& outer,
1229 const SkRRect& inner) {
1230 ASSERT_SINGLE_OWNER
1231 RETURN_IF_ABANDONED
1232 SkDEBUGCODE(this->validate();)
1233 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawDRRect", fContext);
1234
1235 SkASSERT(!outer.isEmpty());
1236 SkASSERT(!inner.isEmpty());
1237
1238 AutoCheckFlush acf(this->drawingManager());
1239
1240 if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) {
1241 return;
1242 }
1243
1244 SkPath path;
1245 path.setIsVolatile(true);
1246 path.addRRect(inner);
1247 path.addRRect(outer);
1248 path.setFillType(SkPath::kEvenOdd_FillType);
1249 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path));
1250 }
1251
1252 ///////////////////////////////////////////////////////////////////////////////
1253
drawRegion(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRegion & region,const GrStyle & style,const GrUserStencilSettings * ss)1254 void GrRenderTargetContext::drawRegion(const GrClip& clip,
1255 GrPaint&& paint,
1256 GrAA aa,
1257 const SkMatrix& viewMatrix,
1258 const SkRegion& region,
1259 const GrStyle& style,
1260 const GrUserStencilSettings* ss) {
1261 ASSERT_SINGLE_OWNER
1262 RETURN_IF_ABANDONED
1263 SkDEBUGCODE(this->validate();)
1264 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRegion", fContext);
1265
1266 if (GrAA::kYes == aa) {
1267 // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
1268 // to see whether aa is really required.
1269 if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
1270 SkScalarIsInt(viewMatrix.getTranslateX()) &&
1271 SkScalarIsInt(viewMatrix.getTranslateY())) {
1272 aa = GrAA::kNo;
1273 }
1274 }
1275 bool complexStyle = !style.isSimpleFill();
1276 if (complexStyle || GrAA::kYes == aa) {
1277 SkPath path;
1278 region.getBoundaryPath(&path);
1279 return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1280 }
1281
1282 GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
1283 std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(std::move(paint), viewMatrix, region, aaType,
1284 ss);
1285 this->addDrawOp(clip, std::move(op));
1286 }
1287
drawOval(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & oval,const GrStyle & style)1288 void GrRenderTargetContext::drawOval(const GrClip& clip,
1289 GrPaint&& paint,
1290 GrAA aa,
1291 const SkMatrix& viewMatrix,
1292 const SkRect& oval,
1293 const GrStyle& style) {
1294 ASSERT_SINGLE_OWNER
1295 RETURN_IF_ABANDONED
1296 SkDEBUGCODE(this->validate();)
1297 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawOval", fContext);
1298
1299 if (oval.isEmpty()) {
1300 return;
1301 }
1302
1303 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
1304
1305 AutoCheckFlush acf(this->drawingManager());
1306 const SkStrokeRec& stroke = style.strokeRec();
1307
1308 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1309 if (GrAAType::kCoverage == aaType) {
1310 const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
1311 std::unique_ptr<GrDrawOp> op =
1312 GrOvalOpFactory::MakeOvalOp(std::move(paint), viewMatrix, oval, stroke, shaderCaps);
1313 if (op) {
1314 this->addDrawOp(clip, std::move(op));
1315 return;
1316 }
1317 }
1318
1319 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix,
1320 GrShape(SkRRect::MakeOval(oval), style));
1321 }
1322
drawArc(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const GrStyle & style)1323 void GrRenderTargetContext::drawArc(const GrClip& clip,
1324 GrPaint&& paint,
1325 GrAA aa,
1326 const SkMatrix& viewMatrix,
1327 const SkRect& oval,
1328 SkScalar startAngle,
1329 SkScalar sweepAngle,
1330 bool useCenter,
1331 const GrStyle& style) {
1332 ASSERT_SINGLE_OWNER
1333 RETURN_IF_ABANDONED
1334 SkDEBUGCODE(this->validate();)
1335 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawArc", fContext);
1336
1337 AutoCheckFlush acf(this->drawingManager());
1338
1339 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1340 if (GrAAType::kCoverage == aaType) {
1341 const GrShaderCaps* shaderCaps = fContext->caps()->shaderCaps();
1342 std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(std::move(paint),
1343 viewMatrix,
1344 oval,
1345 startAngle,
1346 sweepAngle,
1347 useCenter,
1348 style,
1349 shaderCaps);
1350 if (op) {
1351 this->addDrawOp(clip, std::move(op));
1352 return;
1353 }
1354 }
1355 SkPath path;
1356 SkPathPriv::CreateDrawArcPath(&path, oval, startAngle, sweepAngle, useCenter,
1357 style.isSimpleFill());
1358 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path, style));
1359 }
1360
drawImageLattice(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,int imageWidth,int imageHeight,std::unique_ptr<SkLatticeIter> iter,const SkRect & dst)1361 void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
1362 GrPaint&& paint,
1363 const SkMatrix& viewMatrix,
1364 int imageWidth,
1365 int imageHeight,
1366 std::unique_ptr<SkLatticeIter> iter,
1367 const SkRect& dst) {
1368 ASSERT_SINGLE_OWNER
1369 RETURN_IF_ABANDONED
1370 SkDEBUGCODE(this->validate();)
1371 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawImageLattice", fContext);
1372
1373 AutoCheckFlush acf(this->drawingManager());
1374
1375 std::unique_ptr<GrDrawOp> op = GrLatticeOp::MakeNonAA(std::move(paint), viewMatrix, imageWidth,
1376 imageHeight, std::move(iter), dst);
1377 this->addDrawOp(clip, std::move(op));
1378 }
1379
prepareForExternalIO(int numSemaphores,GrBackendSemaphore backendSemaphores[])1380 GrSemaphoresSubmitted GrRenderTargetContext::prepareForExternalIO(
1381 int numSemaphores, GrBackendSemaphore backendSemaphores[]) {
1382 ASSERT_SINGLE_OWNER
1383 if (this->drawingManager()->wasAbandoned()) { return GrSemaphoresSubmitted::kNo; }
1384 SkDEBUGCODE(this->validate();)
1385 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "prepareForExternalIO", fContext);
1386
1387 return this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get(),
1388 numSemaphores,
1389 backendSemaphores);
1390 }
1391
waitOnSemaphores(int numSemaphores,const GrBackendSemaphore * waitSemaphores)1392 bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
1393 const GrBackendSemaphore* waitSemaphores) {
1394 ASSERT_SINGLE_OWNER
1395 RETURN_FALSE_IF_ABANDONED
1396 SkDEBUGCODE(this->validate();)
1397 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "waitOnSemaphores", fContext);
1398
1399 AutoCheckFlush acf(this->drawingManager());
1400
1401 if (numSemaphores && !this->caps()->fenceSyncSupport()) {
1402 return false;
1403 }
1404
1405 auto resourceProvider = fContext->contextPriv().resourceProvider();
1406
1407 SkTArray<sk_sp<GrSemaphore>> semaphores(numSemaphores);
1408 for (int i = 0; i < numSemaphores; ++i) {
1409 sk_sp<GrSemaphore> sema = resourceProvider->wrapBackendSemaphore(
1410 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
1411 kAdopt_GrWrapOwnership);
1412 std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(sema, fRenderTargetProxy.get()));
1413 this->getRTOpList()->addOp(std::move(waitOp), *this->caps());
1414 }
1415 return true;
1416 }
1417
insertEventMarker(const SkString & str)1418 void GrRenderTargetContext::insertEventMarker(const SkString& str) {
1419 std::unique_ptr<GrOp> op(GrDebugMarkerOp::Make(fRenderTargetProxy.get(), str));
1420 this->getRTOpList()->addOp(std::move(op), *this->caps());
1421 }
1422
1423
1424 // Can 'path' be drawn as a pair of filled nested rectangles?
fills_as_nested_rects(const SkMatrix & viewMatrix,const SkPath & path,SkRect rects[2])1425 static bool fills_as_nested_rects(const SkMatrix& viewMatrix, const SkPath& path, SkRect rects[2]) {
1426
1427 if (path.isInverseFillType()) {
1428 return false;
1429 }
1430
1431 // TODO: this restriction could be lifted if we were willing to apply
1432 // the matrix to all the points individually rather than just to the rect
1433 if (!viewMatrix.rectStaysRect()) {
1434 return false;
1435 }
1436
1437 SkPath::Direction dirs[2];
1438 if (!path.isNestedFillRects(rects, dirs)) {
1439 return false;
1440 }
1441
1442 if (SkPath::kWinding_FillType == path.getFillType() && dirs[0] == dirs[1]) {
1443 // The two rects need to be wound opposite to each other
1444 return false;
1445 }
1446
1447 // Right now, nested rects where the margin is not the same width
1448 // all around do not render correctly
1449 const SkScalar* outer = rects[0].asScalars();
1450 const SkScalar* inner = rects[1].asScalars();
1451
1452 bool allEq = true;
1453
1454 SkScalar margin = SkScalarAbs(outer[0] - inner[0]);
1455 bool allGoE1 = margin >= SK_Scalar1;
1456
1457 for (int i = 1; i < 4; ++i) {
1458 SkScalar temp = SkScalarAbs(outer[i] - inner[i]);
1459 if (temp < SK_Scalar1) {
1460 allGoE1 = false;
1461 }
1462 if (!SkScalarNearlyEqual(margin, temp)) {
1463 allEq = false;
1464 }
1465 }
1466
1467 return allEq || allGoE1;
1468 }
1469
drawPath(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkPath & path,const GrStyle & style)1470 void GrRenderTargetContext::drawPath(const GrClip& clip,
1471 GrPaint&& paint,
1472 GrAA aa,
1473 const SkMatrix& viewMatrix,
1474 const SkPath& path,
1475 const GrStyle& style) {
1476 ASSERT_SINGLE_OWNER
1477 RETURN_IF_ABANDONED
1478 SkDEBUGCODE(this->validate();)
1479 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawPath", fContext);
1480
1481 GrShape shape(path, style);
1482 if (shape.isEmpty()) {
1483 if (shape.inverseFilled()) {
1484 this->drawPaint(clip, std::move(paint), viewMatrix);
1485 }
1486 return;
1487 }
1488
1489 AutoCheckFlush acf(this->drawingManager());
1490
1491 if (!shape.style().hasPathEffect()) {
1492 SkRRect rrect;
1493 // We can ignore the starting point and direction since there is no path effect.
1494 bool inverted;
1495 if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
1496 if (rrect.isRect()) {
1497 this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(),
1498 &shape.style());
1499 return;
1500 } else if (rrect.isOval()) {
1501 this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style());
1502 return;
1503 }
1504 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style());
1505 return;
1506 }
1507 }
1508
1509 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1510 if (GrAAType::kCoverage == aaType) {
1511 // TODO: Make GrShape check for nested rects.
1512 SkRect rects[2];
1513 if (shape.style().isSimpleFill() && fills_as_nested_rects(viewMatrix, path, rects)) {
1514 // Concave AA paths are expensive - try to avoid them for special cases
1515 SkRect rects[2];
1516
1517 if (fills_as_nested_rects(viewMatrix, path, rects)) {
1518 std::unique_ptr<GrDrawOp> op =
1519 GrRectOpFactory::MakeAAFillNestedRects(std::move(paint), viewMatrix, rects);
1520 if (op) {
1521 this->addDrawOp(clip, std::move(op));
1522 }
1523 // A null return indicates that there is nothing to draw in this case.
1524 return;
1525 }
1526 }
1527 }
1528 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape);
1529 }
1530
drawAndStencilPath(const GrHardClip & clip,const GrUserStencilSettings * ss,SkRegion::Op op,bool invert,GrAA aa,const SkMatrix & viewMatrix,const SkPath & path)1531 bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
1532 const GrUserStencilSettings* ss,
1533 SkRegion::Op op,
1534 bool invert,
1535 GrAA aa,
1536 const SkMatrix& viewMatrix,
1537 const SkPath& path) {
1538 ASSERT_SINGLE_OWNER_PRIV
1539 RETURN_FALSE_IF_ABANDONED_PRIV
1540 SkDEBUGCODE(fRenderTargetContext->validate();)
1541 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilPath",
1542 fRenderTargetContext->fContext);
1543
1544 if (path.isEmpty() && path.isInverseFillType()) {
1545 this->drawAndStencilRect(clip, ss, op, invert, GrAA::kNo, SkMatrix::I(),
1546 SkRect::MakeIWH(fRenderTargetContext->width(),
1547 fRenderTargetContext->height()));
1548 return true;
1549 }
1550
1551 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
1552
1553 // An Assumption here is that path renderer would use some form of tweaking
1554 // the src color (either the input alpha or in the frag shader) to implement
1555 // aa. If we have some future driver-mojo path AA that can do the right
1556 // thing WRT to the blend then we'll need some query on the PR.
1557 GrAAType aaType = fRenderTargetContext->chooseAAType(aa, GrAllowMixedSamples::kNo);
1558 bool hasUserStencilSettings = !ss->isUnused();
1559
1560 SkIRect clipConservativeBounds;
1561 clip.getConservativeBounds(fRenderTargetContext->width(), fRenderTargetContext->height(),
1562 &clipConservativeBounds, nullptr);
1563
1564 GrShape shape(path, GrStyle::SimpleFill());
1565 GrPathRenderer::CanDrawPathArgs canDrawArgs;
1566 canDrawArgs.fCaps = fRenderTargetContext->drawingManager()->getContext()->caps();
1567 canDrawArgs.fViewMatrix = &viewMatrix;
1568 canDrawArgs.fShape = &shape;
1569 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1570 canDrawArgs.fAAType = aaType;
1571 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
1572
1573 // Don't allow the SW renderer
1574 GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer(
1575 canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor);
1576 if (!pr) {
1577 return false;
1578 }
1579
1580 GrPaint paint;
1581 paint.setCoverageSetOpXPFactory(op, invert);
1582
1583 GrPathRenderer::DrawPathArgs args{fRenderTargetContext->drawingManager()->getContext(),
1584 std::move(paint),
1585 ss,
1586 fRenderTargetContext,
1587 &clip,
1588 &clipConservativeBounds,
1589 &viewMatrix,
1590 &shape,
1591 aaType,
1592 fRenderTargetContext->colorSpaceInfo().isGammaCorrect()};
1593 pr->drawPath(args);
1594 return true;
1595 }
1596
isBudgeted() const1597 SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
1598 ASSERT_SINGLE_OWNER_PRIV
1599
1600 if (fRenderTargetContext->wasAbandoned()) {
1601 return SkBudgeted::kNo;
1602 }
1603
1604 SkDEBUGCODE(fRenderTargetContext->validate();)
1605
1606 return fRenderTargetContext->fRenderTargetProxy->isBudgeted();
1607 }
1608
drawShapeUsingPathRenderer(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const GrShape & originalShape)1609 void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
1610 GrPaint&& paint,
1611 GrAA aa,
1612 const SkMatrix& viewMatrix,
1613 const GrShape& originalShape) {
1614 ASSERT_SINGLE_OWNER
1615 RETURN_IF_ABANDONED
1616 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext);
1617
1618 SkIRect clipConservativeBounds;
1619 clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
1620
1621 GrShape tempShape;
1622 // NVPR cannot handle hairlines, so this would get picked up by a different stencil and
1623 // cover path renderer (i.e. default path renderer). The hairline renderer produces much
1624 // smoother hairlines than MSAA.
1625 GrAllowMixedSamples allowMixedSamples = originalShape.style().isSimpleHairline()
1626 ? GrAllowMixedSamples::kNo
1627 : GrAllowMixedSamples::kYes;
1628 GrAAType aaType = this->chooseAAType(aa, allowMixedSamples);
1629 GrPathRenderer::CanDrawPathArgs canDrawArgs;
1630 canDrawArgs.fCaps = this->drawingManager()->getContext()->caps();
1631 canDrawArgs.fViewMatrix = &viewMatrix;
1632 canDrawArgs.fShape = &originalShape;
1633 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1634 canDrawArgs.fHasUserStencilSettings = false;
1635
1636 GrPathRenderer* pr;
1637 static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
1638 if (originalShape.isEmpty() && !originalShape.inverseFilled()) {
1639 return;
1640 }
1641
1642 canDrawArgs.fAAType = aaType;
1643
1644 // Try a 1st time without applying any of the style to the geometry (and barring sw)
1645 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
1646 SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
1647
1648 if (!pr && originalShape.style().pathEffect()) {
1649 // It didn't work above, so try again with the path effect applied.
1650 tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
1651 if (tempShape.isEmpty()) {
1652 return;
1653 }
1654 canDrawArgs.fShape = &tempShape;
1655 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
1656 }
1657 if (!pr) {
1658 if (canDrawArgs.fShape->style().applies()) {
1659 tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec,
1660 styleScale);
1661 if (tempShape.isEmpty()) {
1662 return;
1663 }
1664 canDrawArgs.fShape = &tempShape;
1665 }
1666 // This time, allow SW renderer
1667 pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
1668 }
1669
1670 if (!pr) {
1671 #ifdef SK_DEBUG
1672 SkDebugf("Unable to find path renderer compatible with path.\n");
1673 #endif
1674 return;
1675 }
1676
1677 GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
1678 std::move(paint),
1679 &GrUserStencilSettings::kUnused,
1680 this,
1681 &clip,
1682 &clipConservativeBounds,
1683 &viewMatrix,
1684 canDrawArgs.fShape,
1685 aaType,
1686 this->colorSpaceInfo().isGammaCorrect()};
1687 pr->drawPath(args);
1688 }
1689
op_bounds(SkRect * bounds,const GrOp * op)1690 static void op_bounds(SkRect* bounds, const GrOp* op) {
1691 *bounds = op->bounds();
1692 if (op->hasZeroArea()) {
1693 if (op->hasAABloat()) {
1694 bounds->outset(0.5f, 0.5f);
1695 } else {
1696 // We don't know which way the particular GPU will snap lines or points at integer
1697 // coords. So we ensure that the bounds is large enough for either snap.
1698 SkRect before = *bounds;
1699 bounds->roundOut(bounds);
1700 if (bounds->fLeft == before.fLeft) {
1701 bounds->fLeft -= 1;
1702 }
1703 if (bounds->fTop == before.fTop) {
1704 bounds->fTop -= 1;
1705 }
1706 if (bounds->fRight == before.fRight) {
1707 bounds->fRight += 1;
1708 }
1709 if (bounds->fBottom == before.fBottom) {
1710 bounds->fBottom += 1;
1711 }
1712 }
1713 }
1714 }
1715
addDrawOp(const GrClip & clip,std::unique_ptr<GrDrawOp> op)1716 uint32_t GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op) {
1717 ASSERT_SINGLE_OWNER
1718 if (this->drawingManager()->wasAbandoned()) {
1719 return SK_InvalidUniqueID;
1720 }
1721 SkDEBUGCODE(this->validate();)
1722 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "addDrawOp", fContext);
1723
1724 // Setup clip
1725 SkRect bounds;
1726 op_bounds(&bounds, op.get());
1727 GrAppliedClip appliedClip;
1728 GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags();
1729 if (!clip.apply(fContext, this, fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA,
1730 fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil, &appliedClip,
1731 &bounds)) {
1732 return SK_InvalidUniqueID;
1733 }
1734
1735 if (fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil ||
1736 appliedClip.hasStencilClip()) {
1737 this->getOpList()->setStencilLoadOp(GrLoadOp::kClear);
1738
1739 this->setNeedsStencil();
1740 }
1741
1742 GrPixelConfigIsClamped dstIsClamped =
1743 GrGetPixelConfigIsClamped(this->colorSpaceInfo().config());
1744 GrXferProcessor::DstProxy dstProxy;
1745 if (GrDrawOp::RequiresDstTexture::kYes == op->finalize(*this->caps(), &appliedClip,
1746 dstIsClamped)) {
1747 if (!this->setupDstProxy(this->asRenderTargetProxy(), clip, op->bounds(), &dstProxy)) {
1748 return SK_InvalidUniqueID;
1749 }
1750 }
1751
1752 op->setClippedBounds(bounds);
1753 return this->getRTOpList()->addOp(std::move(op), *this->caps(),
1754 std::move(appliedClip), dstProxy);
1755 }
1756
setupDstProxy(GrRenderTargetProxy * rtProxy,const GrClip & clip,const SkRect & opBounds,GrXferProcessor::DstProxy * dstProxy)1757 bool GrRenderTargetContext::setupDstProxy(GrRenderTargetProxy* rtProxy, const GrClip& clip,
1758 const SkRect& opBounds,
1759 GrXferProcessor::DstProxy* dstProxy) {
1760 if (this->caps()->textureBarrierSupport()) {
1761 if (GrTextureProxy* texProxy = rtProxy->asTextureProxy()) {
1762 // The render target is a texture, so we can read from it directly in the shader. The XP
1763 // will be responsible to detect this situation and request a texture barrier.
1764 dstProxy->setProxy(sk_ref_sp(texProxy));
1765 dstProxy->setOffset(0, 0);
1766 return true;
1767 }
1768 }
1769
1770 SkIRect copyRect = SkIRect::MakeWH(rtProxy->width(), rtProxy->height());
1771
1772 SkIRect clippedRect;
1773 clip.getConservativeBounds(rtProxy->width(), rtProxy->height(), &clippedRect);
1774 SkIRect drawIBounds;
1775 opBounds.roundOut(&drawIBounds);
1776 // Cover up for any precision issues by outsetting the op bounds a pixel in each direction.
1777 drawIBounds.outset(1, 1);
1778 if (!clippedRect.intersect(drawIBounds)) {
1779 #ifdef SK_DEBUG
1780 GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw.");
1781 #endif
1782 return false;
1783 }
1784
1785 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
1786 // have per-sample dst values by making the copy multisampled.
1787 GrSurfaceDesc desc;
1788 bool rectsMustMatch = false;
1789 bool disallowSubrect = false;
1790 if (!this->caps()->initDescForDstCopy(rtProxy, &desc, &rectsMustMatch, &disallowSubrect)) {
1791 desc.fFlags = kRenderTarget_GrSurfaceFlag;
1792 desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
1793 desc.fConfig = rtProxy->config();
1794 }
1795
1796 if (!disallowSubrect) {
1797 copyRect = clippedRect;
1798 }
1799
1800 SkIPoint dstPoint, dstOffset;
1801 SkBackingFit fit;
1802 if (rectsMustMatch) {
1803 SkASSERT(desc.fOrigin == rtProxy->origin());
1804 desc.fWidth = rtProxy->width();
1805 desc.fHeight = rtProxy->height();
1806 dstPoint = {copyRect.fLeft, copyRect.fTop};
1807 dstOffset = {0, 0};
1808 fit = SkBackingFit::kExact;
1809 } else {
1810 desc.fWidth = copyRect.width();
1811 desc.fHeight = copyRect.height();
1812 dstPoint = {0, 0};
1813 dstOffset = {copyRect.fLeft, copyRect.fTop};
1814 fit = SkBackingFit::kApprox;
1815 }
1816
1817 sk_sp<GrSurfaceContext> sContext = fContext->contextPriv().makeDeferredSurfaceContext(
1818 desc,
1819 GrMipMapped::kNo,
1820 fit,
1821 SkBudgeted::kYes);
1822 if (!sContext) {
1823 SkDebugf("setupDstTexture: surfaceContext creation failed.\n");
1824 return false;
1825 }
1826
1827 if (!sContext->copy(rtProxy, copyRect, dstPoint)) {
1828 SkDebugf("setupDstTexture: copy failed.\n");
1829 return false;
1830 }
1831
1832 dstProxy->setProxy(sContext->asTextureProxyRef());
1833 dstProxy->setOffset(dstOffset);
1834 return true;
1835 }
1836