blob: 742280d73cf930225576d5c7bf3f557ff6599f78 [file] [log] [blame]
robertphillipsea461502015-05-26 11:38:03 -07001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkDrawable.h"
9#include "include/gpu/GrBackendSemaphore.h"
10#include "include/gpu/GrRenderTarget.h"
11#include "include/private/GrAuditTrail.h"
12#include "include/private/GrColor.h"
13#include "include/private/GrOpList.h"
14#include "include/private/GrRecordingContext.h"
15#include "include/private/SkShadowFlags.h"
16#include "include/utils/SkShadowUtils.h"
Brian Salomoncd734f62019-05-10 16:32:54 -040017#include "src/core/SkAutoPixmapStorage.h"
18#include "src/core/SkConvertPixels.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/core/SkDrawShadowInfo.h"
20#include "src/core/SkGlyphRunPainter.h"
21#include "src/core/SkLatticeIter.h"
22#include "src/core/SkMatrixPriv.h"
23#include "src/core/SkRRectPriv.h"
24#include "src/core/SkSurfacePriv.h"
25#include "src/gpu/GrAppliedClip.h"
26#include "src/gpu/GrBlurUtils.h"
27#include "src/gpu/GrCaps.h"
28#include "src/gpu/GrContextPriv.h"
29#include "src/gpu/GrDrawingManager.h"
30#include "src/gpu/GrFixedClip.h"
31#include "src/gpu/GrGpuResourcePriv.h"
32#include "src/gpu/GrMemoryPool.h"
33#include "src/gpu/GrPathRenderer.h"
34#include "src/gpu/GrQuad.h"
35#include "src/gpu/GrRecordingContextPriv.h"
Mike Kleinad44dd52019-05-14 14:01:39 -050036#include "src/gpu/GrRenderTargetContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050037#include "src/gpu/GrRenderTargetContextPriv.h"
38#include "src/gpu/GrResourceProvider.h"
39#include "src/gpu/GrShape.h"
40#include "src/gpu/GrStencilAttachment.h"
41#include "src/gpu/GrStyle.h"
42#include "src/gpu/GrTracing.h"
43#include "src/gpu/SkGr.h"
44#include "src/gpu/effects/GrRRectEffect.h"
45#include "src/gpu/effects/GrTextureDomain.h"
46#include "src/gpu/ops/GrAtlasTextOp.h"
47#include "src/gpu/ops/GrClearOp.h"
48#include "src/gpu/ops/GrClearStencilClipOp.h"
49#include "src/gpu/ops/GrDebugMarkerOp.h"
50#include "src/gpu/ops/GrDrawAtlasOp.h"
51#include "src/gpu/ops/GrDrawOp.h"
52#include "src/gpu/ops/GrDrawVerticesOp.h"
53#include "src/gpu/ops/GrDrawableOp.h"
54#include "src/gpu/ops/GrFillRRectOp.h"
55#include "src/gpu/ops/GrFillRectOp.h"
56#include "src/gpu/ops/GrLatticeOp.h"
57#include "src/gpu/ops/GrOp.h"
58#include "src/gpu/ops/GrOvalOpFactory.h"
59#include "src/gpu/ops/GrRegionOp.h"
60#include "src/gpu/ops/GrSemaphoreOp.h"
61#include "src/gpu/ops/GrShadowRRectOp.h"
62#include "src/gpu/ops/GrStencilPathOp.h"
63#include "src/gpu/ops/GrStrokeRectOp.h"
64#include "src/gpu/ops/GrTextureOp.h"
Brian Salomonab32f652019-05-10 14:24:50 -040065#include "src/gpu/ops/GrTransferFromOp.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050066#include "src/gpu/text/GrTextContext.h"
67#include "src/gpu/text/GrTextTarget.h"
Brian Salomonf18b1d82017-10-27 11:30:49 -040068
Herb Derbyc1b482c2018-08-09 15:02:27 -040069class GrRenderTargetContext::TextTarget : public GrTextTarget {
Brian Salomonf18b1d82017-10-27 11:30:49 -040070public:
71 TextTarget(GrRenderTargetContext* renderTargetContext)
Herb Derbyc1b482c2018-08-09 15:02:27 -040072 : GrTextTarget(renderTargetContext->width(), renderTargetContext->height(),
Robert Phillips7e90be92019-02-15 12:22:59 -050073 renderTargetContext->colorSpaceInfo())
Herb Derby74c6ed32018-07-28 18:07:54 -040074 , fRenderTargetContext(renderTargetContext)
Herb Derby65956872018-08-21 16:55:04 -040075 , fGlyphPainter{*renderTargetContext}{}
Brian Salomonf18b1d82017-10-27 11:30:49 -040076
Robert Phillips7c525e62018-06-12 10:11:12 -040077 void addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) override {
Brian Salomonf18b1d82017-10-27 11:30:49 -040078 fRenderTargetContext->addDrawOp(clip, std::move(op));
79 }
80
Robert Phillips46a13382018-08-23 13:53:01 -040081 void drawShape(const GrClip& clip, const SkPaint& paint,
82 const SkMatrix& viewMatrix, const GrShape& shape) override {
Robert Phillips27927a52018-08-20 13:18:12 -040083 GrBlurUtils::drawShapeWithMaskFilter(fRenderTargetContext->fContext, fRenderTargetContext,
84 clip, paint, viewMatrix, shape);
Brian Salomonf18b1d82017-10-27 11:30:49 -040085 }
86
87 void makeGrPaint(GrMaskFormat maskFormat, const SkPaint& skPaint, const SkMatrix& viewMatrix,
Robert Phillips7c525e62018-06-12 10:11:12 -040088 GrPaint* grPaint) override {
Robert Phillips69893702019-02-22 11:16:30 -050089 auto context = fRenderTargetContext->fContext;
Brian Salomonf18b1d82017-10-27 11:30:49 -040090 const GrColorSpaceInfo& colorSpaceInfo = fRenderTargetContext->colorSpaceInfo();
91 if (kARGB_GrMaskFormat == maskFormat) {
92 SkPaintToGrPaintWithPrimitiveColor(context, colorSpaceInfo, skPaint, grPaint);
93 } else {
94 SkPaintToGrPaint(context, colorSpaceInfo, skPaint, viewMatrix, grPaint);
95 }
96 }
97
Robert Phillips69893702019-02-22 11:16:30 -050098 GrRecordingContext* getContext() override {
Robert Phillips7c525e62018-06-12 10:11:12 -040099 return fRenderTargetContext->fContext;
100 }
101
Herb Derby65956872018-08-21 16:55:04 -0400102 SkGlyphRunListPainter* glyphPainter() override {
103 return &fGlyphPainter;
Herb Derby74c6ed32018-07-28 18:07:54 -0400104 }
105
Brian Salomonf18b1d82017-10-27 11:30:49 -0400106private:
107 GrRenderTargetContext* fRenderTargetContext;
Herb Derby65956872018-08-21 16:55:04 -0400108 SkGlyphRunListPainter fGlyphPainter;
Herb Derby74c6ed32018-07-28 18:07:54 -0400109
Brian Salomonf18b1d82017-10-27 11:30:49 -0400110};
joshualittbc907352016-01-13 06:45:40 -0800111
Robert Phillips72152832017-01-25 17:31:35 -0500112#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
joshualitt1de610a2016-01-06 08:26:09 -0800113#define ASSERT_SINGLE_OWNER \
Robert Phillipsa90aa2b2017-04-10 08:19:26 -0400114 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
robertphillips391395d2016-03-02 09:26:36 -0800115#define ASSERT_SINGLE_OWNER_PRIV \
Robert Phillipsa90aa2b2017-04-10 08:19:26 -0400116 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
Robert Phillips69893702019-02-22 11:16:30 -0500117#define RETURN_IF_ABANDONED if (fContext->priv().abandoned()) { return; }
118#define RETURN_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return; }
119#define RETURN_FALSE_IF_ABANDONED if (fContext->priv().abandoned()) { return false; }
120#define RETURN_FALSE_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return false; }
121#define RETURN_NULL_IF_ABANDONED if (fContext->priv().abandoned()) { return nullptr; }
robertphillipsea461502015-05-26 11:38:03 -0700122
Brian Salomone225b562017-06-14 13:00:03 -0400123//////////////////////////////////////////////////////////////////////////////
124
robertphillipsea461502015-05-26 11:38:03 -0700125class AutoCheckFlush {
126public:
halcanary9d524f22016-03-29 09:03:52 -0700127 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
robertphillips77a2e522015-10-17 07:43:27 -0700128 SkASSERT(fDrawingManager);
129 }
bsalomonb77a9072016-09-07 10:02:04 -0700130 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
robertphillipsea461502015-05-26 11:38:03 -0700131
132private:
robertphillips77a2e522015-10-17 07:43:27 -0700133 GrDrawingManager* fDrawingManager;
robertphillipsea461502015-05-26 11:38:03 -0700134};
135
Robert Phillipsf2361d22016-10-25 14:20:06 -0400136// In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress
Brian Osman11052242016-10-27 14:47:55 -0400137// GrOpLists to be picked up and added to by renderTargetContexts lower in the call
Robert Phillipsf2361d22016-10-25 14:20:06 -0400138// stack. When this occurs with a closed GrOpList, a new one will be allocated
Brian Osman11052242016-10-27 14:47:55 -0400139// when the renderTargetContext attempts to use it (via getOpList).
Robert Phillips69893702019-02-22 11:16:30 -0500140GrRenderTargetContext::GrRenderTargetContext(GrRecordingContext* context,
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400141 sk_sp<GrRenderTargetProxy> rtp,
Brian Osman11052242016-10-27 14:47:55 -0400142 sk_sp<SkColorSpace> colorSpace,
143 const SkSurfaceProps* surfaceProps,
Robert Phillips941d1442017-06-14 16:37:02 -0400144 bool managedOpList)
Robert Phillips0d075de2019-03-04 11:08:13 -0500145 : GrSurfaceContext(context, rtp->config(), std::move(colorSpace))
Brian Salomonf3569f02017-10-24 12:52:33 -0400146 , fRenderTargetProxy(std::move(rtp))
147 , fOpList(sk_ref_sp(fRenderTargetProxy->getLastRenderTargetOpList()))
Brian Salomonf3569f02017-10-24 12:52:33 -0400148 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
149 , fManagedOpList(managedOpList) {
Brian Salomonf18b1d82017-10-27 11:30:49 -0400150 fTextTarget.reset(new TextTarget(this));
robertphillips2e1e51f2015-10-15 08:01:48 -0700151 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -0700152}
153
robertphillips2e1e51f2015-10-15 08:01:48 -0700154#ifdef SK_DEBUG
Brian Osman11052242016-10-27 14:47:55 -0400155void GrRenderTargetContext::validate() const {
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400156 SkASSERT(fRenderTargetProxy);
157 fRenderTargetProxy->validate(fContext);
robertphillipsa106c622015-10-16 09:07:06 -0700158
Robert Phillipsf2361d22016-10-25 14:20:06 -0400159 if (fOpList && !fOpList->isClosed()) {
Robert Phillipsdc83b892017-04-13 12:23:54 -0400160 SkASSERT(fRenderTargetProxy->getLastOpList() == fOpList.get());
robertphillipsa106c622015-10-16 09:07:06 -0700161 }
robertphillips2e1e51f2015-10-15 08:01:48 -0700162}
163#endif
164
Brian Osman11052242016-10-27 14:47:55 -0400165GrRenderTargetContext::~GrRenderTargetContext() {
joshualitt1de610a2016-01-06 08:26:09 -0800166 ASSERT_SINGLE_OWNER
robertphillipsa106c622015-10-16 09:07:06 -0700167}
168
Chris Dalton7d6748e2019-03-13 00:34:52 -0600169inline GrAAType GrRenderTargetContext::chooseAAType(GrAA aa) {
170 auto fsaaType = this->fsaaType();
171 if (GrAA::kNo == aa) {
172 // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
173 // that.
174 if (fsaaType == GrFSAAType::kUnifiedMSAA && !this->caps()->multisampleDisableSupport()) {
175 return GrAAType::kMSAA;
176 }
177 return GrAAType::kNone;
178 }
179 switch (fsaaType) {
180 case GrFSAAType::kNone:
181 case GrFSAAType::kMixedSamples:
182 return GrAAType::kCoverage;
183 case GrFSAAType::kUnifiedMSAA:
184 return GrAAType::kMSAA;
185 }
186 SK_ABORT("Unexpected fsaa type");
187 return GrAAType::kNone;
188}
189
190static inline GrPathRenderer::AATypeFlags choose_path_aa_type_flags(
191 GrAA aa, GrFSAAType fsaaType, const GrCaps& caps) {
192 using AATypeFlags = GrPathRenderer::AATypeFlags;
193 if (GrAA::kNo == aa) {
194 // On some devices we cannot disable MSAA if it is enabled so we make the AA type flags
195 // reflect that.
196 if (fsaaType == GrFSAAType::kUnifiedMSAA && !caps.multisampleDisableSupport()) {
197 return AATypeFlags::kMSAA;
198 }
199 return AATypeFlags::kNone;
200 }
201 switch (fsaaType) {
202 case GrFSAAType::kNone:
203 return AATypeFlags::kCoverage;
204 case GrFSAAType::kMixedSamples:
205 return AATypeFlags::kCoverage | AATypeFlags::kMixedSampledStencilThenCover;
206 case GrFSAAType::kUnifiedMSAA:
207 return AATypeFlags::kMSAA;
208 }
209 SK_ABORT("Invalid GrFSAAType.");
210 return AATypeFlags::kNone;
211}
212
Robert Phillipsf200a902017-01-30 13:27:37 -0500213GrTextureProxy* GrRenderTargetContext::asTextureProxy() {
Robert Phillipseaa86252016-11-08 13:49:39 +0000214 return fRenderTargetProxy->asTextureProxy();
215}
216
Greg Daniele252f082017-10-23 16:05:23 -0400217const GrTextureProxy* GrRenderTargetContext::asTextureProxy() const {
218 return fRenderTargetProxy->asTextureProxy();
219}
220
Robert Phillipsf200a902017-01-30 13:27:37 -0500221sk_sp<GrTextureProxy> GrRenderTargetContext::asTextureProxyRef() {
222 return sk_ref_sp(fRenderTargetProxy->asTextureProxy());
223}
224
Greg Daniele252f082017-10-23 16:05:23 -0400225GrMipMapped GrRenderTargetContext::mipMapped() const {
226 if (const GrTextureProxy* proxy = this->asTextureProxy()) {
227 return proxy->mipMapped();
228 }
229 return GrMipMapped::kNo;
230}
231
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400232GrRenderTargetOpList* GrRenderTargetContext::getRTOpList() {
joshualitt1de610a2016-01-06 08:26:09 -0800233 ASSERT_SINGLE_OWNER
robertphillipsa106c622015-10-16 09:07:06 -0700234 SkDEBUGCODE(this->validate();)
235
Robert Phillipsf2361d22016-10-25 14:20:06 -0400236 if (!fOpList || fOpList->isClosed()) {
Michael Ludwig6e17f1d2019-05-15 14:00:20 +0000237 fOpList = this->drawingManager()->newRTOpList(fRenderTargetProxy, fManagedOpList);
robertphillipsa106c622015-10-16 09:07:06 -0700238 }
239
Robert Phillipsdc83b892017-04-13 12:23:54 -0400240 return fOpList.get();
robertphillipsa106c622015-10-16 09:07:06 -0700241}
242
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400243GrOpList* GrRenderTargetContext::getOpList() {
244 return this->getRTOpList();
robertphillipsea461502015-05-26 11:38:03 -0700245}
246
Herb Derbycddab252018-07-16 11:19:04 -0400247void GrRenderTargetContext::drawGlyphRunList(
248 const GrClip& clip, const SkMatrix& viewMatrix,
Robert Phillipse4643cc2018-08-14 13:01:29 -0400249 const SkGlyphRunList& blob) {
joshualitt1de610a2016-01-06 08:26:09 -0800250 ASSERT_SINGLE_OWNER
robertphillips2d70dcb2015-10-06 07:38:23 -0700251 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700252 SkDEBUGCODE(this->validate();)
Herb Derbycddab252018-07-16 11:19:04 -0400253 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawGlyphRunList", fContext);
robertphillips2d70dcb2015-10-06 07:38:23 -0700254
Greg Danielbe7fc462019-01-03 16:40:42 -0500255 // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
256 // secondary command buffers because it would require stopping and starting a render pass which
257 // we don't have access to.
258 if (this->wrapsVkSecondaryCB()) {
259 return;
260 }
261
Herb Derby26cbe512018-05-24 14:39:01 -0400262 GrTextContext* atlasTextContext = this->drawingManager()->getTextContext();
Herb Derbycddab252018-07-16 11:19:04 -0400263 atlasTextContext->drawGlyphRunList(fContext, fTextTarget.get(), clip, viewMatrix,
Robert Phillipse4643cc2018-08-14 13:01:29 -0400264 fSurfaceProps, blob);
robertphillipsea461502015-05-26 11:38:03 -0700265}
266
Brian Osman11052242016-10-27 14:47:55 -0400267void GrRenderTargetContext::discard() {
joshualitt1de610a2016-01-06 08:26:09 -0800268 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700269 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700270 SkDEBUGCODE(this->validate();)
Robert Phillips6b47c7d2017-08-29 07:24:09 -0400271 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -0700272
Robert Phillips72152832017-01-25 17:31:35 -0500273 AutoCheckFlush acf(this->drawingManager());
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400274
Robert Phillips380b90c2017-08-30 07:41:07 -0400275 this->getRTOpList()->discard();
robertphillipsea461502015-05-26 11:38:03 -0700276}
277
Brian Osman11052242016-10-27 14:47:55 -0400278void GrRenderTargetContext::clear(const SkIRect* rect,
Brian Osman9a9baae2018-11-05 15:06:26 -0500279 const SkPMColor4f& color,
Chris Dalton344e9032017-12-11 15:42:09 -0700280 CanClearFullscreen canClearFullscreen) {
joshualitt1de610a2016-01-06 08:26:09 -0800281 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700282 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700283 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400284 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext);
robertphillipsea461502015-05-26 11:38:03 -0700285
Robert Phillips72152832017-01-25 17:31:35 -0500286 AutoCheckFlush acf(this->drawingManager());
Chris Dalton344e9032017-12-11 15:42:09 -0700287 this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color,
288 canClearFullscreen);
csmartdalton29df7602016-08-31 11:55:52 -0700289}
robertphillips9199a9f2016-07-13 07:48:43 -0700290
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500291void GrRenderTargetContextPriv::clear(const GrFixedClip& clip,
292 const SkPMColor4f& color,
293 CanClearFullscreen canClearFullscreen) {
294 ASSERT_SINGLE_OWNER_PRIV
295 RETURN_IF_ABANDONED_PRIV
296 SkDEBUGCODE(fRenderTargetContext->validate();)
297 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clear",
298 fRenderTargetContext->fContext);
299
300 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
301 fRenderTargetContext->internalClear(clip, color, canClearFullscreen);
302}
303
304static void clear_to_grpaint(const SkPMColor4f& color, GrPaint* paint) {
305 paint->setColor4f(color);
306 if (color.isOpaque()) {
307 // Can just rely on the src-over blend mode to do the right thing
308 paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
309 } else {
310 // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
311 // were src blended
312 paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
313 }
314}
315
316void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
317 const SkPMColor4f& color,
318 CanClearFullscreen canClearFullscreen) {
319 bool isFull = false;
320 if (!clip.hasWindowRectangles()) {
Robert Phillips0e35ce22019-04-05 10:57:28 -0400321 // TODO: wrt the shouldInitializeTextures path, it would be more performant to
322 // only clear the entire target if we knew it had not been cleared before. As
323 // is this could end up doing a lot of redundant clears.
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500324 isFull = !clip.scissorEnabled() ||
325 (CanClearFullscreen::kYes == canClearFullscreen &&
Robert Phillips0e35ce22019-04-05 10:57:28 -0400326 (this->caps()->preferFullscreenClears() || this->caps()->shouldInitializeTextures())) ||
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500327 clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
328 }
329
330 if (isFull) {
331 if (this->getRTOpList()->resetForFullscreenClear() &&
332 !this->caps()->performColorClearsAsDraws()) {
333 // The op list was emptied and native clears are allowed, so just use the load op
334 this->getRTOpList()->setColorLoadOp(GrLoadOp::kClear, color);
335 return;
336 } else {
337 // Will use an op for the clear, reset the load op to discard since the op will
338 // blow away the color buffer contents
339 this->getRTOpList()->setColorLoadOp(GrLoadOp::kDiscard);
340 }
341
342 // Must add an op to the list (either because we couldn't use a load op, or because the
343 // clear load op isn't supported)
344 if (this->caps()->performColorClearsAsDraws()) {
345 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
346 GrPaint paint;
347 clear_to_grpaint(color, &paint);
348 this->addDrawOp(GrFixedClip::Disabled(),
349 GrFillRectOp::Make(fContext, std::move(paint),
350 GrAAType::kNone, SkMatrix::I(), rtRect));
351 } else {
352 this->getRTOpList()->addOp(GrClearOp::Make(fContext, SkIRect::MakeEmpty(), color,
353 /* fullscreen */ true), *this->caps());
354 }
355 } else {
356 if (this->caps()->performPartialClearsAsDraws()) {
357 // performPartialClearsAsDraws() also returns true if any clear has to be a draw.
358 SkRect scissor = SkRect::Make(clip.scissorRect());
359 GrPaint paint;
360 clear_to_grpaint(color, &paint);
361
362 this->addDrawOp(clip, GrFillRectOp::Make(fContext, std::move(paint), GrAAType::kNone,
363 SkMatrix::I(), scissor));
364 } else {
365 std::unique_ptr<GrOp> op(GrClearOp::Make(fContext, clip, color,
366 this->asSurfaceProxy()));
367 // This version of the clear op factory can return null if the clip doesn't intersect
368 // with the surface proxy's boundary
369 if (!op) {
370 return;
371 }
372 this->getRTOpList()->addOp(std::move(op), *this->caps());
373 }
374 }
375}
376
Brian Osman9a9baae2018-11-05 15:06:26 -0500377void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const SkPMColor4f& color) {
Robert Phillips784b7bf2016-12-09 13:35:02 -0500378 ASSERT_SINGLE_OWNER_PRIV
379 RETURN_IF_ABANDONED_PRIV
380 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400381 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "absClear",
382 fRenderTargetContext->fContext);
Robert Phillips784b7bf2016-12-09 13:35:02 -0500383
Robert Phillips72152832017-01-25 17:31:35 -0500384 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
Robert Phillips784b7bf2016-12-09 13:35:02 -0500385
Brian Salomonbb5711a2017-05-17 13:49:59 -0400386 SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth(),
387 fRenderTargetContext->fRenderTargetProxy->worstCaseHeight());
Robert Phillips784b7bf2016-12-09 13:35:02 -0500388
389 if (clearRect) {
390 if (clearRect->contains(rtRect)) {
391 clearRect = nullptr; // full screen
392 } else {
393 if (!rtRect.intersect(*clearRect)) {
394 return;
395 }
396 }
397 }
398
399 // TODO: in a post-MDB world this should be handled at the OpList level.
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500400 // This makes sure to always add an op to the list, instead of marking the clear as a load op.
401 // This code follows very similar logic to internalClear() below, but critical differences are
402 // highlighted in line related to absClear()'s unique behavior.
403 if (clearRect) {
404 if (fRenderTargetContext->caps()->performPartialClearsAsDraws()) {
Ethan Nicholas56d19a52018-10-15 11:26:20 -0400405 GrPaint paint;
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500406 clear_to_grpaint(color, &paint);
407
408 // Use the disabled clip; the rect geometry already matches the clear rectangle and
409 // if it were added to a scissor, that would be intersected with the logical surface
410 // bounds and not the worst case dimensions required here.
411 fRenderTargetContext->addDrawOp(GrFixedClip::Disabled(),
412 GrFillRectOp::Make(fRenderTargetContext->fContext,
413 std::move(paint),
414 GrAAType::kNone,
415 SkMatrix::I(),
416 SkRect::Make(rtRect)));
417 } else {
418 // Must use the ClearOp factory that takes a boolean (false) instead of a surface
419 // proxy. The surface proxy variant would intersect the clip rect with its logical
420 // bounds, which is not desired in this special case.
421 fRenderTargetContext->getRTOpList()->addOp(
422 GrClearOp::Make(fRenderTargetContext->fContext, rtRect, color,
423 /* fullscreen */ false),
424 *fRenderTargetContext->caps());
csmartdalton29df7602016-08-31 11:55:52 -0700425 }
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500426 } else {
427 // Reset the oplist like in internalClear(), but do not rely on a load op for the clear
428 fRenderTargetContext->getRTOpList()->resetForFullscreenClear();
429 fRenderTargetContext->getRTOpList()->setColorLoadOp(GrLoadOp::kDiscard);
430
431 if (fRenderTargetContext->caps()->performColorClearsAsDraws()) {
432 // This draws a quad covering the worst case dimensions instead of just the logical
433 // width and height like in internalClear().
434 GrPaint paint;
435 clear_to_grpaint(color, &paint);
436 fRenderTargetContext->addDrawOp(GrFixedClip::Disabled(),
437 GrFillRectOp::Make(fRenderTargetContext->fContext,
438 std::move(paint),
439 GrAAType::kNone,
440 SkMatrix::I(),
441 SkRect::Make(rtRect)));
442 } else {
443 // Nothing special about this path in absClear compared to internalClear()
444 fRenderTargetContext->getRTOpList()->addOp(
445 GrClearOp::Make(fRenderTargetContext->fContext, SkIRect::MakeEmpty(), color,
446 /* fullscreen */ true),
447 *fRenderTargetContext->caps());
Ethan Nicholas56d19a52018-10-15 11:26:20 -0400448 }
robertphillips9199a9f2016-07-13 07:48:43 -0700449 }
robertphillipsea461502015-05-26 11:38:03 -0700450}
451
Brian Osman11052242016-10-27 14:47:55 -0400452void GrRenderTargetContext::drawPaint(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500453 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -0400454 const SkMatrix& viewMatrix) {
joshualitt1de610a2016-01-06 08:26:09 -0800455 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700456 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700457 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400458 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPaint", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -0700459
robertphillipsea461502015-05-26 11:38:03 -0700460 // set rect to be big enough to fill the space, but not super-huge, so we
461 // don't overflow fixed-point implementations
robertphillips13a7eee2016-08-31 15:06:24 -0700462
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400463 SkRect r = fRenderTargetProxy->getBoundsRect();
robertphillipsea461502015-05-26 11:38:03 -0700464
Michael Ludwig61a16512019-01-15 11:15:13 -0500465 // Check if we can optimize a clipped drawPaint(). We only do the transformation when there are
466 // no fragment processors because they may depend on having correct local coords and this path
467 // draws in device space without a local matrix. It currently handles converting clipRRect()
468 // to drawRRect() and solid colors to screen-filling drawRects() (which are then converted into
469 // clears if possible in drawRect).
Michael Ludwig3d6390e2018-10-09 11:45:16 -0400470 if (!paint.numTotalFragmentProcessors()) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500471 SkRRect rrect;
472 GrAA aa = GrAA::kNo;
473 if (clip.isRRect(r, &rrect, &aa)) {
474 if (rrect.isRect()) {
475 // Use drawFilledRect() with no clip and the reduced rectangle
476 this->drawFilledRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect.rect());
477 } else {
478 // Use drawRRect() with no clip
479 this->drawRRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect,
480 GrStyle::SimpleFill());
481 }
482 } else {
483 // Use drawFilledRect() with no view matrix to draw a fullscreen quad, but preserve
484 // the clip. Since the paint has no FPs we can drop the view matrix without worrying
485 // about local coordinates. If the clip is simple, drawFilledRect() will turn this into
486 // a clear or a scissored clear.
487 this->drawFilledRect(clip, std::move(paint), aa, SkMatrix::I(), r);
Michael Ludwig3d6390e2018-10-09 11:45:16 -0400488 }
Michael Ludwig61a16512019-01-15 11:15:13 -0500489 return;
bsalomoncb31e512016-08-26 10:48:19 -0700490 }
491
Michael Ludwig61a16512019-01-15 11:15:13 -0500492 // Since the paint is not trivial, there's no way at this point drawRect() could have converted
493 // this drawPaint() into an optimized clear. drawRect() would then use GrFillRectOp without
494 // a local matrix, so we can simplify things and use the local matrix variant to draw a screen
495 // filling rect with the inverse view matrix for local coords, which works for all matrix
496 // conditions.
497 SkMatrix localMatrix;
498 if (!viewMatrix.invert(&localMatrix)) {
499 return;
robertphillipsea461502015-05-26 11:38:03 -0700500 }
Michael Ludwig61a16512019-01-15 11:15:13 -0500501
502 AutoCheckFlush acf(this->drawingManager());
503 std::unique_ptr<GrDrawOp> op = GrFillRectOp::MakeWithLocalMatrix(
504 fContext, std::move(paint), GrAAType::kNone, SkMatrix::I(), localMatrix, r);
505 this->addDrawOp(clip, std::move(op));
robertphillipsea461502015-05-26 11:38:03 -0700506}
507
robertphillipsea461502015-05-26 11:38:03 -0700508static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
509 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
510 point.fY >= rect.fTop && point.fY <= rect.fBottom;
511}
512
csmartdalton97f6cd52016-07-13 13:37:08 -0700513// Attempts to crop a rect and optional local rect to the clip boundaries.
514// Returns false if the draw can be skipped entirely.
robertphillips13a7eee2016-08-31 15:06:24 -0700515static bool crop_filled_rect(int width, int height, const GrClip& clip,
csmartdalton97f6cd52016-07-13 13:37:08 -0700516 const SkMatrix& viewMatrix, SkRect* rect,
517 SkRect* localRect = nullptr) {
518 if (!viewMatrix.rectStaysRect()) {
519 return true;
520 }
521
csmartdalton97f6cd52016-07-13 13:37:08 -0700522 SkIRect clipDevBounds;
523 SkRect clipBounds;
csmartdalton97f6cd52016-07-13 13:37:08 -0700524
robertphillips13a7eee2016-08-31 15:06:24 -0700525 clip.getConservativeBounds(width, height, &clipDevBounds);
reeda39667c2016-08-22 06:39:49 -0700526 if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) {
527 return false;
528 }
csmartdalton97f6cd52016-07-13 13:37:08 -0700529
530 if (localRect) {
531 if (!rect->intersects(clipBounds)) {
532 return false;
533 }
Michael Ludwig904657d2019-04-12 10:57:24 -0400534 // localRect is force-sorted after clipping, so this is a sanity check to make sure callers
535 // aren't intentionally using inverted local rectangles.
536 SkASSERT(localRect->isSorted());
csmartdalton97f6cd52016-07-13 13:37:08 -0700537 const SkScalar dx = localRect->width() / rect->width();
538 const SkScalar dy = localRect->height() / rect->height();
539 if (clipBounds.fLeft > rect->fLeft) {
540 localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx;
541 rect->fLeft = clipBounds.fLeft;
542 }
543 if (clipBounds.fTop > rect->fTop) {
544 localRect->fTop += (clipBounds.fTop - rect->fTop) * dy;
545 rect->fTop = clipBounds.fTop;
546 }
547 if (clipBounds.fRight < rect->fRight) {
548 localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx;
549 rect->fRight = clipBounds.fRight;
550 }
551 if (clipBounds.fBottom < rect->fBottom) {
552 localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy;
553 rect->fBottom = clipBounds.fBottom;
554 }
Michael Ludwig904657d2019-04-12 10:57:24 -0400555 // Ensure local coordinates remain sorted after clipping. If the original dstRect was very
556 // large, numeric precision can invert the localRect
557 localRect->sort();
csmartdalton97f6cd52016-07-13 13:37:08 -0700558 return true;
559 }
560
561 return rect->intersect(clipBounds);
562}
563
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400564GrQuadAAFlags set_edge_flag(GrQuadAAFlags currentFlags, GrQuadAAFlags edge, GrAA edgeState) {
565 if (edgeState == GrAA::kNo) {
566 // Turn off 'edge' in currentFlags
567 return currentFlags & (~edge);
568 } else {
569 // Turn on 'edge' in currentFlags
570 return currentFlags | edge;
571 }
572}
573
Michael Ludwig61a16512019-01-15 11:15:13 -0500574bool GrRenderTargetContext::drawFilledRectAsClear(const GrClip& clip, GrPaint&& paint, GrAA aa,
575 const SkMatrix& viewMatrix, const SkRect& rect) {
576 // Rules for a filled rect to become a clear [+scissor]:
577 // 1. The paint is a constant blend color with no other FPs
578 // 2. The view matrix maps rectangles to rectangles, or the transformed quad fully covers
579 // the render target (or clear region in #3).
580 // 3. The clip is an intersection of rectangles, so the clear region will be the
581 // intersection of the clip and the provided rect.
582 // 4. The clear region aligns with pixel bounds
583 // 5. There are no user stencil settings (and since the clip was IOR, the clip won't need
584 // to use the stencil either).
585 // If all conditions pass, the filled rect can either be a fullscreen clear (if it's big
586 // enough), or the rectangle geometry will be used as the scissor clip on the clear.
587 // If everything passes but rule #4, this submits a simplified fill rect op instead so that the
588 // rounding differences between clip and draws don't fight each other.
589 // NOTE: we route draws into clear() regardless of performColorClearsAsDraws() since the
590 // clear call is allowed to reset the oplist even when it also happens to use a GrFillRectOp.
591
592 SkPMColor4f clearColor;
593 if (paint.numCoverageFragmentProcessors() > 0 || !paint.isConstantBlendedColor(&clearColor)) {
594 return false;
595 }
596
597 const SkRect rtRect = fRenderTargetProxy->getBoundsRect();
598 // Will be the intersection of render target, clip, and quad
599 SkRect combinedRect = rtRect;
600
601 SkRRect clipRRect;
602 GrAA clipAA;
603 if (!clip.quickContains(rtRect)) {
604 // If the clip is an rrect with no rounding, then it can replace the full RT bounds as the
605 // limiting region, although we will have to worry about AA. If the clip is anything
606 // more complicated, just punt to the regular fill rect op.
607 if (!clip.isRRect(rtRect, &clipRRect, &clipAA) || !clipRRect.isRect()) {
608 return false;
609 }
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400610
Michael Ludwig43252702019-05-16 15:04:36 -0400611 combinedRect = clipRRect.rect();
Michael Ludwig61a16512019-01-15 11:15:13 -0500612 } else {
613 // The clip is outside the render target, so the clip can be ignored
614 clipAA = GrAA::kNo;
615 }
616
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400617 GrQuadAAFlags edgeFlags; // To account for clip and draw mixing AA modes
Michael Ludwig61a16512019-01-15 11:15:13 -0500618 if (viewMatrix.rectStaysRect()) {
619 // Skip the extra overhead of inverting the view matrix to see if rtRect is contained in the
620 // drawn rectangle, and instead just intersect rtRect with the transformed rect. It will be
621 // the new clear region.
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400622 SkRect drawRect = viewMatrix.mapRect(rect);
623 if (!combinedRect.intersect(drawRect)) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500624 // No intersection means nothing should be drawn, so return true but don't add an op
625 return true;
626 }
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400627
628 // In this case, edge flags start based on draw's AA and then switch per-edge to the clip's
629 // AA setting if that edge was inset.
630 edgeFlags = aa == GrAA::kNo ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll;
631 if (combinedRect.fLeft > drawRect.fLeft) {
632 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kLeft, clipAA);
633 }
634 if (combinedRect.fTop > drawRect.fTop) {
635 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kTop, clipAA);
636 }
637 if (combinedRect.fRight < drawRect.fRight) {
638 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kRight, clipAA);
639 }
640 if (combinedRect.fBottom < drawRect.fBottom) {
641 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kBottom, clipAA);
642 }
Michael Ludwig61a16512019-01-15 11:15:13 -0500643 } else {
644 // If the transformed rectangle does not contain the combined rt and clip, the draw is too
645 // complex to be implemented as a clear
646 SkMatrix invM;
647 if (!viewMatrix.invert(&invM)) {
648 return false;
649 }
650 // The clip region in the rect's local space, so the test becomes the local rect containing
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400651 // the quad's points. If clip is non-AA, test rounded out region to avoid the scenario where
652 // the draw contains the unrounded non-aa clip, but does not contain the rounded version. Be
653 // conservative since we don't know how the GPU would round.
654 SkRect conservative;
655 if (clipAA == GrAA::kNo) {
656 conservative = SkRect::Make(combinedRect.roundOut());
657 } else {
658 conservative = combinedRect;
659 }
660 GrQuad quad = GrQuad::MakeFromRect(conservative, invM);
Michael Ludwig61a16512019-01-15 11:15:13 -0500661 if (!rect_contains_inclusive(rect, quad.point(0)) ||
662 !rect_contains_inclusive(rect, quad.point(1)) ||
663 !rect_contains_inclusive(rect, quad.point(2)) ||
664 !rect_contains_inclusive(rect, quad.point(3))) {
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400665 // No containment, so combinedRect can't be filled by a solid color
Michael Ludwig61a16512019-01-15 11:15:13 -0500666 return false;
667 }
668 // combinedRect can be filled by a solid color but doesn't need to be modified since it's
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400669 // inside the quad to be drawn, which also means the edge AA flags respect the clip AA
670 edgeFlags = clipAA == GrAA::kNo ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll;
Michael Ludwig61a16512019-01-15 11:15:13 -0500671 }
672
673 // Almost every condition is met; now it requires that the combined rect align with pixel
674 // boundaries in order for it to become a scissor-clear. Ignore the AA status in this case
675 // since non-AA with partial-pixel coordinates can be rounded differently on the GPU,
676 // leading to unexpected differences between a scissor test and a rasterized quad.
677 // Also skip very small rectangles since the scissor+clear doesn't by us much then.
678 if (combinedRect.contains(rtRect)) {
679 // Full screen clear
680 this->clear(nullptr, clearColor, CanClearFullscreen::kYes);
681 return true;
682 } else if (GrClip::IsPixelAligned(combinedRect) &&
683 combinedRect.width() > 256 && combinedRect.height() > 256) {
684 // Scissor + clear (round shouldn't do anything since we are pixel aligned)
685 SkIRect scissorRect;
686 combinedRect.round(&scissorRect);
687 this->clear(&scissorRect, clearColor, CanClearFullscreen::kNo);
688 return true;
689 }
690
691 // If we got here, we can't use a scissor + clear, but combinedRect represents the correct
692 // geometry combination of quad + clip so we can perform a simplified fill rect op. We do this
693 // mostly to avoid mismatches in rounding logic on the CPU vs. the GPU, which frequently appears
694 // when drawing and clipping something to the same non-AA rect that never-the-less has
695 // non-integer coordinates.
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400696 aa = edgeFlags == GrQuadAAFlags::kNone ? GrAA::kNo : GrAA::kYes;
Chris Dalton7d6748e2019-03-13 00:34:52 -0600697 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig61a16512019-01-15 11:15:13 -0500698 this->addDrawOp(GrFixedClip::Disabled(),
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400699 GrFillRectOp::MakePerEdge(fContext, std::move(paint), aaType, edgeFlags,
700 SkMatrix::I(), combinedRect));
Michael Ludwig61a16512019-01-15 11:15:13 -0500701 return true;
702}
703
704void GrRenderTargetContext::drawFilledRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500705 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500706 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -0400707 const SkMatrix& viewMatrix,
708 const SkRect& rect,
709 const GrUserStencilSettings* ss) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500710
711 if (!ss) {
712 if (this->drawFilledRectAsClear(clip, std::move(paint), aa, viewMatrix, rect)) {
713 return;
714 }
715 // Fall through to fill rect op
716 assert_alive(paint);
717 }
718
csmartdalton97f6cd52016-07-13 13:37:08 -0700719 SkRect croppedRect = rect;
Robert Phillips784b7bf2016-12-09 13:35:02 -0500720 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500721 // The rectangle would not be drawn, so no need to add a draw op to the list
722 return;
csmartdalton97f6cd52016-07-13 13:37:08 -0700723 }
robertphillips44302392016-07-08 14:43:03 -0700724
Chris Dalton7d6748e2019-03-13 00:34:52 -0600725 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500726 this->addDrawOp(clip, GrFillRectOp::Make(fContext, std::move(paint), aaType, viewMatrix,
727 croppedRect, ss));
robertphillips391395d2016-03-02 09:26:36 -0800728}
729
Brian Osman11052242016-10-27 14:47:55 -0400730void GrRenderTargetContext::drawRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500731 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500732 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -0400733 const SkMatrix& viewMatrix,
734 const SkRect& rect,
735 const GrStyle* style) {
bsalomon6663acf2016-05-10 09:14:17 -0700736 if (!style) {
737 style = &GrStyle::SimpleFill();
738 }
joshualitt1de610a2016-01-06 08:26:09 -0800739 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700740 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700741 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400742 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRect", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -0700743
bsalomon6663acf2016-05-10 09:14:17 -0700744 // Path effects should've been devolved to a path in SkGpuDevice
745 SkASSERT(!style->pathEffect());
robertphillipsea461502015-05-26 11:38:03 -0700746
Robert Phillips72152832017-01-25 17:31:35 -0500747 AutoCheckFlush acf(this->drawingManager());
robertphillipsea461502015-05-26 11:38:03 -0700748
bsalomon6663acf2016-05-10 09:14:17 -0700749 const SkStrokeRec& stroke = style->strokeRec();
Robert Phillips8c8b0462018-08-24 16:18:03 -0400750 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500751 this->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect);
752 return;
bsalomona7d85ba2016-07-06 11:54:59 -0700753 } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
754 stroke.getStyle() == SkStrokeRec::kHairline_Style) {
755 if ((!rect.width() || !rect.height()) &&
756 SkStrokeRec::kHairline_Style != stroke.getStyle()) {
757 SkScalar r = stroke.getWidth() / 2;
758 // TODO: Move these stroke->fill fallbacks to GrShape?
759 switch (stroke.getJoin()) {
760 case SkPaint::kMiter_Join:
Brian Salomon82f44312017-01-11 13:42:54 -0500761 this->drawRect(
762 clip, std::move(paint), aa, viewMatrix,
763 {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r},
764 &GrStyle::SimpleFill());
bsalomona7d85ba2016-07-06 11:54:59 -0700765 return;
766 case SkPaint::kRound_Join:
767 // Raster draws nothing when both dimensions are empty.
768 if (rect.width() || rect.height()){
769 SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
Brian Salomon82f44312017-01-11 13:42:54 -0500770 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect,
771 GrStyle::SimpleFill());
bsalomona7d85ba2016-07-06 11:54:59 -0700772 return;
773 }
774 case SkPaint::kBevel_Join:
775 if (!rect.width()) {
Brian Salomon82f44312017-01-11 13:42:54 -0500776 this->drawRect(clip, std::move(paint), aa, viewMatrix,
bsalomona7d85ba2016-07-06 11:54:59 -0700777 {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
778 &GrStyle::SimpleFill());
779 } else {
Brian Salomon82f44312017-01-11 13:42:54 -0500780 this->drawRect(clip, std::move(paint), aa, viewMatrix,
bsalomona7d85ba2016-07-06 11:54:59 -0700781 {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
782 &GrStyle::SimpleFill());
783 }
784 return;
785 }
786 }
robertphillips44302392016-07-08 14:43:03 -0700787
Brian Salomonbaaf4392017-06-15 09:59:23 -0400788 std::unique_ptr<GrDrawOp> op;
robertphillips44302392016-07-08 14:43:03 -0700789
Chris Dalton7d6748e2019-03-13 00:34:52 -0600790 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500791 op = GrStrokeRectOp::Make(fContext, std::move(paint), aaType, viewMatrix, rect, stroke);
792 // op may be null if the stroke is not supported or if using coverage aa and the view matrix
793 // does not preserve rectangles.
Brian Salomon42521e82016-12-07 16:44:58 -0500794 if (op) {
Brian Salomonbaaf4392017-06-15 09:59:23 -0400795 this->addDrawOp(clip, std::move(op));
robertphillips44302392016-07-08 14:43:03 -0700796 return;
robertphillips4bc31812016-03-01 12:22:49 -0800797 }
robertphillips4bc31812016-03-01 12:22:49 -0800798 }
Mike Klein16885072018-12-11 09:54:31 -0500799 assert_alive(paint);
Brian Salomon2fad74a2017-12-20 13:28:55 -0500800 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style));
robertphillipsea461502015-05-26 11:38:03 -0700801}
802
Michael Ludwig69858532018-11-28 15:34:34 -0500803void GrRenderTargetContext::drawQuadSet(const GrClip& clip, GrPaint&& paint, GrAA aa,
804 const SkMatrix& viewMatrix, const QuadSetEntry quads[],
805 int cnt) {
Chris Dalton7d6748e2019-03-13 00:34:52 -0600806 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig69858532018-11-28 15:34:34 -0500807 this->addDrawOp(clip, GrFillRectOp::MakeSet(fContext, std::move(paint), aaType, viewMatrix,
808 quads, cnt));
809}
810
Robert Phillipsec2249f2016-11-09 08:54:35 -0500811int GrRenderTargetContextPriv::maxWindowRectangles() const {
812 return fRenderTargetContext->fRenderTargetProxy->maxWindowRectangles(
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400813 *fRenderTargetContext->caps());
Robert Phillipsec2249f2016-11-09 08:54:35 -0500814}
815
Jim Van Verth6a40abc2017-11-02 16:56:09 +0000816void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
robertphillips976f5f02016-06-03 10:59:20 -0700817 ASSERT_SINGLE_OWNER_PRIV
818 RETURN_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -0400819 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400820 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clearStencilClip",
821 fRenderTargetContext->fContext);
robertphillips976f5f02016-06-03 10:59:20 -0700822
Robert Phillips72152832017-01-25 17:31:35 -0500823 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
Robert Phillipsb9a02a12017-04-06 11:08:40 -0400824
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500825 fRenderTargetContext->internalStencilClear(clip, insideStencilMask);
826}
827
828void GrRenderTargetContext::internalStencilClear(const GrFixedClip& clip, bool insideStencilMask) {
829 if (this->caps()->performStencilClearsAsDraws()) {
830 const GrUserStencilSettings* ss = GrStencilSettings::SetClipBitSettings(insideStencilMask);
831 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
832
833 // Configure the paint to have no impact on the color buffer
834 GrPaint paint;
835 paint.setColor4f({0.f, 0.f, 0.f, 0.f});
836 paint.setPorterDuffXPFactory(SkBlendMode::kSrcOver);
837
Michael Ludwig6e17f1d2019-05-15 14:00:20 +0000838 // Mark stencil usage here before addDrawOp() so that it doesn't try to re-call
839 // internalStencilClear() just because the op has stencil settings.
840 this->setNeedsStencil();
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500841 this->addDrawOp(clip, GrFillRectOp::Make(fContext, std::move(paint),
842 GrAAType::kNone, SkMatrix::I(), rtRect, ss));
843 } else {
844 std::unique_ptr<GrOp> op(GrClearStencilClipOp::Make(fContext, clip, insideStencilMask,
845 fRenderTargetProxy.get()));
846 if (!op) {
847 return;
848 }
849 this->getRTOpList()->addOp(std::move(op), *this->caps());
Robert Phillipse60ad622016-11-17 10:22:48 -0500850 }
robertphillips976f5f02016-06-03 10:59:20 -0700851}
852
Chris Daltonbbfd5162017-11-07 13:35:22 -0700853void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
Chris Dalton09e56892019-03-13 00:22:01 -0600854 GrAA doStencilMSAA,
Brian Osman11052242016-10-27 14:47:55 -0400855 const SkMatrix& viewMatrix,
856 const GrPath* path) {
Brian Salomon467921e2017-03-06 16:17:12 -0500857 ASSERT_SINGLE_OWNER_PRIV
858 RETURN_IF_ABANDONED_PRIV
859 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400860 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilPath",
861 fRenderTargetContext->fContext);
Brian Salomon467921e2017-03-06 16:17:12 -0500862
Brian Salomon467921e2017-03-06 16:17:12 -0500863 // TODO: extract portions of checkDraw that are relevant to path stenciling.
864 SkASSERT(path);
865 SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
866
867 // FIXME: Use path bounds instead of this WAR once
868 // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
869 SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height());
870
871 // Setup clip
Chris Daltonbbfd5162017-11-07 13:35:22 -0700872 GrAppliedHardClip appliedClip;
873 if (!clip.apply(fRenderTargetContext->width(), fRenderTargetContext->height(), &appliedClip,
874 &bounds)) {
Brian Salomon467921e2017-03-06 16:17:12 -0500875 return;
876 }
877
Michael Ludwig6e17f1d2019-05-15 14:00:20 +0000878 fRenderTargetContext->setNeedsStencil();
879
Robert Phillips7c525e62018-06-12 10:11:12 -0400880 std::unique_ptr<GrOp> op = GrStencilPathOp::Make(fRenderTargetContext->fContext,
881 viewMatrix,
Chris Dalton09e56892019-03-13 00:22:01 -0600882 GrAA::kYes == doStencilMSAA,
Brian Salomon467921e2017-03-06 16:17:12 -0500883 path->getFillType(),
884 appliedClip.hasStencilClip(),
Brian Salomon467921e2017-03-06 16:17:12 -0500885 appliedClip.scissorState(),
Brian Salomon467921e2017-03-06 16:17:12 -0500886 path);
Robert Phillipsb9a02a12017-04-06 11:08:40 -0400887 if (!op) {
888 return;
889 }
Brian Salomon97180af2017-03-14 13:42:58 -0400890 op->setClippedBounds(bounds);
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400891 fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
robertphillips976f5f02016-06-03 10:59:20 -0700892}
893
Chris Daltonbbfd5162017-11-07 13:35:22 -0700894void GrRenderTargetContextPriv::stencilRect(const GrHardClip& clip,
Brian Osman11052242016-10-27 14:47:55 -0400895 const GrUserStencilSettings* ss,
Chris Dalton09e56892019-03-13 00:22:01 -0600896 GrAA doStencilMSAA,
Brian Osman11052242016-10-27 14:47:55 -0400897 const SkMatrix& viewMatrix,
898 const SkRect& rect) {
robertphillips976f5f02016-06-03 10:59:20 -0700899 ASSERT_SINGLE_OWNER_PRIV
900 RETURN_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -0400901 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400902 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilRect",
903 fRenderTargetContext->fContext);
904
Robert Phillips72152832017-01-25 17:31:35 -0500905 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
robertphillips976f5f02016-06-03 10:59:20 -0700906
907 GrPaint paint;
Brian Salomona1633922017-01-09 11:46:10 -0500908 paint.setXPFactory(GrDisableColorXPFactory::Get());
Chris Dalton09e56892019-03-13 00:22:01 -0600909 auto aaType = (GrAA::kYes == doStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
Michael Ludwig72ab3462018-12-10 12:43:36 -0500910 std::unique_ptr<GrDrawOp> op = GrFillRectOp::Make(
911 fRenderTargetContext->fContext, std::move(paint), aaType, viewMatrix, rect, ss);
Brian Salomonbaaf4392017-06-15 09:59:23 -0400912 fRenderTargetContext->addDrawOp(clip, std::move(op));
robertphillips976f5f02016-06-03 10:59:20 -0700913}
914
Chris Daltonbbfd5162017-11-07 13:35:22 -0700915bool GrRenderTargetContextPriv::drawAndStencilRect(const GrHardClip& clip,
Brian Osman11052242016-10-27 14:47:55 -0400916 const GrUserStencilSettings* ss,
917 SkRegion::Op op,
918 bool invert,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500919 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -0400920 const SkMatrix& viewMatrix,
921 const SkRect& rect) {
robertphillips391395d2016-03-02 09:26:36 -0800922 ASSERT_SINGLE_OWNER_PRIV
923 RETURN_FALSE_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -0400924 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400925 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilRect",
926 fRenderTargetContext->fContext);
robertphillips391395d2016-03-02 09:26:36 -0800927
Robert Phillips72152832017-01-25 17:31:35 -0500928 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
robertphillips391395d2016-03-02 09:26:36 -0800929
930 GrPaint paint;
robertphillips391395d2016-03-02 09:26:36 -0800931 paint.setCoverageSetOpXPFactory(op, invert);
932
Michael Ludwig61a16512019-01-15 11:15:13 -0500933 // This will always succeed to draw a rectangle
934 fRenderTargetContext->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect, ss);
935 return true;
robertphillips391395d2016-03-02 09:26:36 -0800936}
937
Michael Ludwig136f45a2019-02-19 11:44:41 -0500938void GrRenderTargetContext::fillRectWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa,
Michael Ludwig75451902019-01-23 11:14:29 -0500939 GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix,
Michael Ludwig136f45a2019-02-19 11:44:41 -0500940 const SkRect& rect, const SkRect* localRect) {
Michael Ludwig75451902019-01-23 11:14:29 -0500941 ASSERT_SINGLE_OWNER
942 RETURN_IF_ABANDONED
943 SkDEBUGCODE(this->validate();)
944 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithEdgeAA", fContext);
945
Chris Dalton7d6748e2019-03-13 00:34:52 -0600946 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig136f45a2019-02-19 11:44:41 -0500947 std::unique_ptr<GrDrawOp> op;
Michael Ludwig75451902019-01-23 11:14:29 -0500948
Michael Ludwig136f45a2019-02-19 11:44:41 -0500949 if (localRect) {
950 // If local coordinates are provided, skip the optimization check to go through
951 // drawFilledRect, and also calculate clipped local coordinates
952 SkRect croppedRect = rect;
953 SkRect croppedLocalRect = *localRect;
954 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect,
955 &croppedLocalRect)) {
956 return;
957 }
958 op = GrFillRectOp::MakePerEdgeWithLocalRect(fContext, std::move(paint), aaType, edgeAA,
959 viewMatrix, croppedRect, croppedLocalRect);
960 } else {
961 // If aaType turns into MSAA, make sure to keep quads with no AA edges as MSAA. Sending
962 // those to drawFilledRect() would have it turn off MSAA in that case, which breaks seaming
963 // with any partial AA edges that kept MSAA.
964 if (aaType != GrAAType::kMSAA &&
965 (edgeAA == GrQuadAAFlags::kNone || edgeAA == GrQuadAAFlags::kAll)) {
966 // This is equivalent to a regular filled rect draw, so route through there to take
967 // advantage of draw->clear optimizations
968 this->drawFilledRect(clip, std::move(paint), GrAA(edgeAA == GrQuadAAFlags::kAll),
969 viewMatrix, rect);
970 return;
971 }
972
973 SkRect croppedRect = rect;
974 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
975 return;
976 }
977 op = GrFillRectOp::MakePerEdge(fContext, std::move(paint), aaType, edgeAA, viewMatrix,
978 croppedRect);
Michael Ludwig75451902019-01-23 11:14:29 -0500979 }
980
981 AutoCheckFlush acf(this->drawingManager());
Michael Ludwig136f45a2019-02-19 11:44:41 -0500982 this->addDrawOp(clip, std::move(op));
Michael Ludwig75451902019-01-23 11:14:29 -0500983}
984
Michael Ludwigce62dec2019-02-19 11:48:46 -0500985void GrRenderTargetContext::fillQuadWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa,
986 GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix,
987 const SkPoint quad[4], const SkPoint localQuad[4]) {
988 ASSERT_SINGLE_OWNER
989 RETURN_IF_ABANDONED
990 SkDEBUGCODE(this->validate();)
991 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillQuadWithEdgeAA", fContext);
992
Chris Dalton7d6748e2019-03-13 00:34:52 -0600993 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwigce62dec2019-02-19 11:48:46 -0500994
995 AutoCheckFlush acf(this->drawingManager());
996 // MakePerEdgeQuad automatically does the right thing if localQuad is null or not
997 this->addDrawOp(clip, GrFillRectOp::MakePerEdgeQuad(fContext, std::move(paint), aaType, edgeAA,
998 viewMatrix, quad, localQuad));
999}
1000
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001001// Creates a paint for GrFillRectOp that matches behavior of GrTextureOp
1002static void draw_texture_to_grpaint(sk_sp<GrTextureProxy> proxy, const SkRect* domain,
1003 GrSamplerState::Filter filter, SkBlendMode mode,
1004 const SkPMColor4f& color, sk_sp<GrColorSpaceXform> csXform,
1005 GrPaint* paint) {
1006 paint->setColor4f(color);
1007 paint->setXPFactory(SkBlendMode_AsXPFactory(mode));
1008
1009 std::unique_ptr<GrFragmentProcessor> fp;
1010 if (domain) {
Michael Ludwigce62dec2019-02-19 11:48:46 -05001011 SkRect correctedDomain = *domain;
1012 if (filter == GrSamplerState::Filter::kBilerp) {
1013 // Inset by 1/2 pixel, which GrTextureOp and GrTextureAdjuster handle automatically
1014 correctedDomain.inset(0.5f, 0.5f);
1015 }
1016 fp = GrTextureDomainEffect::Make(std::move(proxy), SkMatrix::I(), correctedDomain,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001017 GrTextureDomain::kClamp_Mode, filter);
1018 } else {
1019 fp = GrSimpleTextureEffect::Make(std::move(proxy), SkMatrix::I(), filter);
1020 }
1021
1022 fp = GrColorSpaceXformEffect::Make(std::move(fp), csXform);
1023 paint->addColorFragmentProcessor(std::move(fp));
1024}
1025
Brian Salomonbe3c1d22018-05-21 12:54:39 -04001026void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001027 GrSamplerState::Filter filter, SkBlendMode mode,
1028 const SkPMColor4f& color, const SkRect& srcRect,
Michael Ludwig136f45a2019-02-19 11:44:41 -05001029 const SkRect& dstRect, GrAA aa, GrQuadAAFlags aaFlags,
Brian Salomonb80ffee2018-05-23 16:39:39 -04001030 SkCanvas::SrcRectConstraint constraint,
Brian Salomonbe3c1d22018-05-21 12:54:39 -04001031 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -05001032 sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
Brian Salomon34169692017-08-28 15:32:01 -04001033 ASSERT_SINGLE_OWNER
1034 RETURN_IF_ABANDONED
1035 SkDEBUGCODE(this->validate();)
Brian Salomonbe3c1d22018-05-21 12:54:39 -04001036 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTexture", fContext);
Brian Salomonf1709042018-10-03 11:57:00 -04001037 if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
1038 srcRect.contains(proxy->getWorstCaseBoundsRect())) {
1039 constraint = SkCanvas::kFast_SrcRectConstraint;
Brian Salomon34169692017-08-28 15:32:01 -04001040 }
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001041
Chris Dalton7d6748e2019-03-13 00:34:52 -06001042 GrAAType aaType = this->chooseAAType(aa);
Brian Salomonff9d6d32017-08-30 10:27:49 -04001043 SkRect clippedDstRect = dstRect;
1044 SkRect clippedSrcRect = srcRect;
1045 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &clippedDstRect,
1046 &clippedSrcRect)) {
1047 return;
1048 }
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001049
1050 AutoCheckFlush acf(this->drawingManager());
1051
1052 std::unique_ptr<GrDrawOp> op;
1053 if (mode != SkBlendMode::kSrcOver) {
1054 // Emulation mode with GrPaint and GrFillRectOp
1055 if (filter != GrSamplerState::Filter::kNearest &&
1056 !GrTextureOp::GetFilterHasEffect(viewMatrix, clippedSrcRect, clippedDstRect)) {
1057 filter = GrSamplerState::Filter::kNearest;
1058 }
1059
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001060 GrPaint paint;
1061 draw_texture_to_grpaint(std::move(proxy),
Michael Ludwigce62dec2019-02-19 11:48:46 -05001062 constraint == SkCanvas::kStrict_SrcRectConstraint ? &srcRect : nullptr,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001063 filter, mode, color, std::move(textureColorSpaceXform), &paint);
1064 op = GrFillRectOp::MakePerEdgeWithLocalRect(fContext, std::move(paint), aaType, aaFlags,
1065 viewMatrix, clippedDstRect, clippedSrcRect);
1066 } else {
1067 // Can use a lighter weight op that can chain across proxies
1068 op = GrTextureOp::Make(fContext, std::move(proxy), filter, color, clippedSrcRect,
1069 clippedDstRect, aaType, aaFlags, constraint, viewMatrix,
1070 std::move(textureColorSpaceXform));
1071 }
1072
Brian Salomon2213ee92018-10-02 10:44:21 -04001073 this->addDrawOp(clip, std::move(op));
Brian Salomon34169692017-08-28 15:32:01 -04001074}
1075
Michael Ludwigce62dec2019-02-19 11:48:46 -05001076void GrRenderTargetContext::drawTextureQuad(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
1077 GrSamplerState::Filter filter, SkBlendMode mode,
1078 const SkPMColor4f& color, const SkPoint srcQuad[4],
1079 const SkPoint dstQuad[4], GrAA aa,
1080 GrQuadAAFlags aaFlags, const SkRect* domain,
1081 const SkMatrix& viewMatrix,
1082 sk_sp<GrColorSpaceXform> texXform) {
1083 ASSERT_SINGLE_OWNER
1084 RETURN_IF_ABANDONED
1085 SkDEBUGCODE(this->validate();)
1086 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureQuad", fContext);
1087 if (domain && domain->contains(proxy->getWorstCaseBoundsRect())) {
1088 domain = nullptr;
1089 }
1090
Chris Dalton7d6748e2019-03-13 00:34:52 -06001091 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwigce62dec2019-02-19 11:48:46 -05001092
1093 // Unlike drawTexture(), don't bother cropping or optimizing the filter type since we're
1094 // sampling an arbitrary quad of the texture.
1095 AutoCheckFlush acf(this->drawingManager());
1096 std::unique_ptr<GrDrawOp> op;
1097 if (mode != SkBlendMode::kSrcOver) {
1098 // Emulation mode, but don't bother converting to kNearest filter since it's an arbitrary
1099 // quad that is being drawn, which makes the tests too expensive here
1100 GrPaint paint;
1101 draw_texture_to_grpaint(
1102 std::move(proxy), domain, filter, mode, color, std::move(texXform), &paint);
1103 op = GrFillRectOp::MakePerEdgeQuad(fContext, std::move(paint), aaType, aaFlags, viewMatrix,
1104 dstQuad, srcQuad);
1105 } else {
1106 // Use lighter weight GrTextureOp
1107 op = GrTextureOp::MakeQuad(fContext, std::move(proxy), filter, color, srcQuad, dstQuad,
1108 aaType, aaFlags, domain, viewMatrix, std::move(texXform));
1109 }
1110
1111 this->addDrawOp(clip, std::move(op));
1112}
1113
Brian Salomond7065e72018-10-12 11:42:02 -04001114void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetEntry set[], int cnt,
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001115 GrSamplerState::Filter filter, SkBlendMode mode,
Michael Ludwig31ba7182019-04-03 10:38:06 -04001116 GrAA aa, SkCanvas::SrcRectConstraint constraint,
1117 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -05001118 sk_sp<GrColorSpaceXform> texXform) {
Brian Salomond7065e72018-10-12 11:42:02 -04001119 ASSERT_SINGLE_OWNER
1120 RETURN_IF_ABANDONED
1121 SkDEBUGCODE(this->validate();)
1122 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureSet", fContext);
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001123
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001124 if (mode != SkBlendMode::kSrcOver ||
Robert Phillips9da87e02019-02-04 13:26:26 -05001125 !fContext->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001126 // Draw one at a time with GrFillRectOp and a GrPaint that emulates what GrTextureOp does
Michael Ludwig7ae2ab52019-03-05 16:00:20 -05001127 SkMatrix ctm;
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001128 for (int i = 0; i < cnt; ++i) {
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001129 float alpha = set[i].fAlpha;
Michael Ludwig7ae2ab52019-03-05 16:00:20 -05001130 ctm = viewMatrix;
1131 if (set[i].fPreViewMatrix) {
1132 ctm.preConcat(*set[i].fPreViewMatrix);
1133 }
1134
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001135 if (set[i].fDstClipQuad == nullptr) {
Michael Ludwigce62dec2019-02-19 11:48:46 -05001136 // Stick with original rectangles, which allows the ops to know more about what's
1137 // being drawn.
1138 this->drawTexture(clip, set[i].fProxy, filter, mode, {alpha, alpha, alpha, alpha},
1139 set[i].fSrcRect, set[i].fDstRect, aa, set[i].fAAFlags,
Michael Ludwig31ba7182019-04-03 10:38:06 -04001140 constraint, ctm, texXform);
Michael Ludwigce62dec2019-02-19 11:48:46 -05001141 } else {
1142 // Generate interpolated texture coordinates to match the dst clip
1143 SkPoint srcQuad[4];
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001144 GrMapRectPoints(set[i].fDstRect, set[i].fSrcRect, set[i].fDstClipQuad, srcQuad, 4);
Michael Ludwig31ba7182019-04-03 10:38:06 -04001145 const SkRect* domain = constraint == SkCanvas::kStrict_SrcRectConstraint
1146 ? &set[i].fSrcRect : nullptr;
Michael Ludwigce62dec2019-02-19 11:48:46 -05001147 this->drawTextureQuad(clip, set[i].fProxy, filter, mode,
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001148 {alpha, alpha, alpha, alpha}, srcQuad, set[i].fDstClipQuad,
Michael Ludwig31ba7182019-04-03 10:38:06 -04001149 aa, set[i].fAAFlags, domain, ctm, texXform);
Michael Ludwigce62dec2019-02-19 11:48:46 -05001150 }
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001151 }
1152 } else {
1153 // Can use a single op, avoiding GrPaint creation, and can batch across proxies
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001154 AutoCheckFlush acf(this->drawingManager());
Chris Dalton7d6748e2019-03-13 00:34:52 -06001155 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig31ba7182019-04-03 10:38:06 -04001156 auto op = GrTextureOp::MakeSet(fContext, set, cnt, filter, aaType, constraint, viewMatrix,
Michael Ludwig009b92e2019-02-15 16:03:53 -05001157 std::move(texXform));
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001158 this->addDrawOp(clip, std::move(op));
1159 }
Brian Salomond7065e72018-10-12 11:42:02 -04001160}
1161
Brian Osman11052242016-10-27 14:47:55 -04001162void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001163 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001164 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001165 const SkMatrix& viewMatrix,
1166 const SkRect& rectToDraw,
1167 const SkMatrix& localMatrix) {
joshualitt1de610a2016-01-06 08:26:09 -08001168 ASSERT_SINGLE_OWNER
joshualittb6b513b2015-08-21 10:25:18 -07001169 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001170 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001171 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithLocalMatrix", fContext);
joshualittb6b513b2015-08-21 10:25:18 -07001172
csmartdalton97f6cd52016-07-13 13:37:08 -07001173 SkRect croppedRect = rectToDraw;
robertphillips13a7eee2016-08-31 15:06:24 -07001174 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
csmartdalton97f6cd52016-07-13 13:37:08 -07001175 return;
1176 }
1177
Robert Phillips72152832017-01-25 17:31:35 -05001178 AutoCheckFlush acf(this->drawingManager());
csmartdaltona7f29642016-07-07 08:49:11 -07001179
Chris Dalton7d6748e2019-03-13 00:34:52 -06001180 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig72ab3462018-12-10 12:43:36 -05001181 this->addDrawOp(clip, GrFillRectOp::MakeWithLocalMatrix(fContext, std::move(paint), aaType,
1182 viewMatrix, localMatrix, croppedRect));
robertphillipsea461502015-05-26 11:38:03 -07001183}
1184
Brian Osman11052242016-10-27 14:47:55 -04001185void GrRenderTargetContext::drawVertices(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001186 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -04001187 const SkMatrix& viewMatrix,
Brian Osmanae0c50c2017-05-25 16:56:34 -04001188 sk_sp<SkVertices> vertices,
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001189 const SkVertices::Bone bones[],
Ruiqi Mao4ec72f72018-07-10 17:21:07 -04001190 int boneCount,
Brian Osmanae0c50c2017-05-25 16:56:34 -04001191 GrPrimitiveType* overridePrimType) {
Brian Salomon199fb872017-02-06 09:41:10 -05001192 ASSERT_SINGLE_OWNER
1193 RETURN_IF_ABANDONED
1194 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001195 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawVertices", fContext);
Brian Salomon199fb872017-02-06 09:41:10 -05001196
1197 AutoCheckFlush acf(this->drawingManager());
1198
1199 SkASSERT(vertices);
Chris Dalton7d6748e2019-03-13 00:34:52 -06001200 GrAAType aaType = this->chooseAAType(GrAA::kNo);
Brian Salomonf3569f02017-10-24 12:52:33 -04001201 std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
Ruiqi Mao4ec72f72018-07-10 17:21:07 -04001202 fContext, std::move(paint), std::move(vertices), bones, boneCount, viewMatrix, aaType,
Brian Salomonf3569f02017-10-24 12:52:33 -04001203 this->colorSpaceInfo().refColorSpaceXformFromSRGB(), overridePrimType);
Brian Salomonc2f42542017-07-12 14:11:22 -04001204 this->addDrawOp(clip, std::move(op));
robertphillipsea461502015-05-26 11:38:03 -07001205}
1206
1207///////////////////////////////////////////////////////////////////////////////
1208
Brian Osman4d92b892019-03-24 00:53:23 +00001209void GrRenderTargetContext::drawAtlas(const GrClip& clip,
1210 GrPaint&& paint,
1211 const SkMatrix& viewMatrix,
1212 int spriteCount,
1213 const SkRSXform xform[],
1214 const SkRect texRect[],
1215 const SkColor colors[]) {
1216 ASSERT_SINGLE_OWNER
1217 RETURN_IF_ABANDONED
1218 SkDEBUGCODE(this->validate();)
1219 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawAtlas", fContext);
1220
1221 AutoCheckFlush acf(this->drawingManager());
1222
1223 GrAAType aaType = this->chooseAAType(GrAA::kNo);
1224 std::unique_ptr<GrDrawOp> op = GrDrawAtlasOp::Make(fContext, std::move(paint), viewMatrix,
1225 aaType, spriteCount, xform, texRect, colors);
1226 this->addDrawOp(clip, std::move(op));
1227}
1228
1229///////////////////////////////////////////////////////////////////////////////
1230
Brian Osman11052242016-10-27 14:47:55 -04001231void GrRenderTargetContext::drawRRect(const GrClip& origClip,
Brian Salomon82f44312017-01-11 13:42:54 -05001232 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001233 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001234 const SkMatrix& viewMatrix,
1235 const SkRRect& rrect,
1236 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08001237 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07001238 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001239 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001240 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRRect", fContext);
Robert Phillips85290802018-07-02 13:14:28 -04001241
1242 const SkStrokeRec& stroke = style.strokeRec();
1243 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07001244 return;
1245 }
1246
bsalomon7f0d9f32016-08-15 14:49:10 -07001247 GrNoClip noclip;
1248 const GrClip* clip = &origClip;
1249#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1250 // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
Brian Salomon42521e82016-12-07 16:44:58 -05001251 // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it
bsalomon7f0d9f32016-08-15 14:49:10 -07001252 // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
1253 // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
Michael Ludwig28398842019-03-25 10:24:24 -04001254 // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. This
1255 // only works for filled rrects since the stroke width outsets beyond the rrect itself.
bsalomon7f0d9f32016-08-15 14:49:10 -07001256 SkRRect devRRect;
Michael Ludwig28398842019-03-25 10:24:24 -04001257 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.transform(viewMatrix, &devRRect) &&
1258 clip->quickContains(devRRect)) {
bsalomon7f0d9f32016-08-15 14:49:10 -07001259 clip = &noclip;
1260 }
1261#endif
bsalomon6663acf2016-05-10 09:14:17 -07001262 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
ksakamotoec7f2ac2016-07-05 03:54:53 -07001263
Robert Phillips72152832017-01-25 17:31:35 -05001264 AutoCheckFlush acf(this->drawingManager());
csmartdaltona7f29642016-07-07 08:49:11 -07001265
Chris Dalton7d6748e2019-03-13 00:34:52 -06001266 GrAAType aaType = this->chooseAAType(aa);
Chris Dalton133944a2018-11-16 23:30:29 -05001267
Chris Dalton0dffbab2019-03-27 13:08:50 -06001268 std::unique_ptr<GrDrawOp> op;
1269 if (style.isSimpleFill()) {
1270 assert_alive(paint);
1271 op = GrFillRRectOp::Make(
1272 fContext, aaType, viewMatrix, rrect, *this->caps(), std::move(paint));
1273 }
Greg Daniel2655ede2019-04-10 00:49:28 +00001274 if (!op && GrAAType::kCoverage == aaType) {
Chris Dalton0dffbab2019-03-27 13:08:50 -06001275 assert_alive(paint);
1276 op = GrOvalOpFactory::MakeRRectOp(
Greg Daniel2655ede2019-04-10 00:49:28 +00001277 fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
1278
Chris Dalton0dffbab2019-03-27 13:08:50 -06001279 }
1280 if (op) {
1281 this->addDrawOp(*clip, std::move(op));
1282 return;
robertphillipsea461502015-05-26 11:38:03 -07001283 }
robertphillipsb56f9272016-02-25 11:03:52 -08001284
Mike Klein16885072018-12-11 09:54:31 -05001285 assert_alive(paint);
Brian Salomon2fad74a2017-12-20 13:28:55 -05001286 this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix,
1287 GrShape(rrect, style));
robertphillipsea461502015-05-26 11:38:03 -07001288}
1289
Jim Van Verthc5903412016-11-17 15:27:09 -05001290///////////////////////////////////////////////////////////////////////////////
1291
Jim Van Verth3af1af92017-05-18 15:06:54 -04001292static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
1293 SkPoint3 result;
1294 m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
1295 result.fZ = pt.fZ;
1296 return result;
1297}
1298
1299bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
Jim Van Verth3af1af92017-05-18 15:06:54 -04001300 const SkMatrix& viewMatrix,
1301 const SkPath& path,
1302 const SkDrawShadowRec& rec) {
Jim Van Verthc5903412016-11-17 15:27:09 -05001303 ASSERT_SINGLE_OWNER
Robert Phillips6a6de562019-02-15 15:19:15 -05001304 if (fContext->priv().abandoned()) {
Jim Van Verth3af1af92017-05-18 15:06:54 -04001305 return true;
1306 }
Jim Van Verthc5903412016-11-17 15:27:09 -05001307 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001308 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFastShadow", fContext);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001309
1310 // check z plane
1311 bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1312 !SkScalarNearlyZero(rec.fZPlaneParams.fY));
1313 bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1314 if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1315 return false;
1316 }
1317
1318 SkRRect rrect;
1319 SkRect rect;
1320 // we can only handle rects, circles, and rrects with circular corners
Mike Reed242135a2018-02-22 13:41:39 -05001321 bool isRRect = path.isRRect(&rrect) && SkRRectPriv::IsSimpleCircular(rrect) &&
Jim Van Verth3af1af92017-05-18 15:06:54 -04001322 rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero;
1323 if (!isRRect &&
1324 path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1325 rect.width() > SK_ScalarNearlyZero) {
1326 rrect.setOval(rect);
1327 isRRect = true;
1328 }
1329 if (!isRRect && path.isRect(&rect)) {
1330 rrect.setRect(rect);
1331 isRRect = true;
1332 }
1333
1334 if (!isRRect) {
1335 return false;
1336 }
1337
Jim Van Verthc5903412016-11-17 15:27:09 -05001338 if (rrect.isEmpty()) {
Jim Van Verth3af1af92017-05-18 15:06:54 -04001339 return true;
Jim Van Verthc5903412016-11-17 15:27:09 -05001340 }
1341
Robert Phillips72152832017-01-25 17:31:35 -05001342 AutoCheckFlush acf(this->drawingManager());
Jim Van Verthc5903412016-11-17 15:27:09 -05001343
Jim Van Verth3af1af92017-05-18 15:06:54 -04001344 // transform light
1345 SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
1346
1347 // 1/scale
1348 SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1349 SkScalarInvert(viewMatrix[SkMatrix::kMScaleX]) :
1350 sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1351 viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1352
1353 SkScalar occluderHeight = rec.fZPlaneParams.fZ;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001354 bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1355
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001356 if (SkColorGetA(rec.fAmbientColor) > 0) {
Jim Van Verth1af03d42017-07-31 09:34:58 -04001357 SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1358 const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1359 const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001360
1361 // Outset the shadow rrect to the border of the penumbra
1362 SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1363 SkRRect ambientRRect;
1364 SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1365 // If the rrect was an oval then its outset will also be one.
1366 // We set it explicitly to avoid errors.
1367 if (rrect.isOval()) {
1368 ambientRRect = SkRRect::MakeOval(outsetRect);
1369 } else {
Mike Reed242135a2018-02-22 13:41:39 -05001370 SkScalar outsetRad = SkRRectPriv::GetSimpleRadii(rrect).fX + ambientPathOutset;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001371 ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1372 }
1373
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001374 GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001375 if (transparent) {
1376 // set a large inset to force a fill
1377 devSpaceInsetWidth = ambientRRect.width();
1378 }
Jim Van Verth39e71652018-04-23 18:08:45 +00001379
Robert Phillips7c525e62018-06-12 10:11:12 -04001380 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1381 ambientColor,
1382 viewMatrix,
Brian Salomon05969092017-07-13 11:20:51 -04001383 ambientRRect,
1384 devSpaceAmbientBlur,
Jim Van Verthfb186392018-09-11 11:37:46 -04001385 devSpaceInsetWidth);
Robert Phillipse5763782019-04-17 14:38:24 -04001386 if (op) {
1387 this->addDrawOp(clip, std::move(op));
1388 }
Jim Van Verthc5903412016-11-17 15:27:09 -05001389 }
Jim Van Verth3af1af92017-05-18 15:06:54 -04001390
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001391 if (SkColorGetA(rec.fSpotColor) > 0) {
Jim Van Verth1af03d42017-07-31 09:34:58 -04001392 SkScalar devSpaceSpotBlur;
1393 SkScalar spotScale;
1394 SkVector spotOffset;
1395 SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1396 devLightPos.fZ, rec.fLightRadius,
1397 &devSpaceSpotBlur, &spotScale, &spotOffset);
1398 // handle scale of radius due to CTM
Jim Van Verth3af1af92017-05-18 15:06:54 -04001399 const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1400
Jim Van Verth3af1af92017-05-18 15:06:54 -04001401 // Adjust translate for the effect of the scale.
1402 spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1403 spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1404 // This offset is in dev space, need to transform it into source space.
1405 SkMatrix ctmInverse;
1406 if (viewMatrix.invert(&ctmInverse)) {
1407 ctmInverse.mapPoints(&spotOffset, 1);
1408 } else {
1409 // Since the matrix is a similarity, this should never happen, but just in case...
1410 SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1411 SkASSERT(false);
1412 }
1413
1414 // Compute the transformed shadow rrect
1415 SkRRect spotShadowRRect;
1416 SkMatrix shadowTransform;
1417 shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1418 rrect.transform(shadowTransform, &spotShadowRRect);
Mike Reed242135a2018-02-22 13:41:39 -05001419 SkScalar spotRadius = SkRRectPriv::GetSimpleRadii(spotShadowRRect).fX;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001420
1421 // Compute the insetWidth
Jim Van Verth1af03d42017-07-31 09:34:58 -04001422 SkScalar blurOutset = srcSpaceSpotBlur;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001423 SkScalar insetWidth = blurOutset;
1424 if (transparent) {
1425 // If transparent, just do a fill
1426 insetWidth += spotShadowRRect.width();
1427 } else {
1428 // For shadows, instead of using a stroke we specify an inset from the penumbra
1429 // border. We want to extend this inset area so that it meets up with the caster
1430 // geometry. The inset geometry will by default already be inset by the blur width.
1431 //
1432 // We compare the min and max corners inset by the radius between the original
1433 // rrect and the shadow rrect. The distance between the two plus the difference
1434 // between the scaled radius and the original radius gives the distance from the
1435 // transformed shadow shape to the original shape in that corner. The max
1436 // of these gives the maximum distance we need to cover.
1437 //
1438 // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1439 // that to get the full insetWidth.
1440 SkScalar maxOffset;
1441 if (rrect.isRect()) {
1442 // Manhattan distance works better for rects
1443 maxOffset = SkTMax(SkTMax(SkTAbs(spotShadowRRect.rect().fLeft -
1444 rrect.rect().fLeft),
1445 SkTAbs(spotShadowRRect.rect().fTop -
1446 rrect.rect().fTop)),
1447 SkTMax(SkTAbs(spotShadowRRect.rect().fRight -
1448 rrect.rect().fRight),
1449 SkTAbs(spotShadowRRect.rect().fBottom -
1450 rrect.rect().fBottom)));
1451 } else {
Mike Reed242135a2018-02-22 13:41:39 -05001452 SkScalar dr = spotRadius - SkRRectPriv::GetSimpleRadii(rrect).fX;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001453 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1454 rrect.rect().fLeft + dr,
1455 spotShadowRRect.rect().fTop -
1456 rrect.rect().fTop + dr);
1457 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1458 rrect.rect().fRight - dr,
1459 spotShadowRRect.rect().fBottom -
1460 rrect.rect().fBottom - dr);
Cary Clarkdf429f32017-11-08 11:44:31 -05001461 maxOffset = SkScalarSqrt(SkTMax(SkPointPriv::LengthSqd(upperLeftOffset),
1462 SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001463 }
Jim Van Verth4c8c1e82018-04-23 17:14:48 -04001464 insetWidth += SkTMax(blurOutset, maxOffset);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001465 }
1466
1467 // Outset the shadow rrect to the border of the penumbra
1468 SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1469 if (spotShadowRRect.isOval()) {
1470 spotShadowRRect = SkRRect::MakeOval(outsetRect);
1471 } else {
1472 SkScalar outsetRad = spotRadius + blurOutset;
1473 spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1474 }
1475
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001476 GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
Jim Van Verth34d6e4b2017-06-09 11:09:03 -04001477
Robert Phillips7c525e62018-06-12 10:11:12 -04001478 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1479 spotColor,
1480 viewMatrix,
Brian Salomon05969092017-07-13 11:20:51 -04001481 spotShadowRRect,
Jim Van Verth1af03d42017-07-31 09:34:58 -04001482 2.0f * devSpaceSpotBlur,
Brian Salomon05969092017-07-13 11:20:51 -04001483 insetWidth);
Robert Phillipse5763782019-04-17 14:38:24 -04001484 if (op) {
1485 this->addDrawOp(clip, std::move(op));
1486 }
Jim Van Verth3af1af92017-05-18 15:06:54 -04001487 }
1488
1489 return true;
Jim Van Verthc5903412016-11-17 15:27:09 -05001490}
1491
1492///////////////////////////////////////////////////////////////////////////////
1493
Brian Osman11052242016-10-27 14:47:55 -04001494bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001495 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001496 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001497 const SkMatrix& viewMatrix,
1498 const SkRRect& origOuter,
1499 const SkRRect& origInner) {
robertphillips00095892016-02-29 13:50:40 -08001500 SkASSERT(!origInner.isEmpty());
1501 SkASSERT(!origOuter.isEmpty());
1502
Brian Salomon65749212017-12-01 16:01:47 -05001503 SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
1504
Chris Dalton7d6748e2019-03-13 00:34:52 -06001505 GrAAType aaType = this->chooseAAType(aa);
Brian Salomon45839f92017-12-04 09:02:35 -05001506
1507 if (GrAAType::kMSAA == aaType) {
1508 return false;
1509 }
1510
Greg Daniel2655ede2019-04-10 00:49:28 +00001511 if (GrAAType::kCoverage == aaType && SkRRectPriv::IsCircle(*inner)
1512 && SkRRectPriv::IsCircle(*outer)) {
Brian Salomon65749212017-12-01 16:01:47 -05001513 auto outerR = outer->width() / 2.f;
1514 auto innerR = inner->width() / 2.f;
1515 auto cx = outer->getBounds().fLeft + outerR;
1516 auto cy = outer->getBounds().fTop + outerR;
1517 if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) &&
1518 SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) {
1519 auto avgR = (innerR + outerR) / 2.f;
1520 auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR);
1521 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
1522 stroke.setStrokeStyle(outerR - innerR);
Greg Daniel2655ede2019-04-10 00:49:28 +00001523 auto op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix,
Robert Phillips7c525e62018-06-12 10:11:12 -04001524 circleBounds, GrStyle(stroke, nullptr),
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001525 this->caps()->shaderCaps());
Brian Salomon65749212017-12-01 16:01:47 -05001526 if (op) {
1527 this->addDrawOp(clip, std::move(op));
1528 return true;
1529 }
Mike Klein16885072018-12-11 09:54:31 -05001530 assert_alive(paint);
Brian Salomon65749212017-12-01 16:01:47 -05001531 }
1532 }
1533
Ethan Nicholas0f3c7322017-11-09 14:51:17 -05001534 GrClipEdgeType innerEdgeType, outerEdgeType;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001535 if (GrAAType::kCoverage == aaType) {
Ethan Nicholas1706f842017-11-10 11:58:19 -05001536 innerEdgeType = GrClipEdgeType::kInverseFillAA;
1537 outerEdgeType = GrClipEdgeType::kFillAA;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001538 } else {
Ethan Nicholas1706f842017-11-10 11:58:19 -05001539 innerEdgeType = GrClipEdgeType::kInverseFillBW;
1540 outerEdgeType = GrClipEdgeType::kFillBW;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001541 }
robertphillips00095892016-02-29 13:50:40 -08001542
robertphillips00095892016-02-29 13:50:40 -08001543 SkMatrix inverseVM;
1544 if (!viewMatrix.isIdentity()) {
1545 if (!origInner.transform(viewMatrix, inner.writable())) {
1546 return false;
1547 }
1548 if (!origOuter.transform(viewMatrix, outer.writable())) {
1549 return false;
1550 }
1551 if (!viewMatrix.invert(&inverseVM)) {
1552 return false;
1553 }
1554 } else {
1555 inverseVM.reset();
halcanary9d524f22016-03-29 09:03:52 -07001556 }
robertphillips00095892016-02-29 13:50:40 -08001557
Ethan Nicholaseace9352018-10-15 20:09:54 +00001558 const auto& caps = *this->caps()->shaderCaps();
robertphillips00095892016-02-29 13:50:40 -08001559 // TODO these need to be a geometry processors
Ethan Nicholaseace9352018-10-15 20:09:54 +00001560 auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps);
robertphillips00095892016-02-29 13:50:40 -08001561 if (!innerEffect) {
1562 return false;
1563 }
1564
Ethan Nicholaseace9352018-10-15 20:09:54 +00001565 auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps);
robertphillips00095892016-02-29 13:50:40 -08001566 if (!outerEffect) {
1567 return false;
1568 }
1569
Brian Salomon82f44312017-01-11 13:42:54 -05001570 paint.addCoverageFragmentProcessor(std::move(innerEffect));
1571 paint.addCoverageFragmentProcessor(std::move(outerEffect));
robertphillips00095892016-02-29 13:50:40 -08001572
1573 SkRect bounds = outer->getBounds();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001574 if (GrAAType::kCoverage == aaType) {
robertphillips00095892016-02-29 13:50:40 -08001575 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1576 }
halcanary9d524f22016-03-29 09:03:52 -07001577
Brian Salomon82f44312017-01-11 13:42:54 -05001578 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds,
1579 inverseVM);
robertphillips00095892016-02-29 13:50:40 -08001580 return true;
1581}
1582
Brian Osman11052242016-10-27 14:47:55 -04001583void GrRenderTargetContext::drawDRRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001584 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001585 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001586 const SkMatrix& viewMatrix,
1587 const SkRRect& outer,
1588 const SkRRect& inner) {
robertphillips00095892016-02-29 13:50:40 -08001589 ASSERT_SINGLE_OWNER
1590 RETURN_IF_ABANDONED
1591 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001592 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawDRRect", fContext);
robertphillips00095892016-02-29 13:50:40 -08001593
1594 SkASSERT(!outer.isEmpty());
1595 SkASSERT(!inner.isEmpty());
1596
Robert Phillips72152832017-01-25 17:31:35 -05001597 AutoCheckFlush acf(this->drawingManager());
robertphillips00095892016-02-29 13:50:40 -08001598
Brian Salomon82f44312017-01-11 13:42:54 -05001599 if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) {
robertphillips00095892016-02-29 13:50:40 -08001600 return;
1601 }
Mike Klein16885072018-12-11 09:54:31 -05001602 assert_alive(paint);
robertphillips00095892016-02-29 13:50:40 -08001603
1604 SkPath path;
1605 path.setIsVolatile(true);
1606 path.addRRect(inner);
1607 path.addRRect(outer);
1608 path.setFillType(SkPath::kEvenOdd_FillType);
Brian Salomon2fad74a2017-12-20 13:28:55 -05001609 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path));
robertphillips00095892016-02-29 13:50:40 -08001610}
1611
robertphillipsea461502015-05-26 11:38:03 -07001612///////////////////////////////////////////////////////////////////////////////
1613
Brian Osman11052242016-10-27 14:47:55 -04001614void GrRenderTargetContext::drawRegion(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001615 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001616 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001617 const SkMatrix& viewMatrix,
1618 const SkRegion& region,
Stan Iliev73d8fd92017-08-02 15:36:24 -04001619 const GrStyle& style,
1620 const GrUserStencilSettings* ss) {
msarettcc319b92016-08-25 18:07:18 -07001621 ASSERT_SINGLE_OWNER
1622 RETURN_IF_ABANDONED
1623 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001624 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRegion", fContext);
msarettcc319b92016-08-25 18:07:18 -07001625
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001626 if (GrAA::kYes == aa) {
Brian Salomonfc527d22016-12-14 21:07:01 -05001627 // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
Brian Salomonc57c7c92016-12-06 14:47:34 -05001628 // to see whether aa is really required.
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001629 if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
Brian Salomon34169692017-08-28 15:32:01 -04001630 SkScalarIsInt(viewMatrix.getTranslateX()) &&
1631 SkScalarIsInt(viewMatrix.getTranslateY())) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001632 aa = GrAA::kNo;
1633 }
Brian Salomonc57c7c92016-12-06 14:47:34 -05001634 }
msarettcc319b92016-08-25 18:07:18 -07001635 bool complexStyle = !style.isSimpleFill();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001636 if (complexStyle || GrAA::kYes == aa) {
msarettcc319b92016-08-25 18:07:18 -07001637 SkPath path;
1638 region.getBoundaryPath(&path);
Robert Phillips46a13382018-08-23 13:53:01 -04001639 path.setIsVolatile(true);
1640
Brian Salomon82f44312017-01-11 13:42:54 -05001641 return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
msarettcc319b92016-08-25 18:07:18 -07001642 }
1643
Chris Dalton7d6748e2019-03-13 00:34:52 -06001644 GrAAType aaType = this->chooseAAType(GrAA::kNo);
Robert Phillips7c525e62018-06-12 10:11:12 -04001645 std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(fContext, std::move(paint), viewMatrix, region,
1646 aaType, ss);
Brian Salomonf0366322017-07-11 15:53:05 -04001647 this->addDrawOp(clip, std::move(op));
msarettcc319b92016-08-25 18:07:18 -07001648}
1649
Brian Osman11052242016-10-27 14:47:55 -04001650void GrRenderTargetContext::drawOval(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001651 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001652 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001653 const SkMatrix& viewMatrix,
1654 const SkRect& oval,
1655 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08001656 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07001657 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001658 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001659 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawOval", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -07001660
Robert Phillips7484d202018-07-03 09:09:08 -04001661 const SkStrokeRec& stroke = style.strokeRec();
1662
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001663 if (oval.isEmpty() && !style.pathEffect()) {
Robert Phillips7484d202018-07-03 09:09:08 -04001664 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1665 return;
1666 }
1667
1668 this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001669 return;
robertphillipsea461502015-05-26 11:38:03 -07001670 }
1671
Robert Phillips72152832017-01-25 17:31:35 -05001672 AutoCheckFlush acf(this->drawingManager());
csmartdaltona7f29642016-07-07 08:49:11 -07001673
Chris Dalton7d6748e2019-03-13 00:34:52 -06001674 GrAAType aaType = this->chooseAAType(aa);
Chris Dalton0dffbab2019-03-27 13:08:50 -06001675
1676 std::unique_ptr<GrDrawOp> op;
1677 if (style.isSimpleFill()) {
Chris Dalton82eb9e72019-03-21 14:26:39 -06001678 // GrFillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate
1679 // the arc equation. This same special geometry and fragment branch also turn out to be a
1680 // substantial optimization for drawing ovals (namely, by not evaluating the arc equation
1681 // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw
1682 // ovals the exact same way we do round rects.
Chris Daltonebc38c92018-11-28 16:58:09 -07001683 //
Greg Daniel2655ede2019-04-10 00:49:28 +00001684 // However, we still don't draw true circles as round rects in coverage mode, because it can
1685 // cause perf regressions on some platforms as compared to the dedicated circle Op.
1686 if (GrAAType::kCoverage != aaType || oval.height() != oval.width()) {
Chris Daltonbf341ae2019-03-27 00:28:22 +00001687 assert_alive(paint);
Chris Dalton0dffbab2019-03-27 13:08:50 -06001688 op = GrFillRRectOp::Make(fContext, aaType, viewMatrix, SkRRect::MakeOval(oval),
1689 *this->caps(), std::move(paint));
Chris Daltonbf341ae2019-03-27 00:28:22 +00001690 }
Chris Dalton0dffbab2019-03-27 13:08:50 -06001691 }
Greg Daniel2655ede2019-04-10 00:49:28 +00001692 if (!op && GrAAType::kCoverage == aaType) {
Chris Dalton0dffbab2019-03-27 13:08:50 -06001693 assert_alive(paint);
Greg Daniel2655ede2019-04-10 00:49:28 +00001694 op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1695 this->caps()->shaderCaps());
Chris Dalton0dffbab2019-03-27 13:08:50 -06001696 }
1697 if (op) {
1698 this->addDrawOp(clip, std::move(op));
1699 return;
robertphillipsea461502015-05-26 11:38:03 -07001700 }
robertphillipsb56f9272016-02-25 11:03:52 -08001701
Mike Klein16885072018-12-11 09:54:31 -05001702 assert_alive(paint);
Brian Salomon5209d7f2018-04-20 16:52:42 -04001703 this->drawShapeUsingPathRenderer(
1704 clip, std::move(paint), aa, viewMatrix,
1705 GrShape(SkRRect::MakeOval(oval), SkPath::kCW_Direction, 2, false, style));
robertphillipsea461502015-05-26 11:38:03 -07001706}
1707
Brian Osman11052242016-10-27 14:47:55 -04001708void GrRenderTargetContext::drawArc(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001709 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001710 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001711 const SkMatrix& viewMatrix,
1712 const SkRect& oval,
1713 SkScalar startAngle,
1714 SkScalar sweepAngle,
1715 bool useCenter,
1716 const GrStyle& style) {
Robert Phillipsf1d0ced2017-02-10 09:31:01 -05001717 ASSERT_SINGLE_OWNER
1718 RETURN_IF_ABANDONED
1719 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001720 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawArc", fContext);
Robert Phillipsf1d0ced2017-02-10 09:31:01 -05001721
1722 AutoCheckFlush acf(this->drawingManager());
1723
Chris Dalton7d6748e2019-03-13 00:34:52 -06001724 GrAAType aaType = this->chooseAAType(aa);
Greg Daniel2655ede2019-04-10 00:49:28 +00001725 if (GrAAType::kCoverage == aaType) {
1726 const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
1727 std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(fContext,
1728 std::move(paint),
1729 viewMatrix,
1730 oval,
1731 startAngle,
1732 sweepAngle,
1733 useCenter,
1734 style,
1735 shaderCaps);
1736 if (op) {
1737 this->addDrawOp(clip, std::move(op));
1738 return;
1739 }
1740 assert_alive(paint);
bsalomon4f3a0ca2016-08-22 13:14:26 -07001741 }
Brian Salomone4949402018-04-26 15:22:04 -04001742 this->drawShapeUsingPathRenderer(
1743 clip, std::move(paint), aa, viewMatrix,
1744 GrShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style));
bsalomon4f3a0ca2016-08-22 13:14:26 -07001745}
1746
Brian Osman11052242016-10-27 14:47:55 -04001747void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001748 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -04001749 const SkMatrix& viewMatrix,
Brian Salomon2a943df2018-05-04 13:43:19 -04001750 sk_sp<GrTextureProxy> image,
1751 sk_sp<GrColorSpaceXform> csxf,
1752 GrSamplerState::Filter filter,
Brian Osman11052242016-10-27 14:47:55 -04001753 std::unique_ptr<SkLatticeIter> iter,
1754 const SkRect& dst) {
joshualitt1de610a2016-01-06 08:26:09 -08001755 ASSERT_SINGLE_OWNER
joshualitt33a5fce2015-11-18 13:28:51 -08001756 RETURN_IF_ABANDONED
1757 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001758 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawImageLattice", fContext);
joshualitt33a5fce2015-11-18 13:28:51 -08001759
Robert Phillips72152832017-01-25 17:31:35 -05001760 AutoCheckFlush acf(this->drawingManager());
joshualitt33a5fce2015-11-18 13:28:51 -08001761
Brian Salomon2a943df2018-05-04 13:43:19 -04001762 std::unique_ptr<GrDrawOp> op =
Robert Phillips7c525e62018-06-12 10:11:12 -04001763 GrLatticeOp::MakeNonAA(fContext, std::move(paint), viewMatrix, std::move(image),
1764 std::move(csxf), filter, std::move(iter), dst);
Brian Salomon815486c2017-07-11 08:52:13 -04001765 this->addDrawOp(clip, std::move(op));
joshualitt33a5fce2015-11-18 13:28:51 -08001766}
1767
Greg Daniel64cc9aa2018-10-19 13:54:56 -04001768void GrRenderTargetContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
1769 const SkRect& bounds) {
1770 std::unique_ptr<GrOp> op(GrDrawableOp::Make(fContext, std::move(drawable), bounds));
1771 SkASSERT(op);
1772 this->getRTOpList()->addOp(std::move(op), *this->caps());
1773}
1774
Brian Salomon201700f2019-05-17 12:05:44 -04001775bool GrRenderTargetContext::asyncReadPixels(const SkImageInfo& info, int srcX, int srcY,
1776 ReadPixelsCallback callback,
Brian Salomonab32f652019-05-10 14:24:50 -04001777 ReadPixelsContext context) {
1778 auto direct = fContext->priv().asDirectContext();
1779 if (!direct) {
1780 return false;
1781 }
1782 if (!this->caps()->transferBufferSupport()) {
1783 return false;
1784 }
1785 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
1786 return false;
1787 }
1788 // We currently don't know our own alpha type, we assume it's premul if we have an alpha channel
1789 // and opaque otherwise.
Brian Salomon201700f2019-05-17 12:05:44 -04001790 if (!GrPixelConfigIsAlphaOnly(fRenderTargetProxy->config()) &&
1791 info.alphaType() != kPremul_SkAlphaType) {
Brian Salomonab32f652019-05-10 14:24:50 -04001792 return false;
1793 }
Brian Salomon201700f2019-05-17 12:05:44 -04001794 auto dstCT = SkColorTypeToGrColorType(info.colorType());
Brian Salomonab32f652019-05-10 14:24:50 -04001795 auto readCT = this->caps()->supportedReadPixelsColorType(fRenderTargetProxy->config(), dstCT);
Brian Salomoncd734f62019-05-10 16:32:54 -04001796 // Fail if we can't do a CPU conversion from readCT to dstCT.
1797 if (GrColorTypeToSkColorType(readCT) == kUnknown_SkColorType) {
Brian Salomonab32f652019-05-10 14:24:50 -04001798 return false;
1799 }
Brian Salomoncd734f62019-05-10 16:32:54 -04001800 // Fail if readCT does not have all of readCT's color channels.
1801 if (GrColorTypeComponentFlags(dstCT) & ~GrColorTypeComponentFlags(readCT)) {
1802 return false;
1803 }
1804 // Fail if readCT is not supported for transfer buffers.
Brian Salomonab32f652019-05-10 14:24:50 -04001805 if (!this->caps()->transferFromOffsetAlignment(readCT)) {
1806 return false;
1807 }
1808
Brian Salomon201700f2019-05-17 12:05:44 -04001809 sk_sp<GrColorSpaceXform> xform =
1810 GrColorSpaceXform::Make(this->colorSpaceInfo().colorSpace(), kPremul_SkAlphaType,
1811 info.colorSpace(), info.alphaType());
1812 const auto srcRect = SkIRect::MakeXYWH(srcX, srcY, info.width(), info.height());
Brian Salomoncd734f62019-05-10 16:32:54 -04001813 // Insert a draw to a temporary surface if we need to do a y-flip or color space conversion.
1814 if (this->origin() == kBottomLeft_GrSurfaceOrigin || xform) {
Brian Salomonab32f652019-05-10 14:24:50 -04001815 sk_sp<GrTextureProxy> texProxy = sk_ref_sp(fRenderTargetProxy->asTextureProxy());
1816 const auto& backendFormat = fRenderTargetProxy->backendFormat();
1817 SkRect srcRectToDraw = SkRect::Make(srcRect);
1818 // If the src is not texturable first try to make a copy to a texture.
1819 if (!texProxy) {
1820 GrSurfaceDesc desc;
1821 desc.fWidth = srcRect.width();
1822 desc.fHeight = srcRect.height();
1823 desc.fConfig = fRenderTargetProxy->config();
1824 auto sContext = direct->priv().makeDeferredSurfaceContext(
1825 backendFormat, desc, this->origin(), GrMipMapped::kNo, SkBackingFit::kApprox,
1826 SkBudgeted::kNo, this->colorSpaceInfo().refColorSpace());
1827 if (!sContext) {
1828 return false;
1829 }
1830 if (!sContext->copy(fRenderTargetProxy.get(), srcRect, {0, 0})) {
1831 return false;
1832 }
1833 texProxy = sk_ref_sp(sContext->asTextureProxy());
1834 SkASSERT(texProxy);
1835 srcRectToDraw = SkRect::MakeWH(srcRect.width(), srcRect.height());
1836 }
1837 auto rtc = direct->priv().makeDeferredRenderTargetContext(
1838 backendFormat, SkBackingFit::kApprox, srcRect.width(), srcRect.height(),
Brian Salomon201700f2019-05-17 12:05:44 -04001839 fRenderTargetProxy->config(), info.refColorSpace(), 1, GrMipMapped::kNo,
1840 kTopLeft_GrSurfaceOrigin);
Brian Salomonab32f652019-05-10 14:24:50 -04001841 if (!rtc) {
1842 return false;
1843 }
1844 rtc->drawTexture(GrNoClip(), std::move(texProxy), GrSamplerState::Filter::kNearest,
1845 SkBlendMode::kSrc, SK_PMColor4fWHITE, srcRectToDraw,
1846 SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
1847 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
Brian Salomoncd734f62019-05-10 16:32:54 -04001848 std::move(xform));
Brian Salomon201700f2019-05-17 12:05:44 -04001849 return rtc->asyncReadPixels(info, 0, 0, callback, context);
Brian Salomonab32f652019-05-10 14:24:50 -04001850 }
Brian Salomoncd734f62019-05-10 16:32:54 -04001851
1852 size_t rowBytes = GrColorTypeBytesPerPixel(readCT) * srcRect.width();
Brian Salomonab32f652019-05-10 14:24:50 -04001853 size_t size = rowBytes * srcRect.height();
1854 auto buffer = direct->priv().resourceProvider()->createBuffer(
1855 size, GrGpuBufferType::kXferGpuToCpu, GrAccessPattern::kStream_GrAccessPattern);
1856 if (!buffer) {
1857 return false;
1858 }
Brian Salomoncd734f62019-05-10 16:32:54 -04001859 this->getRTOpList()->addOp(GrTransferFromOp::Make(fContext, srcRect, readCT, buffer, 0),
Brian Salomonab32f652019-05-10 14:24:50 -04001860 *this->caps());
1861 struct FinishContext {
Brian Salomoncd734f62019-05-10 16:32:54 -04001862 SkImageInfo fReadInfo;
1863 SkImageInfo fDstInfo;
Brian Salomonab32f652019-05-10 14:24:50 -04001864 ReadPixelsCallback* fClientCallback;
1865 ReadPixelsContext fClientContext;
1866 sk_sp<GrGpuBuffer> fBuffer;
1867 size_t fRowBytes;
1868 };
Brian Salomon201700f2019-05-17 12:05:44 -04001869 const auto readInfo = info.makeColorType(GrColorTypeToSkColorType(readCT));
Brian Salomonab32f652019-05-10 14:24:50 -04001870 // Assumption is that the caller would like to flush. We could take a parameter or require an
1871 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
1872 // callback to GrGpu until after the next flush that flushes our op list, though.
Brian Salomon201700f2019-05-17 12:05:44 -04001873 auto* finishContext = new FinishContext{readInfo, info, callback, context, buffer, rowBytes};
Brian Salomonab32f652019-05-10 14:24:50 -04001874 auto finishCallback = [](GrGpuFinishedContext c) {
1875 auto context = reinterpret_cast<const FinishContext*>(c);
1876 void* data = context->fBuffer->map();
Brian Salomoncd734f62019-05-10 16:32:54 -04001877 if (!data) {
1878 (*context->fClientCallback)(context->fClientContext, nullptr, 0);
1879 delete context;
1880 return;
1881 }
1882 SkAutoPixmapStorage pm;
1883 const void* callbackData = data;
1884 size_t callbackRowBytes = context->fRowBytes;
1885 if (context->fDstInfo != context->fReadInfo) {
1886 pm.alloc(context->fDstInfo);
1887 SkConvertPixels(context->fDstInfo, pm.writable_addr(), pm.rowBytes(),
1888 context->fReadInfo, data, context->fRowBytes);
1889 callbackData = pm.addr();
1890 callbackRowBytes = pm.rowBytes();
1891 }
1892 (*context->fClientCallback)(context->fClientContext, callbackData, callbackRowBytes);
Brian Salomonab32f652019-05-10 14:24:50 -04001893 if (data) {
1894 context->fBuffer->unmap();
1895 }
1896 delete context;
1897 };
1898 GrFlushInfo flushInfo;
1899 flushInfo.fFinishedContext = finishContext;
1900 flushInfo.fFinishedProc = finishCallback;
1901 this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
1902 return true;
1903}
1904
Greg Daniele6bfb7d2019-04-17 15:26:11 -04001905GrSemaphoresSubmitted GrRenderTargetContext::flush(SkSurface::BackendSurfaceAccess access,
1906 const GrFlushInfo& info) {
robertphillips8c523e02016-07-26 07:41:00 -07001907 ASSERT_SINGLE_OWNER
Robert Phillips6a6de562019-02-15 15:19:15 -05001908 if (fContext->priv().abandoned()) {
Robert Phillipsa9162df2019-02-11 14:12:03 -05001909 return GrSemaphoresSubmitted::kNo;
1910 }
robertphillips8c523e02016-07-26 07:41:00 -07001911 SkDEBUGCODE(this->validate();)
Robert Phillips15c91422019-05-07 16:54:48 -04001912 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "flush", fContext);
robertphillips8c523e02016-07-26 07:41:00 -07001913
Greg Daniele6bfb7d2019-04-17 15:26:11 -04001914 return this->drawingManager()->flushSurface(fRenderTargetProxy.get(), access, info);
Greg Daniela5cb7812017-06-16 09:45:32 -04001915}
1916
Greg Danielc64ee462017-06-15 16:59:49 -04001917bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
Robert Phillipsbc4994a2019-02-14 08:36:56 -05001918 const GrBackendSemaphore waitSemaphores[]) {
Greg Daniela5cb7812017-06-16 09:45:32 -04001919 ASSERT_SINGLE_OWNER
Greg Danielc64ee462017-06-15 16:59:49 -04001920 RETURN_FALSE_IF_ABANDONED
Greg Daniela5cb7812017-06-16 09:45:32 -04001921 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001922 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "waitOnSemaphores", fContext);
Greg Daniela5cb7812017-06-16 09:45:32 -04001923
1924 AutoCheckFlush acf(this->drawingManager());
1925
Brian Salomon9ff5acb2019-05-08 09:04:47 -04001926 if (numSemaphores && !this->caps()->semaphoreSupport()) {
Greg Danielc64ee462017-06-15 16:59:49 -04001927 return false;
1928 }
1929
Robert Phillipsbc4994a2019-02-14 08:36:56 -05001930 auto direct = fContext->priv().asDirectContext();
1931 if (!direct) {
1932 return false;
1933 }
1934
1935 auto resourceProvider = direct->priv().resourceProvider();
Robert Phillips6be756b2018-01-16 15:07:54 -05001936
Greg Daniela5cb7812017-06-16 09:45:32 -04001937 for (int i = 0; i < numSemaphores; ++i) {
Robert Phillips6be756b2018-01-16 15:07:54 -05001938 sk_sp<GrSemaphore> sema = resourceProvider->wrapBackendSemaphore(
Greg Daniel17b7c052018-01-09 13:55:33 -05001939 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
1940 kAdopt_GrWrapOwnership);
Robert Phillipsbc4994a2019-02-14 08:36:56 -05001941 std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(fContext, std::move(sema),
Robert Phillips7c525e62018-06-12 10:11:12 -04001942 fRenderTargetProxy.get()));
Greg Danielcb324152019-02-25 11:36:53 -05001943 this->getRTOpList()->addWaitOp(std::move(waitOp), *this->caps());
Greg Daniela5cb7812017-06-16 09:45:32 -04001944 }
Greg Danielc64ee462017-06-15 16:59:49 -04001945 return true;
robertphillips8c523e02016-07-26 07:41:00 -07001946}
joshualitt33a5fce2015-11-18 13:28:51 -08001947
Robert Phillips65a88fa2017-08-08 08:36:22 -04001948void GrRenderTargetContext::insertEventMarker(const SkString& str) {
Robert Phillips88a32ef2018-06-07 11:05:56 -04001949 std::unique_ptr<GrOp> op(GrDebugMarkerOp::Make(fContext, fRenderTargetProxy.get(), str));
Robert Phillips65a88fa2017-08-08 08:36:22 -04001950 this->getRTOpList()->addOp(std::move(op), *this->caps());
1951}
1952
Robert Phillipsbe9aff22019-02-15 11:33:22 -05001953const GrCaps* GrRenderTargetContext::caps() const {
1954 return fContext->priv().caps();
1955}
1956
Brian Osman11052242016-10-27 14:47:55 -04001957void GrRenderTargetContext::drawPath(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001958 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001959 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001960 const SkMatrix& viewMatrix,
Brian Salomon40b77a62017-12-22 11:25:52 -05001961 const SkPath& path,
Brian Osman11052242016-10-27 14:47:55 -04001962 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08001963 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07001964 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001965 SkDEBUGCODE(this->validate();)
Robert Phillips20390c32018-08-17 11:01:03 -04001966 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPath", fContext);
1967
Brian Salomon40b77a62017-12-22 11:25:52 -05001968 GrShape shape(path, style);
Robert Phillips20390c32018-08-17 11:01:03 -04001969
Robert Phillips27927a52018-08-20 13:18:12 -04001970 this->drawShape(clip, std::move(paint), aa, viewMatrix, shape);
Robert Phillips20390c32018-08-17 11:01:03 -04001971}
1972
1973void GrRenderTargetContext::drawShape(const GrClip& clip,
1974 GrPaint&& paint,
1975 GrAA aa,
1976 const SkMatrix& viewMatrix,
1977 const GrShape& shape) {
1978 ASSERT_SINGLE_OWNER
1979 RETURN_IF_ABANDONED
1980 SkDEBUGCODE(this->validate();)
1981 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawShape", fContext);
1982
Brian Salomon2fad74a2017-12-20 13:28:55 -05001983 if (shape.isEmpty()) {
1984 if (shape.inverseFilled()) {
1985 this->drawPaint(clip, std::move(paint), viewMatrix);
1986 }
1987 return;
robertphillipsea461502015-05-26 11:38:03 -07001988 }
1989
Robert Phillips72152832017-01-25 17:31:35 -05001990 AutoCheckFlush acf(this->drawingManager());
robertphillipsea461502015-05-26 11:38:03 -07001991
Brian Salomon2fad74a2017-12-20 13:28:55 -05001992 if (!shape.style().hasPathEffect()) {
Chris Dalton7d6748e2019-03-13 00:34:52 -06001993 GrAAType aaType = this->chooseAAType(aa);
Brian Salomon2fad74a2017-12-20 13:28:55 -05001994 SkRRect rrect;
1995 // We can ignore the starting point and direction since there is no path effect.
1996 bool inverted;
1997 if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
1998 if (rrect.isRect()) {
1999 this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(),
2000 &shape.style());
2001 return;
2002 } else if (rrect.isOval()) {
2003 this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style());
robertphillipsea461502015-05-26 11:38:03 -07002004 return;
2005 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002006 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style());
2007 return;
Robert Phillips73653b42018-08-22 12:42:42 -04002008 } else if (GrAAType::kCoverage == aaType && shape.style().isSimpleFill() &&
2009 viewMatrix.rectStaysRect()) {
2010 // TODO: the rectStaysRect restriction could be lifted if we were willing to apply
2011 // the matrix to all the points individually rather than just to the rect
2012 SkRect rects[2];
2013 if (shape.asNestedRects(rects)) {
2014 // Concave AA paths are expensive - try to avoid them for special cases
Michael Ludwig72ab3462018-12-10 12:43:36 -05002015 std::unique_ptr<GrDrawOp> op = GrStrokeRectOp::MakeNested(
Robert Phillips73653b42018-08-22 12:42:42 -04002016 fContext, std::move(paint), viewMatrix, rects);
2017 if (op) {
2018 this->addDrawOp(clip, std::move(op));
2019 }
2020 // Returning here indicates that there is nothing to draw in this case.
2021 return;
2022 }
robertphillipsea461502015-05-26 11:38:03 -07002023 }
2024 }
robertphillips4bc31812016-03-01 12:22:49 -08002025
Brian Salomon2fad74a2017-12-20 13:28:55 -05002026 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape);
robertphillipsea461502015-05-26 11:38:03 -07002027}
2028
Chris Daltonbbfd5162017-11-07 13:35:22 -07002029bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
Brian Osman11052242016-10-27 14:47:55 -04002030 const GrUserStencilSettings* ss,
2031 SkRegion::Op op,
2032 bool invert,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002033 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04002034 const SkMatrix& viewMatrix,
2035 const SkPath& path) {
robertphillips391395d2016-03-02 09:26:36 -08002036 ASSERT_SINGLE_OWNER_PRIV
2037 RETURN_FALSE_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -04002038 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04002039 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilPath",
2040 fRenderTargetContext->fContext);
robertphillips391395d2016-03-02 09:26:36 -08002041
2042 if (path.isEmpty() && path.isInverseFillType()) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002043 this->drawAndStencilRect(clip, ss, op, invert, GrAA::kNo, SkMatrix::I(),
Brian Osman11052242016-10-27 14:47:55 -04002044 SkRect::MakeIWH(fRenderTargetContext->width(),
2045 fRenderTargetContext->height()));
robertphillips391395d2016-03-02 09:26:36 -08002046 return true;
2047 }
2048
Robert Phillips72152832017-01-25 17:31:35 -05002049 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
robertphillips391395d2016-03-02 09:26:36 -08002050
2051 // An Assumption here is that path renderer would use some form of tweaking
2052 // the src color (either the input alpha or in the frag shader) to implement
2053 // aa. If we have some future driver-mojo path AA that can do the right
2054 // thing WRT to the blend then we'll need some query on the PR.
Chris Dalton09e56892019-03-13 00:22:01 -06002055 auto aaTypeFlags = choose_path_aa_type_flags(
2056 aa, fRenderTargetContext->fsaaType(), *fRenderTargetContext->caps());
robertphillips976f5f02016-06-03 10:59:20 -07002057 bool hasUserStencilSettings = !ss->isUnused();
robertphillips391395d2016-03-02 09:26:36 -08002058
Chris Daltondb91c6e2017-09-08 16:25:08 -06002059 SkIRect clipConservativeBounds;
2060 clip.getConservativeBounds(fRenderTargetContext->width(), fRenderTargetContext->height(),
2061 &clipConservativeBounds, nullptr);
2062
bsalomon8acedde2016-06-24 10:42:16 -07002063 GrShape shape(path, GrStyle::SimpleFill());
robertphillips391395d2016-03-02 09:26:36 -08002064 GrPathRenderer::CanDrawPathArgs canDrawArgs;
Brian Salomonc7fe0f72018-05-11 10:14:21 -04002065 canDrawArgs.fCaps = fRenderTargetContext->caps();
robertphillips391395d2016-03-02 09:26:36 -08002066 canDrawArgs.fViewMatrix = &viewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -07002067 canDrawArgs.fShape = &shape;
Chris Daltondb91c6e2017-09-08 16:25:08 -06002068 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
Chris Dalton09e56892019-03-13 00:22:01 -06002069 canDrawArgs.fAATypeFlags = aaTypeFlags;
Greg Danielbe7fc462019-01-03 16:40:42 -05002070 SkASSERT(!fRenderTargetContext->wrapsVkSecondaryCB());
2071 canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
cdalton93a379b2016-05-11 13:58:08 -07002072 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
robertphillips391395d2016-03-02 09:26:36 -08002073
2074 // Don't allow the SW renderer
Robert Phillips72152832017-01-25 17:31:35 -05002075 GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer(
Brian Salomon36aa1762016-12-10 13:24:02 -05002076 canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor);
robertphillips391395d2016-03-02 09:26:36 -08002077 if (!pr) {
2078 return false;
2079 }
2080
2081 GrPaint paint;
2082 paint.setCoverageSetOpXPFactory(op, invert);
2083
Brian Salomonf3569f02017-10-24 12:52:33 -04002084 GrPathRenderer::DrawPathArgs args{fRenderTargetContext->drawingManager()->getContext(),
2085 std::move(paint),
2086 ss,
2087 fRenderTargetContext,
2088 &clip,
2089 &clipConservativeBounds,
2090 &viewMatrix,
2091 &shape,
Chris Dalton09e56892019-03-13 00:22:01 -06002092 aaTypeFlags,
Brian Osman34ec3742018-07-03 10:40:57 -04002093 fRenderTargetContext->colorSpaceInfo().isLinearlyBlended()};
robertphillips391395d2016-03-02 09:26:36 -08002094 pr->drawPath(args);
2095 return true;
2096}
2097
Brian Osman11052242016-10-27 14:47:55 -04002098SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
robertphillips714712b2016-08-04 06:20:45 -07002099 ASSERT_SINGLE_OWNER_PRIV
2100
Robert Phillips6a6de562019-02-15 15:19:15 -05002101 if (fRenderTargetContext->fContext->priv().abandoned()) {
robertphillips714712b2016-08-04 06:20:45 -07002102 return SkBudgeted::kNo;
2103 }
2104
Brian Osman11052242016-10-27 14:47:55 -04002105 SkDEBUGCODE(fRenderTargetContext->validate();)
robertphillips714712b2016-08-04 06:20:45 -07002106
Robert Phillipsc7635fa2016-10-28 13:25:24 -04002107 return fRenderTargetContext->fRenderTargetProxy->isBudgeted();
robertphillips714712b2016-08-04 06:20:45 -07002108}
2109
Brian Salomon2fad74a2017-12-20 13:28:55 -05002110void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
2111 GrPaint&& paint,
2112 GrAA aa,
2113 const SkMatrix& viewMatrix,
2114 const GrShape& originalShape) {
joshualitt1de610a2016-01-06 08:26:09 -08002115 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07002116 RETURN_IF_ABANDONED
Brian Salomondcbb9d92017-07-19 10:53:20 -04002117 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext);
2118
Jim Van Verthf86073a2018-10-02 13:05:38 -04002119 if (!viewMatrix.isFinite() || !originalShape.bounds().isFinite()) {
2120 return;
2121 }
2122
Chris Daltondb91c6e2017-09-08 16:25:08 -06002123 SkIRect clipConservativeBounds;
2124 clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
2125
Brian Salomon2fad74a2017-12-20 13:28:55 -05002126 GrShape tempShape;
Chris Dalton09e56892019-03-13 00:22:01 -06002127 auto aaTypeFlags = choose_path_aa_type_flags(aa, this->fsaaType(), *this->caps());
2128
robertphillips68737822015-10-29 12:12:21 -07002129 GrPathRenderer::CanDrawPathArgs canDrawArgs;
Brian Salomonc7fe0f72018-05-11 10:14:21 -04002130 canDrawArgs.fCaps = this->caps();
robertphillips68737822015-10-29 12:12:21 -07002131 canDrawArgs.fViewMatrix = &viewMatrix;
Brian Salomon2fad74a2017-12-20 13:28:55 -05002132 canDrawArgs.fShape = &originalShape;
Chris Daltondb91c6e2017-09-08 16:25:08 -06002133 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
Greg Danielbe7fc462019-01-03 16:40:42 -05002134 canDrawArgs.fTargetIsWrappedVkSecondaryCB = this->wrapsVkSecondaryCB();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002135 canDrawArgs.fHasUserStencilSettings = false;
robertphillips68737822015-10-29 12:12:21 -07002136
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002137 GrPathRenderer* pr;
Brian Salomon82125e92016-12-10 09:35:48 -05002138 static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
Brian Salomon2fad74a2017-12-20 13:28:55 -05002139 if (originalShape.isEmpty() && !originalShape.inverseFilled()) {
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002140 return;
2141 }
2142
Chris Dalton09e56892019-03-13 00:22:01 -06002143 canDrawArgs.fAATypeFlags = aaTypeFlags;
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002144
2145 // Try a 1st time without applying any of the style to the geometry (and barring sw)
2146 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
2147 SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
2148
Brian Salomon2fad74a2017-12-20 13:28:55 -05002149 if (!pr && originalShape.style().pathEffect()) {
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002150 // It didn't work above, so try again with the path effect applied.
Brian Salomon2fad74a2017-12-20 13:28:55 -05002151 tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
2152 if (tempShape.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07002153 return;
2154 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002155 canDrawArgs.fShape = &tempShape;
Robert Phillips72152832017-01-25 17:31:35 -05002156 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002157 }
2158 if (!pr) {
Brian Salomon2fad74a2017-12-20 13:28:55 -05002159 if (canDrawArgs.fShape->style().applies()) {
2160 tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec,
2161 styleScale);
2162 if (tempShape.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07002163 return;
2164 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002165 canDrawArgs.fShape = &tempShape;
Brian Salomone7df0bb2018-05-07 14:44:57 -04002166 // This time, allow SW renderer
2167 pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
2168 } else {
2169 pr = this->drawingManager()->getSoftwarePathRenderer();
bsalomon6663acf2016-05-10 09:14:17 -07002170 }
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002171 }
robertphillipsea461502015-05-26 11:38:03 -07002172
bsalomon8acedde2016-06-24 10:42:16 -07002173 if (!pr) {
robertphillipsea461502015-05-26 11:38:03 -07002174#ifdef SK_DEBUG
2175 SkDebugf("Unable to find path renderer compatible with path.\n");
2176#endif
2177 return;
2178 }
2179
Robert Phillips256c37b2017-03-01 14:32:46 -05002180 GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
Brian Salomon82f44312017-01-11 13:42:54 -05002181 std::move(paint),
2182 &GrUserStencilSettings::kUnused,
2183 this,
2184 &clip,
Chris Daltondb91c6e2017-09-08 16:25:08 -06002185 &clipConservativeBounds,
Brian Salomon82f44312017-01-11 13:42:54 -05002186 &viewMatrix,
Brian Salomon2fad74a2017-12-20 13:28:55 -05002187 canDrawArgs.fShape,
Chris Dalton09e56892019-03-13 00:22:01 -06002188 aaTypeFlags,
Brian Osman34ec3742018-07-03 10:40:57 -04002189 this->colorSpaceInfo().isLinearlyBlended()};
bsalomon0aff2fa2015-07-31 06:48:27 -07002190 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -07002191}
2192
Brian Salomon467921e2017-03-06 16:17:12 -05002193static void op_bounds(SkRect* bounds, const GrOp* op) {
2194 *bounds = op->bounds();
2195 if (op->hasZeroArea()) {
2196 if (op->hasAABloat()) {
2197 bounds->outset(0.5f, 0.5f);
2198 } else {
2199 // We don't know which way the particular GPU will snap lines or points at integer
2200 // coords. So we ensure that the bounds is large enough for either snap.
2201 SkRect before = *bounds;
2202 bounds->roundOut(bounds);
2203 if (bounds->fLeft == before.fLeft) {
2204 bounds->fLeft -= 1;
2205 }
2206 if (bounds->fTop == before.fTop) {
2207 bounds->fTop -= 1;
2208 }
2209 if (bounds->fRight == before.fRight) {
2210 bounds->fRight += 1;
2211 }
2212 if (bounds->fBottom == before.fBottom) {
2213 bounds->fBottom += 1;
2214 }
2215 }
2216 }
2217}
2218
Brian Salomon348a0372018-10-31 10:42:18 -04002219void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op,
2220 const std::function<WillAddOpFn>& willAddFn) {
joshualitt1de610a2016-01-06 08:26:09 -08002221 ASSERT_SINGLE_OWNER
Robert Phillips69893702019-02-22 11:16:30 -05002222 if (fContext->priv().abandoned()) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002223 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002224 return;
Robert Phillipsc0138922017-03-08 11:50:55 -05002225 }
robertphillips2e1e51f2015-10-15 08:01:48 -07002226 SkDEBUGCODE(this->validate();)
Ethan Nicholas029b22c2018-10-18 16:49:56 -04002227 SkDEBUGCODE(op->fAddDrawOpCalled = true;)
Brian Salomondcbb9d92017-07-19 10:53:20 -04002228 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "addDrawOp", fContext);
robertphillips2d70dcb2015-10-06 07:38:23 -07002229
Brian Salomon467921e2017-03-06 16:17:12 -05002230 // Setup clip
2231 SkRect bounds;
2232 op_bounds(&bounds, op.get());
Brian Salomon97180af2017-03-14 13:42:58 -04002233 GrAppliedClip appliedClip;
Brian Salomon54d212e2017-03-21 14:22:38 -04002234 GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags();
2235 if (!clip.apply(fContext, this, fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA,
2236 fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil, &appliedClip,
2237 &bounds)) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002238 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002239 return;
Brian Salomon54d212e2017-03-21 14:22:38 -04002240 }
2241
Michael Ludwig6e17f1d2019-05-15 14:00:20 +00002242 if (fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil ||
2243 appliedClip.hasStencilClip()) {
2244 if (this->caps()->performStencilClearsAsDraws()) {
2245 // Must use an op to perform the clear of the stencil buffer before this op, but only
2246 // have to clear the first time any draw needs it (this also ensures we don't loop
2247 // forever when the internal stencil clear adds a draw op that has stencil settings).
2248 if (!fRenderTargetProxy->needsStencil()) {
2249 // Send false so that the stencil buffer is fully cleared to 0
Michael Ludwigc39d0c82019-01-15 10:03:43 -05002250 this->internalStencilClear(GrFixedClip::Disabled(), /* inside mask */ false);
2251 }
Michael Ludwig6e17f1d2019-05-15 14:00:20 +00002252 } else {
2253 // Just make sure the stencil buffer is cleared before the draw op, easy to do it as
2254 // a load at the start
2255 this->getRTOpList()->setStencilLoadOp(GrLoadOp::kClear);
Michael Ludwigc39d0c82019-01-15 10:03:43 -05002256 }
Robert Phillips95214472017-08-08 18:00:03 -04002257
Robert Phillips65048132017-08-10 08:44:49 -04002258 this->setNeedsStencil();
Brian Salomon54d212e2017-03-21 14:22:38 -04002259 }
2260
Brian Osman5ced0bf2019-03-15 10:15:29 -04002261 GrClampType clampType = GrPixelConfigClampType(this->colorSpaceInfo().config());
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002262 GrXferProcessor::DstProxy dstProxy;
Brian Osman5ced0bf2019-03-15 10:15:29 -04002263 GrProcessorSet::Analysis analysis = op->finalize(
2264 *this->caps(), &appliedClip, this->fsaaType(), clampType);
Chris Dalton945ee652019-01-23 09:10:36 -07002265 if (analysis.requiresDstTexture()) {
Brian Salomon09181ef2018-11-14 13:39:51 -05002266 if (!this->setupDstProxy(this->asRenderTargetProxy(), clip, *op, &dstProxy)) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002267 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002268 return;
Brian Salomon54d212e2017-03-21 14:22:38 -04002269 }
2270 }
2271
2272 op->setClippedBounds(bounds);
Brian Salomon348a0372018-10-31 10:42:18 -04002273 auto opList = this->getRTOpList();
2274 if (willAddFn) {
2275 willAddFn(op.get(), opList->uniqueID());
2276 }
Chris Dalton945ee652019-01-23 09:10:36 -07002277 opList->addDrawOp(std::move(op), analysis, std::move(appliedClip), dstProxy, *this->caps());
Brian Salomon54d212e2017-03-21 14:22:38 -04002278}
2279
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002280bool GrRenderTargetContext::setupDstProxy(GrRenderTargetProxy* rtProxy, const GrClip& clip,
Brian Salomon09181ef2018-11-14 13:39:51 -05002281 const GrOp& op,
Robert Phillips16d8ec62017-07-27 16:16:25 -04002282 GrXferProcessor::DstProxy* dstProxy) {
Greg Danielbe7fc462019-01-03 16:40:42 -05002283 // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
2284 // don't actually have a VkImage to make a copy of. Additionally we don't have the power to
2285 // start and stop the render pass in order to make the copy.
2286 if (rtProxy->wrapsVkSecondaryCB()) {
2287 return false;
2288 }
2289
Brian Salomon467921e2017-03-06 16:17:12 -05002290 if (this->caps()->textureBarrierSupport()) {
Robert Phillipsbf25d432017-04-07 10:08:53 -04002291 if (GrTextureProxy* texProxy = rtProxy->asTextureProxy()) {
Brian Salomon467921e2017-03-06 16:17:12 -05002292 // The render target is a texture, so we can read from it directly in the shader. The XP
2293 // will be responsible to detect this situation and request a texture barrier.
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002294 dstProxy->setProxy(sk_ref_sp(texProxy));
2295 dstProxy->setOffset(0, 0);
Robert Phillipsbf25d432017-04-07 10:08:53 -04002296 return true;
Brian Salomon467921e2017-03-06 16:17:12 -05002297 }
2298 }
2299
Robert Phillipsbf25d432017-04-07 10:08:53 -04002300 SkIRect copyRect = SkIRect::MakeWH(rtProxy->width(), rtProxy->height());
Brian Salomon467921e2017-03-06 16:17:12 -05002301
Eric Karl74480882017-04-03 14:49:05 -07002302 SkIRect clippedRect;
Robert Phillipsbf25d432017-04-07 10:08:53 -04002303 clip.getConservativeBounds(rtProxy->width(), rtProxy->height(), &clippedRect);
Brian Salomon09181ef2018-11-14 13:39:51 -05002304 SkRect opBounds = op.bounds();
2305 // If the op has aa bloating or is a infinitely thin geometry (hairline) outset the bounds by
2306 // 0.5 pixels.
2307 if (op.hasAABloat() || op.hasZeroArea()) {
2308 opBounds.outset(0.5f, 0.5f);
2309 // An antialiased/hairline draw can sometimes bleed outside of the clips bounds. For
2310 // performance we may ignore the clip when the draw is entirely inside the clip is float
2311 // space but will hit pixels just outside the clip when actually rasterizing.
2312 clippedRect.outset(1, 1);
2313 clippedRect.intersect(SkIRect::MakeWH(rtProxy->width(), rtProxy->height()));
2314 }
2315 SkIRect opIBounds;
2316 opBounds.roundOut(&opIBounds);
2317 if (!clippedRect.intersect(opIBounds)) {
Brian Salomon467921e2017-03-06 16:17:12 -05002318#ifdef SK_DEBUG
Robert Phillipsbf25d432017-04-07 10:08:53 -04002319 GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw.");
Brian Salomon467921e2017-03-06 16:17:12 -05002320#endif
Robert Phillipsbf25d432017-04-07 10:08:53 -04002321 return false;
Brian Salomon467921e2017-03-06 16:17:12 -05002322 }
2323
2324 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
2325 // have per-sample dst values by making the copy multisampled.
2326 GrSurfaceDesc desc;
Eric Karl74480882017-04-03 14:49:05 -07002327 bool rectsMustMatch = false;
2328 bool disallowSubrect = false;
Brian Salomon2a4f9832018-03-03 22:43:43 -05002329 GrSurfaceOrigin origin;
2330 if (!this->caps()->initDescForDstCopy(rtProxy, &desc, &origin, &rectsMustMatch,
2331 &disallowSubrect)) {
Brian Salomon467921e2017-03-06 16:17:12 -05002332 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillipsbf25d432017-04-07 10:08:53 -04002333 desc.fConfig = rtProxy->config();
Greg Daniel1efe3222018-04-04 14:02:51 -04002334 origin = rtProxy->origin();
Brian Salomon467921e2017-03-06 16:17:12 -05002335 }
2336
Eric Karl74480882017-04-03 14:49:05 -07002337 if (!disallowSubrect) {
2338 copyRect = clippedRect;
2339 }
Brian Salomon467921e2017-03-06 16:17:12 -05002340
Robert Phillipsbf25d432017-04-07 10:08:53 -04002341 SkIPoint dstPoint, dstOffset;
2342 SkBackingFit fit;
Eric Karl74480882017-04-03 14:49:05 -07002343 if (rectsMustMatch) {
Robert Phillipsbf25d432017-04-07 10:08:53 -04002344 desc.fWidth = rtProxy->width();
2345 desc.fHeight = rtProxy->height();
Eric Karl74480882017-04-03 14:49:05 -07002346 dstPoint = {copyRect.fLeft, copyRect.fTop};
2347 dstOffset = {0, 0};
Robert Phillipsbf25d432017-04-07 10:08:53 -04002348 fit = SkBackingFit::kExact;
Eric Karl74480882017-04-03 14:49:05 -07002349 } else {
2350 desc.fWidth = copyRect.width();
2351 desc.fHeight = copyRect.height();
2352 dstPoint = {0, 0};
2353 dstOffset = {copyRect.fLeft, copyRect.fTop};
Robert Phillipsbf25d432017-04-07 10:08:53 -04002354 fit = SkBackingFit::kApprox;
Eric Karl74480882017-04-03 14:49:05 -07002355 }
Brian Salomon467921e2017-03-06 16:17:12 -05002356
Greg Daniel4065d452018-11-16 15:43:41 -05002357 SkASSERT(rtProxy->backendFormat().textureType() == GrTextureType::k2D);
2358 const GrBackendFormat& format = rtProxy->backendFormat();
Robert Phillips9da87e02019-02-04 13:26:26 -05002359 sk_sp<GrSurfaceContext> sContext = fContext->priv().makeDeferredSurfaceContext(
Greg Daniel4065d452018-11-16 15:43:41 -05002360 format, desc, origin, GrMipMapped::kNo, fit, SkBudgeted::kYes,
Brian Salomonf802e752018-02-13 17:13:31 -05002361 sk_ref_sp(this->colorSpaceInfo().colorSpace()));
Robert Phillipsbf25d432017-04-07 10:08:53 -04002362 if (!sContext) {
2363 SkDebugf("setupDstTexture: surfaceContext creation failed.\n");
2364 return false;
2365 }
2366
2367 if (!sContext->copy(rtProxy, copyRect, dstPoint)) {
2368 SkDebugf("setupDstTexture: copy failed.\n");
2369 return false;
2370 }
2371
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002372 dstProxy->setProxy(sContext->asTextureProxyRef());
2373 dstProxy->setOffset(dstOffset);
Robert Phillipsbf25d432017-04-07 10:08:53 -04002374 return true;
robertphillips2334fb62015-06-17 05:43:33 -07002375}