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 "GrCaps.h"
15 #include "GrColor.h"
16 #include "GrContextPriv.h"
17 #include "GrDrawingManager.h"
18 #include "GrFixedClip.h"
19 #include "GrGpuResourcePriv.h"
20 #include "GrMemoryPool.h"
21 #include "GrOpList.h"
22 #include "GrPathRenderer.h"
23 #include "GrQuad.h"
24 #include "GrRecordingContext.h"
25 #include "GrRecordingContextPriv.h"
26 #include "GrRenderTarget.h"
27 #include "GrRenderTargetContextPriv.h"
28 #include "GrResourceProvider.h"
29 #include "GrShape.h"
30 #include "GrStencilAttachment.h"
31 #include "GrStyle.h"
32 #include "GrTracing.h"
33 #include "SkDrawable.h"
34 #include "SkDrawShadowInfo.h"
35 #include "SkGlyphRunPainter.h"
36 #include "SkGr.h"
37 #include "SkLatticeIter.h"
38 #include "SkMatrixPriv.h"
39 #include "SkRRectPriv.h"
40 #include "SkShadowUtils.h"
41 #include "SkSurfacePriv.h"
42 #include "effects/GrRRectEffect.h"
43 #include "effects/GrTextureDomain.h"
44 #include "ops/GrAtlasTextOp.h"
45 #include "ops/GrClearOp.h"
46 #include "ops/GrClearStencilClipOp.h"
47 #include "ops/GrDebugMarkerOp.h"
48 #include "ops/GrDrawableOp.h"
49 #include "ops/GrDrawAtlasOp.h"
50 #include "ops/GrDrawOp.h"
51 #include "ops/GrDrawVerticesOp.h"
52 #include "ops/GrFillRectOp.h"
53 #include "ops/GrAAFillRRectOp.h"
54 #include "ops/GrLatticeOp.h"
55 #include "ops/GrOp.h"
56 #include "ops/GrOvalOpFactory.h"
57 #include "ops/GrRegionOp.h"
58 #include "ops/GrSemaphoreOp.h"
59 #include "ops/GrShadowRRectOp.h"
60 #include "ops/GrStencilPathOp.h"
61 #include "ops/GrStrokeRectOp.h"
62 #include "ops/GrTextureOp.h"
63 #include "text/GrTextContext.h"
64 #include "text/GrTextTarget.h"
65
66 class GrRenderTargetContext::TextTarget : public GrTextTarget {
67 public:
TextTarget(GrRenderTargetContext * renderTargetContext)68 TextTarget(GrRenderTargetContext* renderTargetContext)
69 : GrTextTarget(renderTargetContext->width(), renderTargetContext->height(),
70 renderTargetContext->colorSpaceInfo())
71 , fRenderTargetContext(renderTargetContext)
72 , fGlyphPainter{*renderTargetContext}{}
73
addDrawOp(const GrClip & clip,std::unique_ptr<GrAtlasTextOp> op)74 void addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) override {
75 fRenderTargetContext->addDrawOp(clip, std::move(op));
76 }
77
drawShape(const GrClip & clip,const SkPaint & paint,const SkMatrix & viewMatrix,const GrShape & shape)78 void drawShape(const GrClip& clip, const SkPaint& paint,
79 const SkMatrix& viewMatrix, const GrShape& shape) override {
80 GrBlurUtils::drawShapeWithMaskFilter(fRenderTargetContext->fContext, fRenderTargetContext,
81 clip, paint, viewMatrix, shape);
82 }
83
makeGrPaint(GrMaskFormat maskFormat,const SkPaint & skPaint,const SkMatrix & viewMatrix,GrPaint * grPaint)84 void makeGrPaint(GrMaskFormat maskFormat, const SkPaint& skPaint, const SkMatrix& viewMatrix,
85 GrPaint* grPaint) override {
86 auto context = fRenderTargetContext->fContext;
87 const GrColorSpaceInfo& colorSpaceInfo = fRenderTargetContext->colorSpaceInfo();
88 if (kARGB_GrMaskFormat == maskFormat) {
89 SkPaintToGrPaintWithPrimitiveColor(context, colorSpaceInfo, skPaint, grPaint);
90 } else {
91 SkPaintToGrPaint(context, colorSpaceInfo, skPaint, viewMatrix, grPaint);
92 }
93 }
94
getContext()95 GrRecordingContext* getContext() override {
96 return fRenderTargetContext->fContext;
97 }
98
glyphPainter()99 SkGlyphRunListPainter* glyphPainter() override {
100 return &fGlyphPainter;
101 }
102
103 private:
104 GrRenderTargetContext* fRenderTargetContext;
105 SkGlyphRunListPainter fGlyphPainter;
106
107 };
108
109 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
110 #define ASSERT_SINGLE_OWNER \
111 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
112 #define ASSERT_SINGLE_OWNER_PRIV \
113 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
114 #define RETURN_IF_ABANDONED if (fContext->priv().abandoned()) { return; }
115 #define RETURN_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return; }
116 #define RETURN_FALSE_IF_ABANDONED if (fContext->priv().abandoned()) { return false; }
117 #define RETURN_FALSE_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return false; }
118 #define RETURN_NULL_IF_ABANDONED if (fContext->priv().abandoned()) { return nullptr; }
119
120 //////////////////////////////////////////////////////////////////////////////
121
GrChooseAAType(GrAA aa,GrFSAAType fsaaType,GrAllowMixedSamples allowMixedSamples,const GrCaps & caps)122 GrAAType GrChooseAAType(GrAA aa, GrFSAAType fsaaType, GrAllowMixedSamples allowMixedSamples,
123 const GrCaps& caps) {
124 if (GrAA::kNo == aa) {
125 // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
126 // that.
127 if (fsaaType == GrFSAAType::kUnifiedMSAA && !caps.multisampleDisableSupport()) {
128 return GrAAType::kMSAA;
129 }
130 return GrAAType::kNone;
131 }
132 switch (fsaaType) {
133 case GrFSAAType::kNone:
134 return GrAAType::kCoverage;
135 case GrFSAAType::kUnifiedMSAA:
136 return GrAAType::kMSAA;
137 case GrFSAAType::kMixedSamples:
138 return GrAllowMixedSamples::kYes == allowMixedSamples ? GrAAType::kMixedSamples
139 : GrAAType::kCoverage;
140 }
141 SK_ABORT("Unexpected fsaa type");
142 return GrAAType::kNone;
143 }
144
145 //////////////////////////////////////////////////////////////////////////////
146
147 class AutoCheckFlush {
148 public:
AutoCheckFlush(GrDrawingManager * drawingManager)149 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
150 SkASSERT(fDrawingManager);
151 }
~AutoCheckFlush()152 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
153
154 private:
155 GrDrawingManager* fDrawingManager;
156 };
157
158 // In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress
159 // GrOpLists to be picked up and added to by renderTargetContexts lower in the call
160 // stack. When this occurs with a closed GrOpList, a new one will be allocated
161 // when the renderTargetContext attempts to use it (via getOpList).
GrRenderTargetContext(GrRecordingContext * context,sk_sp<GrRenderTargetProxy> rtp,sk_sp<SkColorSpace> colorSpace,const SkSurfaceProps * surfaceProps,bool managedOpList)162 GrRenderTargetContext::GrRenderTargetContext(GrRecordingContext* context,
163 sk_sp<GrRenderTargetProxy> rtp,
164 sk_sp<SkColorSpace> colorSpace,
165 const SkSurfaceProps* surfaceProps,
166 bool managedOpList)
167 : GrSurfaceContext(context, rtp->config(), std::move(colorSpace))
168 , fRenderTargetProxy(std::move(rtp))
169 , fOpList(sk_ref_sp(fRenderTargetProxy->getLastRenderTargetOpList()))
170 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
171 , fManagedOpList(managedOpList) {
172 if (!context->priv().explicitlyAllocateGPUResources()) {
173 // MDB TODO: to ensure all resources still get allocated in the correct order in the hybrid
174 // world we need to get the correct opList here so that it, in turn, can grab and hold
175 // its rendertarget.
176 this->getRTOpList();
177 }
178
179 fTextTarget.reset(new TextTarget(this));
180 SkDEBUGCODE(this->validate();)
181 }
182
183 #ifdef SK_DEBUG
validate() const184 void GrRenderTargetContext::validate() const {
185 SkASSERT(fRenderTargetProxy);
186 fRenderTargetProxy->validate(fContext);
187
188 if (fOpList && !fOpList->isClosed()) {
189 SkASSERT(fRenderTargetProxy->getLastOpList() == fOpList.get());
190 }
191 }
192 #endif
193
~GrRenderTargetContext()194 GrRenderTargetContext::~GrRenderTargetContext() {
195 ASSERT_SINGLE_OWNER
196 }
197
asTextureProxy()198 GrTextureProxy* GrRenderTargetContext::asTextureProxy() {
199 return fRenderTargetProxy->asTextureProxy();
200 }
201
asTextureProxy() const202 const GrTextureProxy* GrRenderTargetContext::asTextureProxy() const {
203 return fRenderTargetProxy->asTextureProxy();
204 }
205
asTextureProxyRef()206 sk_sp<GrTextureProxy> GrRenderTargetContext::asTextureProxyRef() {
207 return sk_ref_sp(fRenderTargetProxy->asTextureProxy());
208 }
209
mipMapped() const210 GrMipMapped GrRenderTargetContext::mipMapped() const {
211 if (const GrTextureProxy* proxy = this->asTextureProxy()) {
212 return proxy->mipMapped();
213 }
214 return GrMipMapped::kNo;
215 }
216
getRTOpList()217 GrRenderTargetOpList* GrRenderTargetContext::getRTOpList() {
218 ASSERT_SINGLE_OWNER
219 SkDEBUGCODE(this->validate();)
220
221 if (!fOpList || fOpList->isClosed()) {
222 fOpList = this->drawingManager()->newRTOpList(fRenderTargetProxy.get(), fManagedOpList);
223 }
224
225 return fOpList.get();
226 }
227
getOpList()228 GrOpList* GrRenderTargetContext::getOpList() {
229 return this->getRTOpList();
230 }
231
drawGlyphRunList(const GrClip & clip,const SkMatrix & viewMatrix,const SkGlyphRunList & blob)232 void GrRenderTargetContext::drawGlyphRunList(
233 const GrClip& clip, const SkMatrix& viewMatrix,
234 const SkGlyphRunList& blob) {
235 ASSERT_SINGLE_OWNER
236 RETURN_IF_ABANDONED
237 SkDEBUGCODE(this->validate();)
238 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawGlyphRunList", fContext);
239
240 // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
241 // secondary command buffers because it would require stopping and starting a render pass which
242 // we don't have access to.
243 if (this->wrapsVkSecondaryCB()) {
244 return;
245 }
246
247 GrTextContext* atlasTextContext = this->drawingManager()->getTextContext();
248 atlasTextContext->drawGlyphRunList(fContext, fTextTarget.get(), clip, viewMatrix,
249 fSurfaceProps, blob);
250 }
251
discard()252 void GrRenderTargetContext::discard() {
253 ASSERT_SINGLE_OWNER
254 RETURN_IF_ABANDONED
255 SkDEBUGCODE(this->validate();)
256 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext);
257
258 AutoCheckFlush acf(this->drawingManager());
259
260 this->getRTOpList()->discard();
261 }
262
clear(const SkIRect * rect,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)263 void GrRenderTargetContext::clear(const SkIRect* rect,
264 const SkPMColor4f& color,
265 CanClearFullscreen canClearFullscreen) {
266 ASSERT_SINGLE_OWNER
267 RETURN_IF_ABANDONED
268 SkDEBUGCODE(this->validate();)
269 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext);
270
271 AutoCheckFlush acf(this->drawingManager());
272 this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color,
273 canClearFullscreen);
274 }
275
clear(const GrFixedClip & clip,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)276 void GrRenderTargetContextPriv::clear(const GrFixedClip& clip,
277 const SkPMColor4f& color,
278 CanClearFullscreen canClearFullscreen) {
279 ASSERT_SINGLE_OWNER_PRIV
280 RETURN_IF_ABANDONED_PRIV
281 SkDEBUGCODE(fRenderTargetContext->validate();)
282 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clear",
283 fRenderTargetContext->fContext);
284
285 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
286 fRenderTargetContext->internalClear(clip, color, canClearFullscreen);
287 }
288
clear_to_grpaint(const SkPMColor4f & color,GrPaint * paint)289 static void clear_to_grpaint(const SkPMColor4f& color, GrPaint* paint) {
290 paint->setColor4f(color);
291 if (color.isOpaque()) {
292 // Can just rely on the src-over blend mode to do the right thing
293 paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
294 } else {
295 // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
296 // were src blended
297 paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
298 }
299 }
300
internalClear(const GrFixedClip & clip,const SkPMColor4f & color,CanClearFullscreen canClearFullscreen)301 void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
302 const SkPMColor4f& color,
303 CanClearFullscreen canClearFullscreen) {
304 bool isFull = false;
305 if (!clip.hasWindowRectangles()) {
306 isFull = !clip.scissorEnabled() ||
307 (CanClearFullscreen::kYes == canClearFullscreen &&
308 this->caps()->preferFullscreenClears()) ||
309 clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
310 }
311
312 if (isFull) {
313 if (this->getRTOpList()->resetForFullscreenClear() &&
314 !this->caps()->performColorClearsAsDraws()) {
315 // The op list was emptied and native clears are allowed, so just use the load op
316 this->getRTOpList()->setColorLoadOp(GrLoadOp::kClear, color);
317 return;
318 } else {
319 // Will use an op for the clear, reset the load op to discard since the op will
320 // blow away the color buffer contents
321 this->getRTOpList()->setColorLoadOp(GrLoadOp::kDiscard);
322 }
323
324 // Must add an op to the list (either because we couldn't use a load op, or because the
325 // clear load op isn't supported)
326 if (this->caps()->performColorClearsAsDraws()) {
327 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
328 GrPaint paint;
329 clear_to_grpaint(color, &paint);
330 this->addDrawOp(GrFixedClip::Disabled(),
331 GrFillRectOp::Make(fContext, std::move(paint),
332 GrAAType::kNone, SkMatrix::I(), rtRect));
333 } else {
334 this->getRTOpList()->addOp(GrClearOp::Make(fContext, SkIRect::MakeEmpty(), color,
335 /* fullscreen */ true), *this->caps());
336 }
337 } else {
338 if (this->caps()->performPartialClearsAsDraws()) {
339 // performPartialClearsAsDraws() also returns true if any clear has to be a draw.
340 SkRect scissor = SkRect::Make(clip.scissorRect());
341 GrPaint paint;
342 clear_to_grpaint(color, &paint);
343
344 this->addDrawOp(clip, GrFillRectOp::Make(fContext, std::move(paint), GrAAType::kNone,
345 SkMatrix::I(), scissor));
346 } else {
347 std::unique_ptr<GrOp> op(GrClearOp::Make(fContext, clip, color,
348 this->asSurfaceProxy()));
349 // This version of the clear op factory can return null if the clip doesn't intersect
350 // with the surface proxy's boundary
351 if (!op) {
352 return;
353 }
354 this->getRTOpList()->addOp(std::move(op), *this->caps());
355 }
356 }
357 }
358
absClear(const SkIRect * clearRect,const SkPMColor4f & color)359 void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const SkPMColor4f& color) {
360 ASSERT_SINGLE_OWNER_PRIV
361 RETURN_IF_ABANDONED_PRIV
362 SkDEBUGCODE(fRenderTargetContext->validate();)
363 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "absClear",
364 fRenderTargetContext->fContext);
365
366 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
367
368 SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth(),
369 fRenderTargetContext->fRenderTargetProxy->worstCaseHeight());
370
371 if (clearRect) {
372 if (clearRect->contains(rtRect)) {
373 clearRect = nullptr; // full screen
374 } else {
375 if (!rtRect.intersect(*clearRect)) {
376 return;
377 }
378 }
379 }
380
381 // TODO: in a post-MDB world this should be handled at the OpList level.
382 // This makes sure to always add an op to the list, instead of marking the clear as a load op.
383 // This code follows very similar logic to internalClear() below, but critical differences are
384 // highlighted in line related to absClear()'s unique behavior.
385 if (clearRect) {
386 if (fRenderTargetContext->caps()->performPartialClearsAsDraws()) {
387 GrPaint paint;
388 clear_to_grpaint(color, &paint);
389
390 // Use the disabled clip; the rect geometry already matches the clear rectangle and
391 // if it were added to a scissor, that would be intersected with the logical surface
392 // bounds and not the worst case dimensions required here.
393 fRenderTargetContext->addDrawOp(GrFixedClip::Disabled(),
394 GrFillRectOp::Make(fRenderTargetContext->fContext,
395 std::move(paint),
396 GrAAType::kNone,
397 SkMatrix::I(),
398 SkRect::Make(rtRect)));
399 } else {
400 // Must use the ClearOp factory that takes a boolean (false) instead of a surface
401 // proxy. The surface proxy variant would intersect the clip rect with its logical
402 // bounds, which is not desired in this special case.
403 fRenderTargetContext->getRTOpList()->addOp(
404 GrClearOp::Make(fRenderTargetContext->fContext, rtRect, color,
405 /* fullscreen */ false),
406 *fRenderTargetContext->caps());
407 }
408 } else {
409 // Reset the oplist like in internalClear(), but do not rely on a load op for the clear
410 fRenderTargetContext->getRTOpList()->resetForFullscreenClear();
411 fRenderTargetContext->getRTOpList()->setColorLoadOp(GrLoadOp::kDiscard);
412
413 if (fRenderTargetContext->caps()->performColorClearsAsDraws()) {
414 // This draws a quad covering the worst case dimensions instead of just the logical
415 // width and height like in internalClear().
416 GrPaint paint;
417 clear_to_grpaint(color, &paint);
418 fRenderTargetContext->addDrawOp(GrFixedClip::Disabled(),
419 GrFillRectOp::Make(fRenderTargetContext->fContext,
420 std::move(paint),
421 GrAAType::kNone,
422 SkMatrix::I(),
423 SkRect::Make(rtRect)));
424 } else {
425 // Nothing special about this path in absClear compared to internalClear()
426 fRenderTargetContext->getRTOpList()->addOp(
427 GrClearOp::Make(fRenderTargetContext->fContext, SkIRect::MakeEmpty(), color,
428 /* fullscreen */ true),
429 *fRenderTargetContext->caps());
430 }
431 }
432 }
433
drawPaint(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix)434 void GrRenderTargetContext::drawPaint(const GrClip& clip,
435 GrPaint&& paint,
436 const SkMatrix& viewMatrix) {
437 ASSERT_SINGLE_OWNER
438 RETURN_IF_ABANDONED
439 SkDEBUGCODE(this->validate();)
440 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPaint", fContext);
441
442 // set rect to be big enough to fill the space, but not super-huge, so we
443 // don't overflow fixed-point implementations
444
445 SkRect r = fRenderTargetProxy->getBoundsRect();
446
447 // Check if we can optimize a clipped drawPaint(). We only do the transformation when there are
448 // no fragment processors because they may depend on having correct local coords and this path
449 // draws in device space without a local matrix. It currently handles converting clipRRect()
450 // to drawRRect() and solid colors to screen-filling drawRects() (which are then converted into
451 // clears if possible in drawRect).
452 if (!paint.numTotalFragmentProcessors()) {
453 SkRRect rrect;
454 GrAA aa = GrAA::kNo;
455 if (clip.isRRect(r, &rrect, &aa)) {
456 if (rrect.isRect()) {
457 // Use drawFilledRect() with no clip and the reduced rectangle
458 this->drawFilledRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect.rect());
459 } else {
460 // Use drawRRect() with no clip
461 this->drawRRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect,
462 GrStyle::SimpleFill());
463 }
464 } else {
465 // Use drawFilledRect() with no view matrix to draw a fullscreen quad, but preserve
466 // the clip. Since the paint has no FPs we can drop the view matrix without worrying
467 // about local coordinates. If the clip is simple, drawFilledRect() will turn this into
468 // a clear or a scissored clear.
469 this->drawFilledRect(clip, std::move(paint), aa, SkMatrix::I(), r);
470 }
471 return;
472 }
473
474 // Since the paint is not trivial, there's no way at this point drawRect() could have converted
475 // this drawPaint() into an optimized clear. drawRect() would then use GrFillRectOp without
476 // a local matrix, so we can simplify things and use the local matrix variant to draw a screen
477 // filling rect with the inverse view matrix for local coords, which works for all matrix
478 // conditions.
479 SkMatrix localMatrix;
480 if (!viewMatrix.invert(&localMatrix)) {
481 return;
482 }
483
484 AutoCheckFlush acf(this->drawingManager());
485 std::unique_ptr<GrDrawOp> op = GrFillRectOp::MakeWithLocalMatrix(
486 fContext, std::move(paint), GrAAType::kNone, SkMatrix::I(), localMatrix, r);
487 this->addDrawOp(clip, std::move(op));
488 }
489
rect_contains_inclusive(const SkRect & rect,const SkPoint & point)490 static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
491 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
492 point.fY >= rect.fTop && point.fY <= rect.fBottom;
493 }
494
495 // Attempts to crop a rect and optional local rect to the clip boundaries.
496 // 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)497 static bool crop_filled_rect(int width, int height, const GrClip& clip,
498 const SkMatrix& viewMatrix, SkRect* rect,
499 SkRect* localRect = nullptr) {
500 if (!viewMatrix.rectStaysRect()) {
501 return true;
502 }
503
504 SkIRect clipDevBounds;
505 SkRect clipBounds;
506
507 clip.getConservativeBounds(width, height, &clipDevBounds);
508 if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) {
509 return false;
510 }
511
512 if (localRect) {
513 if (!rect->intersects(clipBounds)) {
514 return false;
515 }
516 const SkScalar dx = localRect->width() / rect->width();
517 const SkScalar dy = localRect->height() / rect->height();
518 if (clipBounds.fLeft > rect->fLeft) {
519 localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx;
520 rect->fLeft = clipBounds.fLeft;
521 }
522 if (clipBounds.fTop > rect->fTop) {
523 localRect->fTop += (clipBounds.fTop - rect->fTop) * dy;
524 rect->fTop = clipBounds.fTop;
525 }
526 if (clipBounds.fRight < rect->fRight) {
527 localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx;
528 rect->fRight = clipBounds.fRight;
529 }
530 if (clipBounds.fBottom < rect->fBottom) {
531 localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy;
532 rect->fBottom = clipBounds.fBottom;
533 }
534 return true;
535 }
536
537 return rect->intersect(clipBounds);
538 }
539
drawFilledRectAsClear(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect)540 bool GrRenderTargetContext::drawFilledRectAsClear(const GrClip& clip, GrPaint&& paint, GrAA aa,
541 const SkMatrix& viewMatrix, const SkRect& rect) {
542 // Rules for a filled rect to become a clear [+scissor]:
543 // 1. The paint is a constant blend color with no other FPs
544 // 2. The view matrix maps rectangles to rectangles, or the transformed quad fully covers
545 // the render target (or clear region in #3).
546 // 3. The clip is an intersection of rectangles, so the clear region will be the
547 // intersection of the clip and the provided rect.
548 // 4. The clear region aligns with pixel bounds
549 // 5. There are no user stencil settings (and since the clip was IOR, the clip won't need
550 // to use the stencil either).
551 // If all conditions pass, the filled rect can either be a fullscreen clear (if it's big
552 // enough), or the rectangle geometry will be used as the scissor clip on the clear.
553 // If everything passes but rule #4, this submits a simplified fill rect op instead so that the
554 // rounding differences between clip and draws don't fight each other.
555 // NOTE: we route draws into clear() regardless of performColorClearsAsDraws() since the
556 // clear call is allowed to reset the oplist even when it also happens to use a GrFillRectOp.
557
558 SkPMColor4f clearColor;
559 if (paint.numCoverageFragmentProcessors() > 0 || !paint.isConstantBlendedColor(&clearColor)) {
560 return false;
561 }
562
563 const SkRect rtRect = fRenderTargetProxy->getBoundsRect();
564 // Will be the intersection of render target, clip, and quad
565 SkRect combinedRect = rtRect;
566
567 SkRRect clipRRect;
568 GrAA clipAA;
569 if (!clip.quickContains(rtRect)) {
570 // If the clip is an rrect with no rounding, then it can replace the full RT bounds as the
571 // limiting region, although we will have to worry about AA. If the clip is anything
572 // more complicated, just punt to the regular fill rect op.
573 if (!clip.isRRect(rtRect, &clipRRect, &clipAA) || !clipRRect.isRect()) {
574 return false;
575 }
576 combinedRect = clipRRect.rect();
577 } else {
578 // The clip is outside the render target, so the clip can be ignored
579 clipAA = GrAA::kNo;
580 }
581
582 if (viewMatrix.rectStaysRect()) {
583 // Skip the extra overhead of inverting the view matrix to see if rtRect is contained in the
584 // drawn rectangle, and instead just intersect rtRect with the transformed rect. It will be
585 // the new clear region.
586 if (!combinedRect.intersect(viewMatrix.mapRect(rect))) {
587 // No intersection means nothing should be drawn, so return true but don't add an op
588 return true;
589 }
590 } else {
591 // If the transformed rectangle does not contain the combined rt and clip, the draw is too
592 // complex to be implemented as a clear
593 SkMatrix invM;
594 if (!viewMatrix.invert(&invM)) {
595 return false;
596 }
597 // The clip region in the rect's local space, so the test becomes the local rect containing
598 // the quad's points.
599 GrQuad quad = GrQuad::MakeFromRect(rtRect, invM);
600 if (!rect_contains_inclusive(rect, quad.point(0)) ||
601 !rect_contains_inclusive(rect, quad.point(1)) ||
602 !rect_contains_inclusive(rect, quad.point(2)) ||
603 !rect_contains_inclusive(rect, quad.point(3))) {
604 // No containment, so rtRect can't be filled by a solid color
605 return false;
606 }
607 // combinedRect can be filled by a solid color but doesn't need to be modified since it's
608 // inside the quad to be drawn.
609 }
610
611 // Almost every condition is met; now it requires that the combined rect align with pixel
612 // boundaries in order for it to become a scissor-clear. Ignore the AA status in this case
613 // since non-AA with partial-pixel coordinates can be rounded differently on the GPU,
614 // leading to unexpected differences between a scissor test and a rasterized quad.
615 // Also skip very small rectangles since the scissor+clear doesn't by us much then.
616 if (combinedRect.contains(rtRect)) {
617 // Full screen clear
618 this->clear(nullptr, clearColor, CanClearFullscreen::kYes);
619 return true;
620 } else if (GrClip::IsPixelAligned(combinedRect) &&
621 combinedRect.width() > 256 && combinedRect.height() > 256) {
622 // Scissor + clear (round shouldn't do anything since we are pixel aligned)
623 SkIRect scissorRect;
624 combinedRect.round(&scissorRect);
625 this->clear(&scissorRect, clearColor, CanClearFullscreen::kNo);
626 return true;
627 }
628
629 // If we got here, we can't use a scissor + clear, but combinedRect represents the correct
630 // geometry combination of quad + clip so we can perform a simplified fill rect op. We do this
631 // mostly to avoid mismatches in rounding logic on the CPU vs. the GPU, which frequently appears
632 // when drawing and clipping something to the same non-AA rect that never-the-less has
633 // non-integer coordinates.
634
635 // For AA, use non-AA only when both clip and draw are non-AA.
636 if (clipAA == GrAA::kYes) {
637 aa = GrAA::kYes;
638 }
639 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
640 this->addDrawOp(GrFixedClip::Disabled(),
641 GrFillRectOp::Make(fContext, std::move(paint), aaType, SkMatrix::I(),
642 combinedRect));
643 return true;
644 }
645
drawFilledRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect,const GrUserStencilSettings * ss)646 void GrRenderTargetContext::drawFilledRect(const GrClip& clip,
647 GrPaint&& paint,
648 GrAA aa,
649 const SkMatrix& viewMatrix,
650 const SkRect& rect,
651 const GrUserStencilSettings* ss) {
652
653 if (!ss) {
654 if (this->drawFilledRectAsClear(clip, std::move(paint), aa, viewMatrix, rect)) {
655 return;
656 }
657 // Fall through to fill rect op
658 assert_alive(paint);
659 }
660
661 SkRect croppedRect = rect;
662 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
663 // The rectangle would not be drawn, so no need to add a draw op to the list
664 return;
665 }
666
667 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
668 this->addDrawOp(clip, GrFillRectOp::Make(fContext, std::move(paint), aaType, viewMatrix,
669 croppedRect, ss));
670 }
671
drawRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect,const GrStyle * style)672 void GrRenderTargetContext::drawRect(const GrClip& clip,
673 GrPaint&& paint,
674 GrAA aa,
675 const SkMatrix& viewMatrix,
676 const SkRect& rect,
677 const GrStyle* style) {
678 if (!style) {
679 style = &GrStyle::SimpleFill();
680 }
681 ASSERT_SINGLE_OWNER
682 RETURN_IF_ABANDONED
683 SkDEBUGCODE(this->validate();)
684 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRect", fContext);
685
686 // Path effects should've been devolved to a path in SkGpuDevice
687 SkASSERT(!style->pathEffect());
688
689 AutoCheckFlush acf(this->drawingManager());
690
691 const SkStrokeRec& stroke = style->strokeRec();
692 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
693 this->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect);
694 return;
695 } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
696 stroke.getStyle() == SkStrokeRec::kHairline_Style) {
697 if ((!rect.width() || !rect.height()) &&
698 SkStrokeRec::kHairline_Style != stroke.getStyle()) {
699 SkScalar r = stroke.getWidth() / 2;
700 // TODO: Move these stroke->fill fallbacks to GrShape?
701 switch (stroke.getJoin()) {
702 case SkPaint::kMiter_Join:
703 this->drawRect(
704 clip, std::move(paint), aa, viewMatrix,
705 {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r},
706 &GrStyle::SimpleFill());
707 return;
708 case SkPaint::kRound_Join:
709 // Raster draws nothing when both dimensions are empty.
710 if (rect.width() || rect.height()){
711 SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
712 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect,
713 GrStyle::SimpleFill());
714 return;
715 }
716 case SkPaint::kBevel_Join:
717 if (!rect.width()) {
718 this->drawRect(clip, std::move(paint), aa, viewMatrix,
719 {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
720 &GrStyle::SimpleFill());
721 } else {
722 this->drawRect(clip, std::move(paint), aa, viewMatrix,
723 {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
724 &GrStyle::SimpleFill());
725 }
726 return;
727 }
728 }
729
730 std::unique_ptr<GrDrawOp> op;
731
732 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
733 op = GrStrokeRectOp::Make(fContext, std::move(paint), aaType, viewMatrix, rect, stroke);
734 // op may be null if the stroke is not supported or if using coverage aa and the view matrix
735 // does not preserve rectangles.
736 if (op) {
737 this->addDrawOp(clip, std::move(op));
738 return;
739 }
740 }
741 assert_alive(paint);
742 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style));
743 }
744
drawQuadSet(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const QuadSetEntry quads[],int cnt)745 void GrRenderTargetContext::drawQuadSet(const GrClip& clip, GrPaint&& paint, GrAA aa,
746 const SkMatrix& viewMatrix, const QuadSetEntry quads[],
747 int cnt) {
748 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
749 this->addDrawOp(clip, GrFillRectOp::MakeSet(fContext, std::move(paint), aaType, viewMatrix,
750 quads, cnt));
751 }
752
maxWindowRectangles() const753 int GrRenderTargetContextPriv::maxWindowRectangles() const {
754 return fRenderTargetContext->fRenderTargetProxy->maxWindowRectangles(
755 *fRenderTargetContext->caps());
756 }
757
clearStencilClip(const GrFixedClip & clip,bool insideStencilMask)758 void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
759 ASSERT_SINGLE_OWNER_PRIV
760 RETURN_IF_ABANDONED_PRIV
761 SkDEBUGCODE(fRenderTargetContext->validate();)
762 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clearStencilClip",
763 fRenderTargetContext->fContext);
764
765 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
766
767 fRenderTargetContext->internalStencilClear(clip, insideStencilMask);
768 }
769
internalStencilClear(const GrFixedClip & clip,bool insideStencilMask)770 void GrRenderTargetContext::internalStencilClear(const GrFixedClip& clip, bool insideStencilMask) {
771 if (this->caps()->performStencilClearsAsDraws()) {
772 const GrUserStencilSettings* ss = GrStencilSettings::SetClipBitSettings(insideStencilMask);
773 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
774
775 // Configure the paint to have no impact on the color buffer
776 GrPaint paint;
777 paint.setColor4f({0.f, 0.f, 0.f, 0.f});
778 paint.setPorterDuffXPFactory(SkBlendMode::kSrcOver);
779
780 // Mark stencil usage here before addDrawOp() so that it doesn't try to re-call
781 // internalStencilClear() just because the op has stencil settings.
782 this->setNeedsStencil();
783 this->addDrawOp(clip, GrFillRectOp::Make(fContext, std::move(paint),
784 GrAAType::kNone, SkMatrix::I(), rtRect, ss));
785 } else {
786 std::unique_ptr<GrOp> op(GrClearStencilClipOp::Make(fContext, clip, insideStencilMask,
787 fRenderTargetProxy.get()));
788 if (!op) {
789 return;
790 }
791 this->getRTOpList()->addOp(std::move(op), *this->caps());
792 }
793 }
794
stencilPath(const GrHardClip & clip,GrAAType aaType,const SkMatrix & viewMatrix,const GrPath * path)795 void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
796 GrAAType aaType,
797 const SkMatrix& viewMatrix,
798 const GrPath* path) {
799 ASSERT_SINGLE_OWNER_PRIV
800 RETURN_IF_ABANDONED_PRIV
801 SkDEBUGCODE(fRenderTargetContext->validate();)
802 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilPath",
803 fRenderTargetContext->fContext);
804
805 SkASSERT(aaType != GrAAType::kCoverage);
806
807 bool useHWAA = GrAATypeIsHW(aaType);
808 // TODO: extract portions of checkDraw that are relevant to path stenciling.
809 SkASSERT(path);
810 SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
811
812 // FIXME: Use path bounds instead of this WAR once
813 // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
814 SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height());
815
816 // Setup clip
817 GrAppliedHardClip appliedClip;
818 if (!clip.apply(fRenderTargetContext->width(), fRenderTargetContext->height(), &appliedClip,
819 &bounds)) {
820 return;
821 }
822
823 fRenderTargetContext->setNeedsStencil();
824
825 std::unique_ptr<GrOp> op = GrStencilPathOp::Make(fRenderTargetContext->fContext,
826 viewMatrix,
827 useHWAA,
828 path->getFillType(),
829 appliedClip.hasStencilClip(),
830 appliedClip.scissorState(),
831 path);
832 if (!op) {
833 return;
834 }
835 op->setClippedBounds(bounds);
836 fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
837 }
838
stencilRect(const GrHardClip & clip,const GrUserStencilSettings * ss,GrAAType aaType,const SkMatrix & viewMatrix,const SkRect & rect)839 void GrRenderTargetContextPriv::stencilRect(const GrHardClip& clip,
840 const GrUserStencilSettings* ss,
841 GrAAType aaType,
842 const SkMatrix& viewMatrix,
843 const SkRect& rect) {
844 ASSERT_SINGLE_OWNER_PRIV
845 RETURN_IF_ABANDONED_PRIV
846 SkDEBUGCODE(fRenderTargetContext->validate();)
847 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilRect",
848 fRenderTargetContext->fContext);
849
850 SkASSERT(GrAAType::kCoverage != aaType);
851 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
852
853 GrPaint paint;
854 paint.setXPFactory(GrDisableColorXPFactory::Get());
855 std::unique_ptr<GrDrawOp> op = GrFillRectOp::Make(
856 fRenderTargetContext->fContext, std::move(paint), aaType, viewMatrix, rect, ss);
857 fRenderTargetContext->addDrawOp(clip, std::move(op));
858 }
859
drawAndStencilRect(const GrHardClip & clip,const GrUserStencilSettings * ss,SkRegion::Op op,bool invert,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rect)860 bool GrRenderTargetContextPriv::drawAndStencilRect(const GrHardClip& clip,
861 const GrUserStencilSettings* ss,
862 SkRegion::Op op,
863 bool invert,
864 GrAA aa,
865 const SkMatrix& viewMatrix,
866 const SkRect& rect) {
867 ASSERT_SINGLE_OWNER_PRIV
868 RETURN_FALSE_IF_ABANDONED_PRIV
869 SkDEBUGCODE(fRenderTargetContext->validate();)
870 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilRect",
871 fRenderTargetContext->fContext);
872
873 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
874
875 GrPaint paint;
876 paint.setCoverageSetOpXPFactory(op, invert);
877
878 // This will always succeed to draw a rectangle
879 fRenderTargetContext->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect, ss);
880 return true;
881 }
882
fillRectWithEdgeAA(const GrClip & clip,GrPaint && paint,GrAA aa,GrQuadAAFlags edgeAA,const SkMatrix & viewMatrix,const SkRect & rect,const SkRect * localRect)883 void GrRenderTargetContext::fillRectWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa,
884 GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix,
885 const SkRect& rect, const SkRect* localRect) {
886 ASSERT_SINGLE_OWNER
887 RETURN_IF_ABANDONED
888 SkDEBUGCODE(this->validate();)
889 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithEdgeAA", fContext);
890
891 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
892 std::unique_ptr<GrDrawOp> op;
893
894 if (localRect) {
895 // If local coordinates are provided, skip the optimization check to go through
896 // drawFilledRect, and also calculate clipped local coordinates
897 SkRect croppedRect = rect;
898 SkRect croppedLocalRect = *localRect;
899 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect,
900 &croppedLocalRect)) {
901 return;
902 }
903 op = GrFillRectOp::MakePerEdgeWithLocalRect(fContext, std::move(paint), aaType, edgeAA,
904 viewMatrix, croppedRect, croppedLocalRect);
905 } else {
906 // If aaType turns into MSAA, make sure to keep quads with no AA edges as MSAA. Sending
907 // those to drawFilledRect() would have it turn off MSAA in that case, which breaks seaming
908 // with any partial AA edges that kept MSAA.
909 if (aaType != GrAAType::kMSAA &&
910 (edgeAA == GrQuadAAFlags::kNone || edgeAA == GrQuadAAFlags::kAll)) {
911 // This is equivalent to a regular filled rect draw, so route through there to take
912 // advantage of draw->clear optimizations
913 this->drawFilledRect(clip, std::move(paint), GrAA(edgeAA == GrQuadAAFlags::kAll),
914 viewMatrix, rect);
915 return;
916 }
917
918 SkRect croppedRect = rect;
919 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
920 return;
921 }
922 op = GrFillRectOp::MakePerEdge(fContext, std::move(paint), aaType, edgeAA, viewMatrix,
923 croppedRect);
924 }
925
926 AutoCheckFlush acf(this->drawingManager());
927 this->addDrawOp(clip, std::move(op));
928 }
929
fillQuadWithEdgeAA(const GrClip & clip,GrPaint && paint,GrAA aa,GrQuadAAFlags edgeAA,const SkMatrix & viewMatrix,const SkPoint quad[4],const SkPoint localQuad[4])930 void GrRenderTargetContext::fillQuadWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa,
931 GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix,
932 const SkPoint quad[4], const SkPoint localQuad[4]) {
933 ASSERT_SINGLE_OWNER
934 RETURN_IF_ABANDONED
935 SkDEBUGCODE(this->validate();)
936 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillQuadWithEdgeAA", fContext);
937
938 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
939
940 AutoCheckFlush acf(this->drawingManager());
941 // MakePerEdgeQuad automatically does the right thing if localQuad is null or not
942 this->addDrawOp(clip, GrFillRectOp::MakePerEdgeQuad(fContext, std::move(paint), aaType, edgeAA,
943 viewMatrix, quad, localQuad));
944 }
945
946 // Creates a paint for GrFillRectOp that matches behavior of GrTextureOp
draw_texture_to_grpaint(sk_sp<GrTextureProxy> proxy,const SkRect * domain,GrSamplerState::Filter filter,SkBlendMode mode,const SkPMColor4f & color,sk_sp<GrColorSpaceXform> csXform,GrPaint * paint)947 static void draw_texture_to_grpaint(sk_sp<GrTextureProxy> proxy, const SkRect* domain,
948 GrSamplerState::Filter filter, SkBlendMode mode,
949 const SkPMColor4f& color, sk_sp<GrColorSpaceXform> csXform,
950 GrPaint* paint) {
951 paint->setColor4f(color);
952 paint->setXPFactory(SkBlendMode_AsXPFactory(mode));
953
954 std::unique_ptr<GrFragmentProcessor> fp;
955 if (domain) {
956 SkRect correctedDomain = *domain;
957 if (filter == GrSamplerState::Filter::kBilerp) {
958 // Inset by 1/2 pixel, which GrTextureOp and GrTextureAdjuster handle automatically
959 correctedDomain.inset(0.5f, 0.5f);
960 }
961 fp = GrTextureDomainEffect::Make(std::move(proxy), SkMatrix::I(), correctedDomain,
962 GrTextureDomain::kClamp_Mode, filter);
963 } else {
964 fp = GrSimpleTextureEffect::Make(std::move(proxy), SkMatrix::I(), filter);
965 }
966
967 fp = GrColorSpaceXformEffect::Make(std::move(fp), csXform);
968 paint->addColorFragmentProcessor(std::move(fp));
969 }
970
drawTexture(const GrClip & clip,sk_sp<GrTextureProxy> proxy,GrSamplerState::Filter filter,SkBlendMode mode,const SkPMColor4f & color,const SkRect & srcRect,const SkRect & dstRect,GrAA aa,GrQuadAAFlags aaFlags,SkCanvas::SrcRectConstraint constraint,const SkMatrix & viewMatrix,sk_sp<GrColorSpaceXform> textureColorSpaceXform)971 void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
972 GrSamplerState::Filter filter, SkBlendMode mode,
973 const SkPMColor4f& color, const SkRect& srcRect,
974 const SkRect& dstRect, GrAA aa, GrQuadAAFlags aaFlags,
975 SkCanvas::SrcRectConstraint constraint,
976 const SkMatrix& viewMatrix,
977 sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
978 ASSERT_SINGLE_OWNER
979 RETURN_IF_ABANDONED
980 SkDEBUGCODE(this->validate();)
981 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTexture", fContext);
982 if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
983 srcRect.contains(proxy->getWorstCaseBoundsRect())) {
984 constraint = SkCanvas::kFast_SrcRectConstraint;
985 }
986
987 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
988 SkRect clippedDstRect = dstRect;
989 SkRect clippedSrcRect = srcRect;
990 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &clippedDstRect,
991 &clippedSrcRect)) {
992 return;
993 }
994
995 AutoCheckFlush acf(this->drawingManager());
996
997 std::unique_ptr<GrDrawOp> op;
998 if (mode != SkBlendMode::kSrcOver) {
999 // Emulation mode with GrPaint and GrFillRectOp
1000 if (filter != GrSamplerState::Filter::kNearest &&
1001 !GrTextureOp::GetFilterHasEffect(viewMatrix, clippedSrcRect, clippedDstRect)) {
1002 filter = GrSamplerState::Filter::kNearest;
1003 }
1004
1005 GrPaint paint;
1006 draw_texture_to_grpaint(std::move(proxy),
1007 constraint == SkCanvas::kStrict_SrcRectConstraint ? &srcRect : nullptr,
1008 filter, mode, color, std::move(textureColorSpaceXform), &paint);
1009 op = GrFillRectOp::MakePerEdgeWithLocalRect(fContext, std::move(paint), aaType, aaFlags,
1010 viewMatrix, clippedDstRect, clippedSrcRect);
1011 } else {
1012 // Can use a lighter weight op that can chain across proxies
1013 op = GrTextureOp::Make(fContext, std::move(proxy), filter, color, clippedSrcRect,
1014 clippedDstRect, aaType, aaFlags, constraint, viewMatrix,
1015 std::move(textureColorSpaceXform));
1016 }
1017
1018 this->addDrawOp(clip, std::move(op));
1019 }
1020
drawTextureQuad(const GrClip & clip,sk_sp<GrTextureProxy> proxy,GrSamplerState::Filter filter,SkBlendMode mode,const SkPMColor4f & color,const SkPoint srcQuad[4],const SkPoint dstQuad[4],GrAA aa,GrQuadAAFlags aaFlags,const SkRect * domain,const SkMatrix & viewMatrix,sk_sp<GrColorSpaceXform> texXform)1021 void GrRenderTargetContext::drawTextureQuad(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
1022 GrSamplerState::Filter filter, SkBlendMode mode,
1023 const SkPMColor4f& color, const SkPoint srcQuad[4],
1024 const SkPoint dstQuad[4], GrAA aa,
1025 GrQuadAAFlags aaFlags, const SkRect* domain,
1026 const SkMatrix& viewMatrix,
1027 sk_sp<GrColorSpaceXform> texXform) {
1028 ASSERT_SINGLE_OWNER
1029 RETURN_IF_ABANDONED
1030 SkDEBUGCODE(this->validate();)
1031 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureQuad", fContext);
1032 if (domain && domain->contains(proxy->getWorstCaseBoundsRect())) {
1033 domain = nullptr;
1034 }
1035
1036 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1037
1038 // Unlike drawTexture(), don't bother cropping or optimizing the filter type since we're
1039 // sampling an arbitrary quad of the texture.
1040 AutoCheckFlush acf(this->drawingManager());
1041 std::unique_ptr<GrDrawOp> op;
1042 if (mode != SkBlendMode::kSrcOver) {
1043 // Emulation mode, but don't bother converting to kNearest filter since it's an arbitrary
1044 // quad that is being drawn, which makes the tests too expensive here
1045 GrPaint paint;
1046 draw_texture_to_grpaint(
1047 std::move(proxy), domain, filter, mode, color, std::move(texXform), &paint);
1048 op = GrFillRectOp::MakePerEdgeQuad(fContext, std::move(paint), aaType, aaFlags, viewMatrix,
1049 dstQuad, srcQuad);
1050 } else {
1051 // Use lighter weight GrTextureOp
1052 op = GrTextureOp::MakeQuad(fContext, std::move(proxy), filter, color, srcQuad, dstQuad,
1053 aaType, aaFlags, domain, viewMatrix, std::move(texXform));
1054 }
1055
1056 this->addDrawOp(clip, std::move(op));
1057 }
1058
drawTextureSet(const GrClip & clip,const TextureSetEntry set[],int cnt,GrSamplerState::Filter filter,SkBlendMode mode,GrAA aa,const SkMatrix & viewMatrix,sk_sp<GrColorSpaceXform> texXform)1059 void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetEntry set[], int cnt,
1060 GrSamplerState::Filter filter, SkBlendMode mode,
1061 GrAA aa, const SkMatrix& viewMatrix,
1062 sk_sp<GrColorSpaceXform> texXform) {
1063 ASSERT_SINGLE_OWNER
1064 RETURN_IF_ABANDONED
1065 SkDEBUGCODE(this->validate();)
1066 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureSet", fContext);
1067
1068 if (mode != SkBlendMode::kSrcOver ||
1069 !fContext->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
1070 // Draw one at a time with GrFillRectOp and a GrPaint that emulates what GrTextureOp does
1071 SkMatrix ctm;
1072 for (int i = 0; i < cnt; ++i) {
1073 float alpha = set[i].fAlpha;
1074 ctm = viewMatrix;
1075 if (set[i].fPreViewMatrix) {
1076 ctm.preConcat(*set[i].fPreViewMatrix);
1077 }
1078
1079 if (set[i].fDstClipQuad == nullptr) {
1080 // Stick with original rectangles, which allows the ops to know more about what's
1081 // being drawn.
1082 this->drawTexture(clip, set[i].fProxy, filter, mode, {alpha, alpha, alpha, alpha},
1083 set[i].fSrcRect, set[i].fDstRect, aa, set[i].fAAFlags,
1084 SkCanvas::kFast_SrcRectConstraint, ctm, texXform);
1085 } else {
1086 // Generate interpolated texture coordinates to match the dst clip
1087 SkPoint srcQuad[4];
1088 GrMapRectPoints(set[i].fDstRect, set[i].fSrcRect, set[i].fDstClipQuad, srcQuad, 4);
1089 // Don't send srcRect as the domain, since the normal case doesn't use a constraint
1090 // with the entire srcRect, so sampling into dstRect outside of dstClip will just
1091 // keep seams look more correct.
1092 this->drawTextureQuad(clip, set[i].fProxy, filter, mode,
1093 {alpha, alpha, alpha, alpha}, srcQuad, set[i].fDstClipQuad,
1094 aa, set[i].fAAFlags, nullptr, ctm, texXform);
1095 }
1096 }
1097 } else {
1098 // Can use a single op, avoiding GrPaint creation, and can batch across proxies
1099 AutoCheckFlush acf(this->drawingManager());
1100 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1101 auto op = GrTextureOp::MakeSet(fContext, set, cnt, filter, aaType, viewMatrix,
1102 std::move(texXform));
1103 this->addDrawOp(clip, std::move(op));
1104 }
1105 }
1106
fillRectWithLocalMatrix(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & rectToDraw,const SkMatrix & localMatrix)1107 void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,
1108 GrPaint&& paint,
1109 GrAA aa,
1110 const SkMatrix& viewMatrix,
1111 const SkRect& rectToDraw,
1112 const SkMatrix& localMatrix) {
1113 ASSERT_SINGLE_OWNER
1114 RETURN_IF_ABANDONED
1115 SkDEBUGCODE(this->validate();)
1116 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithLocalMatrix", fContext);
1117
1118 SkRect croppedRect = rectToDraw;
1119 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
1120 return;
1121 }
1122
1123 AutoCheckFlush acf(this->drawingManager());
1124
1125 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1126 this->addDrawOp(clip, GrFillRectOp::MakeWithLocalMatrix(fContext, std::move(paint), aaType,
1127 viewMatrix, localMatrix, croppedRect));
1128 }
1129
drawVertices(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,sk_sp<SkVertices> vertices,const SkVertices::Bone bones[],int boneCount,GrPrimitiveType * overridePrimType)1130 void GrRenderTargetContext::drawVertices(const GrClip& clip,
1131 GrPaint&& paint,
1132 const SkMatrix& viewMatrix,
1133 sk_sp<SkVertices> vertices,
1134 const SkVertices::Bone bones[],
1135 int boneCount,
1136 GrPrimitiveType* overridePrimType) {
1137 ASSERT_SINGLE_OWNER
1138 RETURN_IF_ABANDONED
1139 SkDEBUGCODE(this->validate();)
1140 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawVertices", fContext);
1141
1142 AutoCheckFlush acf(this->drawingManager());
1143
1144 SkASSERT(vertices);
1145 GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
1146 std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
1147 fContext, std::move(paint), std::move(vertices), bones, boneCount, viewMatrix, aaType,
1148 this->colorSpaceInfo().refColorSpaceXformFromSRGB(), overridePrimType);
1149 this->addDrawOp(clip, std::move(op));
1150 }
1151
1152 ///////////////////////////////////////////////////////////////////////////////
1153
drawAtlas(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,int spriteCount,const SkRSXform xform[],const SkRect texRect[],const SkColor colors[])1154 void GrRenderTargetContext::drawAtlas(const GrClip& clip,
1155 GrPaint&& paint,
1156 const SkMatrix& viewMatrix,
1157 int spriteCount,
1158 const SkRSXform xform[],
1159 const SkRect texRect[],
1160 const SkColor colors[]) {
1161 ASSERT_SINGLE_OWNER
1162 RETURN_IF_ABANDONED
1163 SkDEBUGCODE(this->validate();)
1164 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawAtlas", fContext);
1165
1166 AutoCheckFlush acf(this->drawingManager());
1167
1168 GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
1169 std::unique_ptr<GrDrawOp> op = GrDrawAtlasOp::Make(fContext, std::move(paint), viewMatrix,
1170 aaType, spriteCount, xform, texRect, colors);
1171 this->addDrawOp(clip, std::move(op));
1172 }
1173
1174 ///////////////////////////////////////////////////////////////////////////////
1175
drawRRect(const GrClip & origClip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & rrect,const GrStyle & style)1176 void GrRenderTargetContext::drawRRect(const GrClip& origClip,
1177 GrPaint&& paint,
1178 GrAA aa,
1179 const SkMatrix& viewMatrix,
1180 const SkRRect& rrect,
1181 const GrStyle& style) {
1182 ASSERT_SINGLE_OWNER
1183 RETURN_IF_ABANDONED
1184 SkDEBUGCODE(this->validate();)
1185 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRRect", fContext);
1186
1187 const SkStrokeRec& stroke = style.strokeRec();
1188 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.isEmpty()) {
1189 return;
1190 }
1191
1192 GrNoClip noclip;
1193 const GrClip* clip = &origClip;
1194 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1195 // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
1196 // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it
1197 // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
1198 // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
1199 // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. This
1200 // only works for filled rrects since the stroke width outsets beyond the rrect itself.
1201 SkRRect devRRect;
1202 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.transform(viewMatrix, &devRRect) &&
1203 clip->quickContains(devRRect)) {
1204 clip = &noclip;
1205 }
1206 #endif
1207 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
1208
1209 AutoCheckFlush acf(this->drawingManager());
1210
1211 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1212 if (GrAAType::kCoverage == aaType) {
1213 std::unique_ptr<GrDrawOp> op;
1214 if (style.isSimpleFill()) {
1215 op = GrAAFillRRectOp::Make(fContext, viewMatrix, rrect, *this->caps(),
1216 std::move(paint));
1217 }
1218 if (!op) {
1219 assert_alive(paint);
1220 op = GrOvalOpFactory::MakeRRectOp(fContext, std::move(paint), viewMatrix, rrect, stroke,
1221 this->caps()->shaderCaps());
1222 }
1223
1224 if (op) {
1225 this->addDrawOp(*clip, std::move(op));
1226 return;
1227 }
1228 }
1229
1230 assert_alive(paint);
1231 this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix,
1232 GrShape(rrect, style));
1233 }
1234
1235 ///////////////////////////////////////////////////////////////////////////////
1236
map(const SkMatrix & m,const SkPoint3 & pt)1237 static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
1238 SkPoint3 result;
1239 m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
1240 result.fZ = pt.fZ;
1241 return result;
1242 }
1243
drawFastShadow(const GrClip & clip,const SkMatrix & viewMatrix,const SkPath & path,const SkDrawShadowRec & rec)1244 bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
1245 const SkMatrix& viewMatrix,
1246 const SkPath& path,
1247 const SkDrawShadowRec& rec) {
1248 ASSERT_SINGLE_OWNER
1249 if (fContext->priv().abandoned()) {
1250 return true;
1251 }
1252 SkDEBUGCODE(this->validate();)
1253 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFastShadow", fContext);
1254
1255 // check z plane
1256 bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1257 !SkScalarNearlyZero(rec.fZPlaneParams.fY));
1258 bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1259 if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1260 return false;
1261 }
1262
1263 SkRRect rrect;
1264 SkRect rect;
1265 // we can only handle rects, circles, and rrects with circular corners
1266 bool isRRect = path.isRRect(&rrect) && SkRRectPriv::IsSimpleCircular(rrect) &&
1267 rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero;
1268 if (!isRRect &&
1269 path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1270 rect.width() > SK_ScalarNearlyZero) {
1271 rrect.setOval(rect);
1272 isRRect = true;
1273 }
1274 if (!isRRect && path.isRect(&rect)) {
1275 rrect.setRect(rect);
1276 isRRect = true;
1277 }
1278
1279 if (!isRRect) {
1280 return false;
1281 }
1282
1283 if (rrect.isEmpty()) {
1284 return true;
1285 }
1286
1287 AutoCheckFlush acf(this->drawingManager());
1288
1289 // transform light
1290 SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
1291
1292 // 1/scale
1293 SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1294 SkScalarInvert(viewMatrix[SkMatrix::kMScaleX]) :
1295 sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1296 viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1297
1298 SkScalar occluderHeight = rec.fZPlaneParams.fZ;
1299 bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1300
1301 if (SkColorGetA(rec.fAmbientColor) > 0) {
1302 SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1303 const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1304 const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
1305
1306 // Outset the shadow rrect to the border of the penumbra
1307 SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1308 SkRRect ambientRRect;
1309 SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1310 // If the rrect was an oval then its outset will also be one.
1311 // We set it explicitly to avoid errors.
1312 if (rrect.isOval()) {
1313 ambientRRect = SkRRect::MakeOval(outsetRect);
1314 } else {
1315 SkScalar outsetRad = SkRRectPriv::GetSimpleRadii(rrect).fX + ambientPathOutset;
1316 ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1317 }
1318
1319 GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
1320 if (transparent) {
1321 // set a large inset to force a fill
1322 devSpaceInsetWidth = ambientRRect.width();
1323 }
1324
1325 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1326 ambientColor,
1327 viewMatrix,
1328 ambientRRect,
1329 devSpaceAmbientBlur,
1330 devSpaceInsetWidth);
1331 SkASSERT(op);
1332 this->addDrawOp(clip, std::move(op));
1333 }
1334
1335 if (SkColorGetA(rec.fSpotColor) > 0) {
1336 SkScalar devSpaceSpotBlur;
1337 SkScalar spotScale;
1338 SkVector spotOffset;
1339 SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1340 devLightPos.fZ, rec.fLightRadius,
1341 &devSpaceSpotBlur, &spotScale, &spotOffset);
1342 // handle scale of radius due to CTM
1343 const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1344
1345 // Adjust translate for the effect of the scale.
1346 spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1347 spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1348 // This offset is in dev space, need to transform it into source space.
1349 SkMatrix ctmInverse;
1350 if (viewMatrix.invert(&ctmInverse)) {
1351 ctmInverse.mapPoints(&spotOffset, 1);
1352 } else {
1353 // Since the matrix is a similarity, this should never happen, but just in case...
1354 SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1355 SkASSERT(false);
1356 }
1357
1358 // Compute the transformed shadow rrect
1359 SkRRect spotShadowRRect;
1360 SkMatrix shadowTransform;
1361 shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1362 rrect.transform(shadowTransform, &spotShadowRRect);
1363 SkScalar spotRadius = SkRRectPriv::GetSimpleRadii(spotShadowRRect).fX;
1364
1365 // Compute the insetWidth
1366 SkScalar blurOutset = srcSpaceSpotBlur;
1367 SkScalar insetWidth = blurOutset;
1368 if (transparent) {
1369 // If transparent, just do a fill
1370 insetWidth += spotShadowRRect.width();
1371 } else {
1372 // For shadows, instead of using a stroke we specify an inset from the penumbra
1373 // border. We want to extend this inset area so that it meets up with the caster
1374 // geometry. The inset geometry will by default already be inset by the blur width.
1375 //
1376 // We compare the min and max corners inset by the radius between the original
1377 // rrect and the shadow rrect. The distance between the two plus the difference
1378 // between the scaled radius and the original radius gives the distance from the
1379 // transformed shadow shape to the original shape in that corner. The max
1380 // of these gives the maximum distance we need to cover.
1381 //
1382 // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1383 // that to get the full insetWidth.
1384 SkScalar maxOffset;
1385 if (rrect.isRect()) {
1386 // Manhattan distance works better for rects
1387 maxOffset = SkTMax(SkTMax(SkTAbs(spotShadowRRect.rect().fLeft -
1388 rrect.rect().fLeft),
1389 SkTAbs(spotShadowRRect.rect().fTop -
1390 rrect.rect().fTop)),
1391 SkTMax(SkTAbs(spotShadowRRect.rect().fRight -
1392 rrect.rect().fRight),
1393 SkTAbs(spotShadowRRect.rect().fBottom -
1394 rrect.rect().fBottom)));
1395 } else {
1396 SkScalar dr = spotRadius - SkRRectPriv::GetSimpleRadii(rrect).fX;
1397 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1398 rrect.rect().fLeft + dr,
1399 spotShadowRRect.rect().fTop -
1400 rrect.rect().fTop + dr);
1401 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1402 rrect.rect().fRight - dr,
1403 spotShadowRRect.rect().fBottom -
1404 rrect.rect().fBottom - dr);
1405 maxOffset = SkScalarSqrt(SkTMax(SkPointPriv::LengthSqd(upperLeftOffset),
1406 SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
1407 }
1408 insetWidth += SkTMax(blurOutset, maxOffset);
1409 }
1410
1411 // Outset the shadow rrect to the border of the penumbra
1412 SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1413 if (spotShadowRRect.isOval()) {
1414 spotShadowRRect = SkRRect::MakeOval(outsetRect);
1415 } else {
1416 SkScalar outsetRad = spotRadius + blurOutset;
1417 spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1418 }
1419
1420 GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
1421
1422 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1423 spotColor,
1424 viewMatrix,
1425 spotShadowRRect,
1426 2.0f * devSpaceSpotBlur,
1427 insetWidth);
1428 SkASSERT(op);
1429 this->addDrawOp(clip, std::move(op));
1430 }
1431
1432 return true;
1433 }
1434
1435 ///////////////////////////////////////////////////////////////////////////////
1436
drawFilledDRRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & origOuter,const SkRRect & origInner)1437 bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
1438 GrPaint&& paint,
1439 GrAA aa,
1440 const SkMatrix& viewMatrix,
1441 const SkRRect& origOuter,
1442 const SkRRect& origInner) {
1443 SkASSERT(!origInner.isEmpty());
1444 SkASSERT(!origOuter.isEmpty());
1445
1446 SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
1447
1448 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1449
1450 if (GrAAType::kMSAA == aaType) {
1451 return false;
1452 }
1453
1454 if (GrAAType::kCoverage == aaType && SkRRectPriv::IsCircle(*inner)
1455 && SkRRectPriv::IsCircle(*outer)) {
1456 auto outerR = outer->width() / 2.f;
1457 auto innerR = inner->width() / 2.f;
1458 auto cx = outer->getBounds().fLeft + outerR;
1459 auto cy = outer->getBounds().fTop + outerR;
1460 if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) &&
1461 SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) {
1462 auto avgR = (innerR + outerR) / 2.f;
1463 auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR);
1464 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
1465 stroke.setStrokeStyle(outerR - innerR);
1466 auto op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix,
1467 circleBounds, GrStyle(stroke, nullptr),
1468 this->caps()->shaderCaps());
1469 if (op) {
1470 this->addDrawOp(clip, std::move(op));
1471 return true;
1472 }
1473 assert_alive(paint);
1474 }
1475 }
1476
1477 GrClipEdgeType innerEdgeType, outerEdgeType;
1478 if (GrAAType::kCoverage == aaType) {
1479 innerEdgeType = GrClipEdgeType::kInverseFillAA;
1480 outerEdgeType = GrClipEdgeType::kFillAA;
1481 } else {
1482 innerEdgeType = GrClipEdgeType::kInverseFillBW;
1483 outerEdgeType = GrClipEdgeType::kFillBW;
1484 }
1485
1486 SkMatrix inverseVM;
1487 if (!viewMatrix.isIdentity()) {
1488 if (!origInner.transform(viewMatrix, inner.writable())) {
1489 return false;
1490 }
1491 if (!origOuter.transform(viewMatrix, outer.writable())) {
1492 return false;
1493 }
1494 if (!viewMatrix.invert(&inverseVM)) {
1495 return false;
1496 }
1497 } else {
1498 inverseVM.reset();
1499 }
1500
1501 const auto& caps = *this->caps()->shaderCaps();
1502 // TODO these need to be a geometry processors
1503 auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps);
1504 if (!innerEffect) {
1505 return false;
1506 }
1507
1508 auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps);
1509 if (!outerEffect) {
1510 return false;
1511 }
1512
1513 paint.addCoverageFragmentProcessor(std::move(innerEffect));
1514 paint.addCoverageFragmentProcessor(std::move(outerEffect));
1515
1516 SkRect bounds = outer->getBounds();
1517 if (GrAAType::kCoverage == aaType) {
1518 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1519 }
1520
1521 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds,
1522 inverseVM);
1523 return true;
1524 }
1525
drawDRRect(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRRect & outer,const SkRRect & inner)1526 void GrRenderTargetContext::drawDRRect(const GrClip& clip,
1527 GrPaint&& paint,
1528 GrAA aa,
1529 const SkMatrix& viewMatrix,
1530 const SkRRect& outer,
1531 const SkRRect& inner) {
1532 ASSERT_SINGLE_OWNER
1533 RETURN_IF_ABANDONED
1534 SkDEBUGCODE(this->validate();)
1535 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawDRRect", fContext);
1536
1537 SkASSERT(!outer.isEmpty());
1538 SkASSERT(!inner.isEmpty());
1539
1540 AutoCheckFlush acf(this->drawingManager());
1541
1542 if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) {
1543 return;
1544 }
1545 assert_alive(paint);
1546
1547 SkPath path;
1548 path.setIsVolatile(true);
1549 path.addRRect(inner);
1550 path.addRRect(outer);
1551 path.setFillType(SkPath::kEvenOdd_FillType);
1552 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path));
1553 }
1554
1555 ///////////////////////////////////////////////////////////////////////////////
1556
drawRegion(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRegion & region,const GrStyle & style,const GrUserStencilSettings * ss)1557 void GrRenderTargetContext::drawRegion(const GrClip& clip,
1558 GrPaint&& paint,
1559 GrAA aa,
1560 const SkMatrix& viewMatrix,
1561 const SkRegion& region,
1562 const GrStyle& style,
1563 const GrUserStencilSettings* ss) {
1564 ASSERT_SINGLE_OWNER
1565 RETURN_IF_ABANDONED
1566 SkDEBUGCODE(this->validate();)
1567 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRegion", fContext);
1568
1569 if (GrAA::kYes == aa) {
1570 // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
1571 // to see whether aa is really required.
1572 if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
1573 SkScalarIsInt(viewMatrix.getTranslateX()) &&
1574 SkScalarIsInt(viewMatrix.getTranslateY())) {
1575 aa = GrAA::kNo;
1576 }
1577 }
1578 bool complexStyle = !style.isSimpleFill();
1579 if (complexStyle || GrAA::kYes == aa) {
1580 SkPath path;
1581 region.getBoundaryPath(&path);
1582 path.setIsVolatile(true);
1583
1584 return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
1585 }
1586
1587 GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
1588 std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(fContext, std::move(paint), viewMatrix, region,
1589 aaType, ss);
1590 this->addDrawOp(clip, std::move(op));
1591 }
1592
drawOval(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & oval,const GrStyle & style)1593 void GrRenderTargetContext::drawOval(const GrClip& clip,
1594 GrPaint&& paint,
1595 GrAA aa,
1596 const SkMatrix& viewMatrix,
1597 const SkRect& oval,
1598 const GrStyle& style) {
1599 ASSERT_SINGLE_OWNER
1600 RETURN_IF_ABANDONED
1601 SkDEBUGCODE(this->validate();)
1602 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawOval", fContext);
1603
1604 const SkStrokeRec& stroke = style.strokeRec();
1605
1606 if (oval.isEmpty() && !style.pathEffect()) {
1607 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1608 return;
1609 }
1610
1611 this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
1612 return;
1613 }
1614
1615 AutoCheckFlush acf(this->drawingManager());
1616
1617 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1618 if (GrAAType::kCoverage == aaType) {
1619 std::unique_ptr<GrDrawOp> op;
1620 // GrAAFillRRectOp has special geometry and a fragment-shader branch to conditionally
1621 // evaluate the arc equation. This same special geometry and fragment branch also turn out
1622 // to be a substantial optimization for drawing ovals (namely, by not evaluating the arc
1623 // equation inside the oval's inner diamond). Given these optimizations, it's a clear win to
1624 // draw ovals the exact same way we do round rects.
1625 //
1626 // However, we still don't draw true circles as round rects, because it can cause perf
1627 // regressions on some platforms as compared to the dedicated circle Op.
1628 if (style.isSimpleFill() && oval.height() != oval.width()) {
1629 op = GrAAFillRRectOp::Make(fContext, viewMatrix, SkRRect::MakeOval(oval), *this->caps(),
1630 std::move(paint));
1631 }
1632 if (!op) {
1633 assert_alive(paint);
1634 op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1635 this->caps()->shaderCaps());
1636 }
1637 if (op) {
1638 this->addDrawOp(clip, std::move(op));
1639 return;
1640 }
1641 }
1642
1643 assert_alive(paint);
1644 this->drawShapeUsingPathRenderer(
1645 clip, std::move(paint), aa, viewMatrix,
1646 GrShape(SkRRect::MakeOval(oval), SkPath::kCW_Direction, 2, false, style));
1647 }
1648
drawArc(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkRect & oval,SkScalar startAngle,SkScalar sweepAngle,bool useCenter,const GrStyle & style)1649 void GrRenderTargetContext::drawArc(const GrClip& clip,
1650 GrPaint&& paint,
1651 GrAA aa,
1652 const SkMatrix& viewMatrix,
1653 const SkRect& oval,
1654 SkScalar startAngle,
1655 SkScalar sweepAngle,
1656 bool useCenter,
1657 const GrStyle& style) {
1658 ASSERT_SINGLE_OWNER
1659 RETURN_IF_ABANDONED
1660 SkDEBUGCODE(this->validate();)
1661 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawArc", fContext);
1662
1663 AutoCheckFlush acf(this->drawingManager());
1664
1665 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1666 if (GrAAType::kCoverage == aaType) {
1667 const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
1668 std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(fContext,
1669 std::move(paint),
1670 viewMatrix,
1671 oval,
1672 startAngle,
1673 sweepAngle,
1674 useCenter,
1675 style,
1676 shaderCaps);
1677 if (op) {
1678 this->addDrawOp(clip, std::move(op));
1679 return;
1680 }
1681 assert_alive(paint);
1682 }
1683 this->drawShapeUsingPathRenderer(
1684 clip, std::move(paint), aa, viewMatrix,
1685 GrShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style));
1686 }
1687
drawImageLattice(const GrClip & clip,GrPaint && paint,const SkMatrix & viewMatrix,sk_sp<GrTextureProxy> image,sk_sp<GrColorSpaceXform> csxf,GrSamplerState::Filter filter,std::unique_ptr<SkLatticeIter> iter,const SkRect & dst)1688 void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
1689 GrPaint&& paint,
1690 const SkMatrix& viewMatrix,
1691 sk_sp<GrTextureProxy> image,
1692 sk_sp<GrColorSpaceXform> csxf,
1693 GrSamplerState::Filter filter,
1694 std::unique_ptr<SkLatticeIter> iter,
1695 const SkRect& dst) {
1696 ASSERT_SINGLE_OWNER
1697 RETURN_IF_ABANDONED
1698 SkDEBUGCODE(this->validate();)
1699 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawImageLattice", fContext);
1700
1701 AutoCheckFlush acf(this->drawingManager());
1702
1703 std::unique_ptr<GrDrawOp> op =
1704 GrLatticeOp::MakeNonAA(fContext, std::move(paint), viewMatrix, std::move(image),
1705 std::move(csxf), filter, std::move(iter), dst);
1706 this->addDrawOp(clip, std::move(op));
1707 }
1708
drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,const SkRect & bounds)1709 void GrRenderTargetContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
1710 const SkRect& bounds) {
1711 std::unique_ptr<GrOp> op(GrDrawableOp::Make(fContext, std::move(drawable), bounds));
1712 SkASSERT(op);
1713 this->getRTOpList()->addOp(std::move(op), *this->caps());
1714 }
1715
prepareForExternalIO(SkSurface::BackendSurfaceAccess access,GrFlushFlags flags,int numSemaphores,GrBackendSemaphore backendSemaphores[],GrGpuFinishedProc finishedProc,GrGpuFinishedContext finishedContext)1716 GrSemaphoresSubmitted GrRenderTargetContext::prepareForExternalIO(
1717 SkSurface::BackendSurfaceAccess access, GrFlushFlags flags, int numSemaphores,
1718 GrBackendSemaphore backendSemaphores[], GrGpuFinishedProc finishedProc,
1719 GrGpuFinishedContext finishedContext) {
1720 ASSERT_SINGLE_OWNER
1721 if (fContext->priv().abandoned()) {
1722 return GrSemaphoresSubmitted::kNo;
1723 }
1724 SkDEBUGCODE(this->validate();)
1725 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "prepareForExternalIO", fContext);
1726
1727 return this->drawingManager()->prepareSurfaceForExternalIO(fRenderTargetProxy.get(),
1728 access, flags,
1729 numSemaphores,
1730 backendSemaphores,
1731 finishedProc,
1732 finishedContext);
1733 }
1734
waitOnSemaphores(int numSemaphores,const GrBackendSemaphore waitSemaphores[])1735 bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
1736 const GrBackendSemaphore waitSemaphores[]) {
1737 ASSERT_SINGLE_OWNER
1738 RETURN_FALSE_IF_ABANDONED
1739 SkDEBUGCODE(this->validate();)
1740 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "waitOnSemaphores", fContext);
1741
1742 AutoCheckFlush acf(this->drawingManager());
1743
1744 if (numSemaphores && !this->caps()->fenceSyncSupport()) {
1745 return false;
1746 }
1747
1748 auto direct = fContext->priv().asDirectContext();
1749 if (!direct) {
1750 return false;
1751 }
1752
1753 auto resourceProvider = direct->priv().resourceProvider();
1754
1755 for (int i = 0; i < numSemaphores; ++i) {
1756 sk_sp<GrSemaphore> sema = resourceProvider->wrapBackendSemaphore(
1757 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
1758 kAdopt_GrWrapOwnership);
1759 std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(fContext, std::move(sema),
1760 fRenderTargetProxy.get()));
1761 this->getRTOpList()->addWaitOp(std::move(waitOp), *this->caps());
1762 }
1763 return true;
1764 }
1765
insertEventMarker(const SkString & str)1766 void GrRenderTargetContext::insertEventMarker(const SkString& str) {
1767 std::unique_ptr<GrOp> op(GrDebugMarkerOp::Make(fContext, fRenderTargetProxy.get(), str));
1768 this->getRTOpList()->addOp(std::move(op), *this->caps());
1769 }
1770
caps() const1771 const GrCaps* GrRenderTargetContext::caps() const {
1772 return fContext->priv().caps();
1773 }
1774
drawPath(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const SkPath & path,const GrStyle & style)1775 void GrRenderTargetContext::drawPath(const GrClip& clip,
1776 GrPaint&& paint,
1777 GrAA aa,
1778 const SkMatrix& viewMatrix,
1779 const SkPath& path,
1780 const GrStyle& style) {
1781 ASSERT_SINGLE_OWNER
1782 RETURN_IF_ABANDONED
1783 SkDEBUGCODE(this->validate();)
1784 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPath", fContext);
1785
1786 GrShape shape(path, style);
1787
1788 this->drawShape(clip, std::move(paint), aa, viewMatrix, shape);
1789 }
1790
drawShape(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const GrShape & shape)1791 void GrRenderTargetContext::drawShape(const GrClip& clip,
1792 GrPaint&& paint,
1793 GrAA aa,
1794 const SkMatrix& viewMatrix,
1795 const GrShape& shape) {
1796 ASSERT_SINGLE_OWNER
1797 RETURN_IF_ABANDONED
1798 SkDEBUGCODE(this->validate();)
1799 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawShape", fContext);
1800
1801 if (shape.isEmpty()) {
1802 if (shape.inverseFilled()) {
1803 this->drawPaint(clip, std::move(paint), viewMatrix);
1804 }
1805 return;
1806 }
1807
1808 AutoCheckFlush acf(this->drawingManager());
1809
1810 if (!shape.style().hasPathEffect()) {
1811 GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
1812 SkRRect rrect;
1813 // We can ignore the starting point and direction since there is no path effect.
1814 bool inverted;
1815 if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
1816 if (rrect.isRect()) {
1817 this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(),
1818 &shape.style());
1819 return;
1820 } else if (rrect.isOval()) {
1821 this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style());
1822 return;
1823 }
1824 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style());
1825 return;
1826 } else if (GrAAType::kCoverage == aaType && shape.style().isSimpleFill() &&
1827 viewMatrix.rectStaysRect()) {
1828 // TODO: the rectStaysRect restriction could be lifted if we were willing to apply
1829 // the matrix to all the points individually rather than just to the rect
1830 SkRect rects[2];
1831 if (shape.asNestedRects(rects)) {
1832 // Concave AA paths are expensive - try to avoid them for special cases
1833 std::unique_ptr<GrDrawOp> op = GrStrokeRectOp::MakeNested(
1834 fContext, std::move(paint), viewMatrix, rects);
1835 if (op) {
1836 this->addDrawOp(clip, std::move(op));
1837 }
1838 // Returning here indicates that there is nothing to draw in this case.
1839 return;
1840 }
1841 }
1842 }
1843
1844 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape);
1845 }
1846
drawAndStencilPath(const GrHardClip & clip,const GrUserStencilSettings * ss,SkRegion::Op op,bool invert,GrAA aa,const SkMatrix & viewMatrix,const SkPath & path)1847 bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
1848 const GrUserStencilSettings* ss,
1849 SkRegion::Op op,
1850 bool invert,
1851 GrAA aa,
1852 const SkMatrix& viewMatrix,
1853 const SkPath& path) {
1854 ASSERT_SINGLE_OWNER_PRIV
1855 RETURN_FALSE_IF_ABANDONED_PRIV
1856 SkDEBUGCODE(fRenderTargetContext->validate();)
1857 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilPath",
1858 fRenderTargetContext->fContext);
1859
1860 if (path.isEmpty() && path.isInverseFillType()) {
1861 this->drawAndStencilRect(clip, ss, op, invert, GrAA::kNo, SkMatrix::I(),
1862 SkRect::MakeIWH(fRenderTargetContext->width(),
1863 fRenderTargetContext->height()));
1864 return true;
1865 }
1866
1867 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
1868
1869 // An Assumption here is that path renderer would use some form of tweaking
1870 // the src color (either the input alpha or in the frag shader) to implement
1871 // aa. If we have some future driver-mojo path AA that can do the right
1872 // thing WRT to the blend then we'll need some query on the PR.
1873 GrAAType aaType = fRenderTargetContext->chooseAAType(aa, GrAllowMixedSamples::kNo);
1874 bool hasUserStencilSettings = !ss->isUnused();
1875
1876 SkIRect clipConservativeBounds;
1877 clip.getConservativeBounds(fRenderTargetContext->width(), fRenderTargetContext->height(),
1878 &clipConservativeBounds, nullptr);
1879
1880 GrShape shape(path, GrStyle::SimpleFill());
1881 GrPathRenderer::CanDrawPathArgs canDrawArgs;
1882 canDrawArgs.fCaps = fRenderTargetContext->caps();
1883 canDrawArgs.fViewMatrix = &viewMatrix;
1884 canDrawArgs.fShape = &shape;
1885 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1886 canDrawArgs.fAAType = aaType;
1887 SkASSERT(!fRenderTargetContext->wrapsVkSecondaryCB());
1888 canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
1889 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
1890
1891 // Don't allow the SW renderer
1892 GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer(
1893 canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor);
1894 if (!pr) {
1895 return false;
1896 }
1897
1898 GrPaint paint;
1899 paint.setCoverageSetOpXPFactory(op, invert);
1900
1901 GrPathRenderer::DrawPathArgs args{fRenderTargetContext->drawingManager()->getContext(),
1902 std::move(paint),
1903 ss,
1904 fRenderTargetContext,
1905 &clip,
1906 &clipConservativeBounds,
1907 &viewMatrix,
1908 &shape,
1909 aaType,
1910 fRenderTargetContext->colorSpaceInfo().isLinearlyBlended()};
1911 pr->drawPath(args);
1912 return true;
1913 }
1914
isBudgeted() const1915 SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
1916 ASSERT_SINGLE_OWNER_PRIV
1917
1918 if (fRenderTargetContext->fContext->priv().abandoned()) {
1919 return SkBudgeted::kNo;
1920 }
1921
1922 SkDEBUGCODE(fRenderTargetContext->validate();)
1923
1924 return fRenderTargetContext->fRenderTargetProxy->isBudgeted();
1925 }
1926
drawShapeUsingPathRenderer(const GrClip & clip,GrPaint && paint,GrAA aa,const SkMatrix & viewMatrix,const GrShape & originalShape)1927 void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
1928 GrPaint&& paint,
1929 GrAA aa,
1930 const SkMatrix& viewMatrix,
1931 const GrShape& originalShape) {
1932 ASSERT_SINGLE_OWNER
1933 RETURN_IF_ABANDONED
1934 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext);
1935
1936 if (!viewMatrix.isFinite() || !originalShape.bounds().isFinite()) {
1937 return;
1938 }
1939
1940 SkIRect clipConservativeBounds;
1941 clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
1942
1943 GrShape tempShape;
1944 // NVPR cannot handle hairlines, so this would get picked up by a different stencil and
1945 // cover path renderer (i.e. default path renderer). The hairline renderer produces much
1946 // smoother hairlines than MSAA.
1947 GrAllowMixedSamples allowMixedSamples = originalShape.style().isSimpleHairline()
1948 ? GrAllowMixedSamples::kNo
1949 : GrAllowMixedSamples::kYes;
1950 GrAAType aaType = this->chooseAAType(aa, allowMixedSamples);
1951 GrPathRenderer::CanDrawPathArgs canDrawArgs;
1952 canDrawArgs.fCaps = this->caps();
1953 canDrawArgs.fViewMatrix = &viewMatrix;
1954 canDrawArgs.fShape = &originalShape;
1955 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
1956 canDrawArgs.fTargetIsWrappedVkSecondaryCB = this->wrapsVkSecondaryCB();
1957 canDrawArgs.fHasUserStencilSettings = false;
1958
1959 GrPathRenderer* pr;
1960 static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
1961 if (originalShape.isEmpty() && !originalShape.inverseFilled()) {
1962 return;
1963 }
1964
1965 canDrawArgs.fAAType = aaType;
1966
1967 // Try a 1st time without applying any of the style to the geometry (and barring sw)
1968 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
1969 SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
1970
1971 if (!pr && originalShape.style().pathEffect()) {
1972 // It didn't work above, so try again with the path effect applied.
1973 tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
1974 if (tempShape.isEmpty()) {
1975 return;
1976 }
1977 canDrawArgs.fShape = &tempShape;
1978 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
1979 }
1980 if (!pr) {
1981 if (canDrawArgs.fShape->style().applies()) {
1982 tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec,
1983 styleScale);
1984 if (tempShape.isEmpty()) {
1985 return;
1986 }
1987 canDrawArgs.fShape = &tempShape;
1988 // This time, allow SW renderer
1989 pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
1990 } else {
1991 pr = this->drawingManager()->getSoftwarePathRenderer();
1992 }
1993 }
1994
1995 if (!pr) {
1996 #ifdef SK_DEBUG
1997 SkDebugf("Unable to find path renderer compatible with path.\n");
1998 #endif
1999 return;
2000 }
2001
2002 GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
2003 std::move(paint),
2004 &GrUserStencilSettings::kUnused,
2005 this,
2006 &clip,
2007 &clipConservativeBounds,
2008 &viewMatrix,
2009 canDrawArgs.fShape,
2010 aaType,
2011 this->colorSpaceInfo().isLinearlyBlended()};
2012 pr->drawPath(args);
2013 }
2014
op_bounds(SkRect * bounds,const GrOp * op)2015 static void op_bounds(SkRect* bounds, const GrOp* op) {
2016 *bounds = op->bounds();
2017 if (op->hasZeroArea()) {
2018 if (op->hasAABloat()) {
2019 bounds->outset(0.5f, 0.5f);
2020 } else {
2021 // We don't know which way the particular GPU will snap lines or points at integer
2022 // coords. So we ensure that the bounds is large enough for either snap.
2023 SkRect before = *bounds;
2024 bounds->roundOut(bounds);
2025 if (bounds->fLeft == before.fLeft) {
2026 bounds->fLeft -= 1;
2027 }
2028 if (bounds->fTop == before.fTop) {
2029 bounds->fTop -= 1;
2030 }
2031 if (bounds->fRight == before.fRight) {
2032 bounds->fRight += 1;
2033 }
2034 if (bounds->fBottom == before.fBottom) {
2035 bounds->fBottom += 1;
2036 }
2037 }
2038 }
2039 }
2040
addDrawOp(const GrClip & clip,std::unique_ptr<GrDrawOp> op,const std::function<WillAddOpFn> & willAddFn)2041 void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op,
2042 const std::function<WillAddOpFn>& willAddFn) {
2043 ASSERT_SINGLE_OWNER
2044 if (fContext->priv().abandoned()) {
2045 fContext->priv().opMemoryPool()->release(std::move(op));
2046 return;
2047 }
2048 SkDEBUGCODE(this->validate();)
2049 SkDEBUGCODE(op->fAddDrawOpCalled = true;)
2050 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "addDrawOp", fContext);
2051
2052 // Setup clip
2053 SkRect bounds;
2054 op_bounds(&bounds, op.get());
2055 GrAppliedClip appliedClip;
2056 GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags();
2057 if (!clip.apply(fContext, this, fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA,
2058 fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil, &appliedClip,
2059 &bounds)) {
2060 fContext->priv().opMemoryPool()->release(std::move(op));
2061 return;
2062 }
2063
2064 if (fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil ||
2065 appliedClip.hasStencilClip()) {
2066 if (this->caps()->performStencilClearsAsDraws()) {
2067 // Must use an op to perform the clear of the stencil buffer before this op, but only
2068 // have to clear the first time any draw needs it (this also ensures we don't loop
2069 // forever when the internal stencil clear adds a draw op that has stencil settings).
2070 if (!fRenderTargetProxy->needsStencil()) {
2071 // Send false so that the stencil buffer is fully cleared to 0
2072 this->internalStencilClear(GrFixedClip::Disabled(), /* inside mask */ false);
2073 }
2074 } else {
2075 // Just make sure the stencil buffer is cleared before the draw op, easy to do it as
2076 // a load at the start
2077 this->getRTOpList()->setStencilLoadOp(GrLoadOp::kClear);
2078 }
2079
2080 this->setNeedsStencil();
2081 }
2082
2083 GrClampType clampType = GrPixelConfigClampType(this->colorSpaceInfo().config());
2084 GrXferProcessor::DstProxy dstProxy;
2085 GrProcessorSet::Analysis analysis = op->finalize(
2086 *this->caps(), &appliedClip, this->fsaaType(), clampType);
2087 if (analysis.requiresDstTexture()) {
2088 if (!this->setupDstProxy(this->asRenderTargetProxy(), clip, *op, &dstProxy)) {
2089 fContext->priv().opMemoryPool()->release(std::move(op));
2090 return;
2091 }
2092 }
2093
2094 op->setClippedBounds(bounds);
2095 auto opList = this->getRTOpList();
2096 if (willAddFn) {
2097 willAddFn(op.get(), opList->uniqueID());
2098 }
2099 opList->addDrawOp(std::move(op), analysis, std::move(appliedClip), dstProxy, *this->caps());
2100 }
2101
setupDstProxy(GrRenderTargetProxy * rtProxy,const GrClip & clip,const GrOp & op,GrXferProcessor::DstProxy * dstProxy)2102 bool GrRenderTargetContext::setupDstProxy(GrRenderTargetProxy* rtProxy, const GrClip& clip,
2103 const GrOp& op,
2104 GrXferProcessor::DstProxy* dstProxy) {
2105 // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
2106 // don't actually have a VkImage to make a copy of. Additionally we don't have the power to
2107 // start and stop the render pass in order to make the copy.
2108 if (rtProxy->wrapsVkSecondaryCB()) {
2109 return false;
2110 }
2111
2112 if (this->caps()->textureBarrierSupport()) {
2113 if (GrTextureProxy* texProxy = rtProxy->asTextureProxy()) {
2114 // The render target is a texture, so we can read from it directly in the shader. The XP
2115 // will be responsible to detect this situation and request a texture barrier.
2116 dstProxy->setProxy(sk_ref_sp(texProxy));
2117 dstProxy->setOffset(0, 0);
2118 return true;
2119 }
2120 }
2121
2122 SkIRect copyRect = SkIRect::MakeWH(rtProxy->width(), rtProxy->height());
2123
2124 SkIRect clippedRect;
2125 clip.getConservativeBounds(rtProxy->width(), rtProxy->height(), &clippedRect);
2126 SkRect opBounds = op.bounds();
2127 // If the op has aa bloating or is a infinitely thin geometry (hairline) outset the bounds by
2128 // 0.5 pixels.
2129 if (op.hasAABloat() || op.hasZeroArea()) {
2130 opBounds.outset(0.5f, 0.5f);
2131 // An antialiased/hairline draw can sometimes bleed outside of the clips bounds. For
2132 // performance we may ignore the clip when the draw is entirely inside the clip is float
2133 // space but will hit pixels just outside the clip when actually rasterizing.
2134 clippedRect.outset(1, 1);
2135 clippedRect.intersect(SkIRect::MakeWH(rtProxy->width(), rtProxy->height()));
2136 }
2137 SkIRect opIBounds;
2138 opBounds.roundOut(&opIBounds);
2139 if (!clippedRect.intersect(opIBounds)) {
2140 #ifdef SK_DEBUG
2141 GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw.");
2142 #endif
2143 return false;
2144 }
2145
2146 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
2147 // have per-sample dst values by making the copy multisampled.
2148 GrSurfaceDesc desc;
2149 bool rectsMustMatch = false;
2150 bool disallowSubrect = false;
2151 GrSurfaceOrigin origin;
2152 if (!this->caps()->initDescForDstCopy(rtProxy, &desc, &origin, &rectsMustMatch,
2153 &disallowSubrect)) {
2154 desc.fFlags = kRenderTarget_GrSurfaceFlag;
2155 desc.fConfig = rtProxy->config();
2156 origin = rtProxy->origin();
2157 }
2158
2159 if (!disallowSubrect) {
2160 copyRect = clippedRect;
2161 }
2162
2163 SkIPoint dstPoint, dstOffset;
2164 SkBackingFit fit;
2165 if (rectsMustMatch) {
2166 desc.fWidth = rtProxy->width();
2167 desc.fHeight = rtProxy->height();
2168 dstPoint = {copyRect.fLeft, copyRect.fTop};
2169 dstOffset = {0, 0};
2170 fit = SkBackingFit::kExact;
2171 } else {
2172 desc.fWidth = copyRect.width();
2173 desc.fHeight = copyRect.height();
2174 dstPoint = {0, 0};
2175 dstOffset = {copyRect.fLeft, copyRect.fTop};
2176 fit = SkBackingFit::kApprox;
2177 }
2178
2179 SkASSERT(rtProxy->backendFormat().textureType() == GrTextureType::k2D);
2180 const GrBackendFormat& format = rtProxy->backendFormat();
2181 sk_sp<GrSurfaceContext> sContext = fContext->priv().makeDeferredSurfaceContext(
2182 format, desc, origin, GrMipMapped::kNo, fit, SkBudgeted::kYes,
2183 sk_ref_sp(this->colorSpaceInfo().colorSpace()));
2184 if (!sContext) {
2185 SkDebugf("setupDstTexture: surfaceContext creation failed.\n");
2186 return false;
2187 }
2188
2189 if (!sContext->copy(rtProxy, copyRect, dstPoint)) {
2190 SkDebugf("setupDstTexture: copy failed.\n");
2191 return false;
2192 }
2193
2194 dstProxy->setProxy(sContext->asTextureProxyRef());
2195 dstProxy->setOffset(dstOffset);
2196 return true;
2197 }
2198