blob: 6b77d30bc6c67bb6c9bd4360c595c0e0c46a9209 [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
Brian Salomon031b0ba2019-05-23 11:05:26 -04008#include "src/gpu/GrRenderTargetContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "include/core/SkDrawable.h"
10#include "include/gpu/GrBackendSemaphore.h"
11#include "include/gpu/GrRenderTarget.h"
12#include "include/private/GrAuditTrail.h"
13#include "include/private/GrColor.h"
14#include "include/private/GrOpList.h"
15#include "include/private/GrRecordingContext.h"
16#include "include/private/SkShadowFlags.h"
17#include "include/utils/SkShadowUtils.h"
Brian Salomoncd734f62019-05-10 16:32:54 -040018#include "src/core/SkAutoPixmapStorage.h"
19#include "src/core/SkConvertPixels.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/core/SkDrawShadowInfo.h"
21#include "src/core/SkGlyphRunPainter.h"
22#include "src/core/SkLatticeIter.h"
23#include "src/core/SkMatrixPriv.h"
24#include "src/core/SkRRectPriv.h"
25#include "src/core/SkSurfacePriv.h"
26#include "src/gpu/GrAppliedClip.h"
27#include "src/gpu/GrBlurUtils.h"
28#include "src/gpu/GrCaps.h"
29#include "src/gpu/GrContextPriv.h"
30#include "src/gpu/GrDrawingManager.h"
31#include "src/gpu/GrFixedClip.h"
32#include "src/gpu/GrGpuResourcePriv.h"
33#include "src/gpu/GrMemoryPool.h"
34#include "src/gpu/GrPathRenderer.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050035#include "src/gpu/GrRecordingContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050036#include "src/gpu/GrRenderTargetContextPriv.h"
37#include "src/gpu/GrResourceProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050038#include "src/gpu/GrStencilAttachment.h"
39#include "src/gpu/GrStyle.h"
40#include "src/gpu/GrTracing.h"
41#include "src/gpu/SkGr.h"
Brian Salomon031b0ba2019-05-23 11:05:26 -040042#include "src/gpu/effects/GrBicubicEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050043#include "src/gpu/effects/GrRRectEffect.h"
44#include "src/gpu/effects/GrTextureDomain.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040045#include "src/gpu/geometry/GrQuad.h"
Michael Ludwig663afe52019-06-03 16:46:19 -040046#include "src/gpu/geometry/GrShape.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050047#include "src/gpu/ops/GrAtlasTextOp.h"
48#include "src/gpu/ops/GrClearOp.h"
49#include "src/gpu/ops/GrClearStencilClipOp.h"
50#include "src/gpu/ops/GrDebugMarkerOp.h"
51#include "src/gpu/ops/GrDrawAtlasOp.h"
52#include "src/gpu/ops/GrDrawOp.h"
53#include "src/gpu/ops/GrDrawVerticesOp.h"
54#include "src/gpu/ops/GrDrawableOp.h"
55#include "src/gpu/ops/GrFillRRectOp.h"
56#include "src/gpu/ops/GrFillRectOp.h"
57#include "src/gpu/ops/GrLatticeOp.h"
58#include "src/gpu/ops/GrOp.h"
59#include "src/gpu/ops/GrOvalOpFactory.h"
60#include "src/gpu/ops/GrRegionOp.h"
61#include "src/gpu/ops/GrSemaphoreOp.h"
62#include "src/gpu/ops/GrShadowRRectOp.h"
63#include "src/gpu/ops/GrStencilPathOp.h"
64#include "src/gpu/ops/GrStrokeRectOp.h"
65#include "src/gpu/ops/GrTextureOp.h"
Brian Salomonab32f652019-05-10 14:24:50 -040066#include "src/gpu/ops/GrTransferFromOp.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050067#include "src/gpu/text/GrTextContext.h"
68#include "src/gpu/text/GrTextTarget.h"
Brian Salomonf18b1d82017-10-27 11:30:49 -040069
Herb Derbyc1b482c2018-08-09 15:02:27 -040070class GrRenderTargetContext::TextTarget : public GrTextTarget {
Brian Salomonf18b1d82017-10-27 11:30:49 -040071public:
72 TextTarget(GrRenderTargetContext* renderTargetContext)
Herb Derbyc1b482c2018-08-09 15:02:27 -040073 : GrTextTarget(renderTargetContext->width(), renderTargetContext->height(),
Robert Phillips7e90be92019-02-15 12:22:59 -050074 renderTargetContext->colorSpaceInfo())
Herb Derby74c6ed32018-07-28 18:07:54 -040075 , fRenderTargetContext(renderTargetContext)
Herb Derby65956872018-08-21 16:55:04 -040076 , fGlyphPainter{*renderTargetContext}{}
Brian Salomonf18b1d82017-10-27 11:30:49 -040077
Robert Phillips7c525e62018-06-12 10:11:12 -040078 void addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) override {
Brian Salomonf18b1d82017-10-27 11:30:49 -040079 fRenderTargetContext->addDrawOp(clip, std::move(op));
80 }
81
Robert Phillips46a13382018-08-23 13:53:01 -040082 void drawShape(const GrClip& clip, const SkPaint& paint,
83 const SkMatrix& viewMatrix, const GrShape& shape) override {
Robert Phillips27927a52018-08-20 13:18:12 -040084 GrBlurUtils::drawShapeWithMaskFilter(fRenderTargetContext->fContext, fRenderTargetContext,
85 clip, paint, viewMatrix, shape);
Brian Salomonf18b1d82017-10-27 11:30:49 -040086 }
87
88 void makeGrPaint(GrMaskFormat maskFormat, const SkPaint& skPaint, const SkMatrix& viewMatrix,
Robert Phillips7c525e62018-06-12 10:11:12 -040089 GrPaint* grPaint) override {
Robert Phillips69893702019-02-22 11:16:30 -050090 auto context = fRenderTargetContext->fContext;
Brian Salomonf18b1d82017-10-27 11:30:49 -040091 const GrColorSpaceInfo& colorSpaceInfo = fRenderTargetContext->colorSpaceInfo();
92 if (kARGB_GrMaskFormat == maskFormat) {
93 SkPaintToGrPaintWithPrimitiveColor(context, colorSpaceInfo, skPaint, grPaint);
94 } else {
95 SkPaintToGrPaint(context, colorSpaceInfo, skPaint, viewMatrix, grPaint);
96 }
97 }
98
Robert Phillips69893702019-02-22 11:16:30 -050099 GrRecordingContext* getContext() override {
Robert Phillips7c525e62018-06-12 10:11:12 -0400100 return fRenderTargetContext->fContext;
101 }
102
Herb Derby65956872018-08-21 16:55:04 -0400103 SkGlyphRunListPainter* glyphPainter() override {
104 return &fGlyphPainter;
Herb Derby74c6ed32018-07-28 18:07:54 -0400105 }
106
Brian Salomonf18b1d82017-10-27 11:30:49 -0400107private:
108 GrRenderTargetContext* fRenderTargetContext;
Herb Derby65956872018-08-21 16:55:04 -0400109 SkGlyphRunListPainter fGlyphPainter;
Herb Derby74c6ed32018-07-28 18:07:54 -0400110
Brian Salomonf18b1d82017-10-27 11:30:49 -0400111};
joshualittbc907352016-01-13 06:45:40 -0800112
Robert Phillips72152832017-01-25 17:31:35 -0500113#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
joshualitt1de610a2016-01-06 08:26:09 -0800114#define ASSERT_SINGLE_OWNER \
Robert Phillipsa90aa2b2017-04-10 08:19:26 -0400115 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
robertphillips391395d2016-03-02 09:26:36 -0800116#define ASSERT_SINGLE_OWNER_PRIV \
Robert Phillipsa90aa2b2017-04-10 08:19:26 -0400117 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
Robert Phillips69893702019-02-22 11:16:30 -0500118#define RETURN_IF_ABANDONED if (fContext->priv().abandoned()) { return; }
119#define RETURN_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return; }
120#define RETURN_FALSE_IF_ABANDONED if (fContext->priv().abandoned()) { return false; }
121#define RETURN_FALSE_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return false; }
122#define RETURN_NULL_IF_ABANDONED if (fContext->priv().abandoned()) { return nullptr; }
robertphillipsea461502015-05-26 11:38:03 -0700123
Brian Salomone225b562017-06-14 13:00:03 -0400124//////////////////////////////////////////////////////////////////////////////
125
robertphillipsea461502015-05-26 11:38:03 -0700126class AutoCheckFlush {
127public:
halcanary9d524f22016-03-29 09:03:52 -0700128 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
robertphillips77a2e522015-10-17 07:43:27 -0700129 SkASSERT(fDrawingManager);
130 }
bsalomonb77a9072016-09-07 10:02:04 -0700131 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
robertphillipsea461502015-05-26 11:38:03 -0700132
133private:
robertphillips77a2e522015-10-17 07:43:27 -0700134 GrDrawingManager* fDrawingManager;
robertphillipsea461502015-05-26 11:38:03 -0700135};
136
Robert Phillipsf2361d22016-10-25 14:20:06 -0400137// In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress
Brian Osman11052242016-10-27 14:47:55 -0400138// GrOpLists to be picked up and added to by renderTargetContexts lower in the call
Robert Phillipsf2361d22016-10-25 14:20:06 -0400139// stack. When this occurs with a closed GrOpList, a new one will be allocated
Brian Osman11052242016-10-27 14:47:55 -0400140// when the renderTargetContext attempts to use it (via getOpList).
Robert Phillips69893702019-02-22 11:16:30 -0500141GrRenderTargetContext::GrRenderTargetContext(GrRecordingContext* context,
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400142 sk_sp<GrRenderTargetProxy> rtp,
Brian Osman11052242016-10-27 14:47:55 -0400143 sk_sp<SkColorSpace> colorSpace,
144 const SkSurfaceProps* surfaceProps,
Robert Phillips941d1442017-06-14 16:37:02 -0400145 bool managedOpList)
Robert Phillips0d075de2019-03-04 11:08:13 -0500146 : GrSurfaceContext(context, rtp->config(), std::move(colorSpace))
Brian Salomonf3569f02017-10-24 12:52:33 -0400147 , fRenderTargetProxy(std::move(rtp))
148 , fOpList(sk_ref_sp(fRenderTargetProxy->getLastRenderTargetOpList()))
Brian Salomonf3569f02017-10-24 12:52:33 -0400149 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
150 , fManagedOpList(managedOpList) {
Brian Salomonf18b1d82017-10-27 11:30:49 -0400151 fTextTarget.reset(new TextTarget(this));
robertphillips2e1e51f2015-10-15 08:01:48 -0700152 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -0700153}
154
robertphillips2e1e51f2015-10-15 08:01:48 -0700155#ifdef SK_DEBUG
Brian Osman11052242016-10-27 14:47:55 -0400156void GrRenderTargetContext::validate() const {
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400157 SkASSERT(fRenderTargetProxy);
158 fRenderTargetProxy->validate(fContext);
robertphillipsa106c622015-10-16 09:07:06 -0700159
Robert Phillipsf2361d22016-10-25 14:20:06 -0400160 if (fOpList && !fOpList->isClosed()) {
Robert Phillipsdc83b892017-04-13 12:23:54 -0400161 SkASSERT(fRenderTargetProxy->getLastOpList() == fOpList.get());
robertphillipsa106c622015-10-16 09:07:06 -0700162 }
robertphillips2e1e51f2015-10-15 08:01:48 -0700163}
164#endif
165
Brian Osman11052242016-10-27 14:47:55 -0400166GrRenderTargetContext::~GrRenderTargetContext() {
joshualitt1de610a2016-01-06 08:26:09 -0800167 ASSERT_SINGLE_OWNER
robertphillipsa106c622015-10-16 09:07:06 -0700168}
169
Chris Dalton7d6748e2019-03-13 00:34:52 -0600170inline GrAAType GrRenderTargetContext::chooseAAType(GrAA aa) {
171 auto fsaaType = this->fsaaType();
172 if (GrAA::kNo == aa) {
173 // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
174 // that.
175 if (fsaaType == GrFSAAType::kUnifiedMSAA && !this->caps()->multisampleDisableSupport()) {
176 return GrAAType::kMSAA;
177 }
178 return GrAAType::kNone;
179 }
180 switch (fsaaType) {
181 case GrFSAAType::kNone:
182 case GrFSAAType::kMixedSamples:
183 return GrAAType::kCoverage;
184 case GrFSAAType::kUnifiedMSAA:
185 return GrAAType::kMSAA;
186 }
187 SK_ABORT("Unexpected fsaa type");
188 return GrAAType::kNone;
189}
190
191static inline GrPathRenderer::AATypeFlags choose_path_aa_type_flags(
192 GrAA aa, GrFSAAType fsaaType, const GrCaps& caps) {
193 using AATypeFlags = GrPathRenderer::AATypeFlags;
194 if (GrAA::kNo == aa) {
195 // On some devices we cannot disable MSAA if it is enabled so we make the AA type flags
196 // reflect that.
197 if (fsaaType == GrFSAAType::kUnifiedMSAA && !caps.multisampleDisableSupport()) {
198 return AATypeFlags::kMSAA;
199 }
200 return AATypeFlags::kNone;
201 }
202 switch (fsaaType) {
203 case GrFSAAType::kNone:
204 return AATypeFlags::kCoverage;
205 case GrFSAAType::kMixedSamples:
206 return AATypeFlags::kCoverage | AATypeFlags::kMixedSampledStencilThenCover;
207 case GrFSAAType::kUnifiedMSAA:
208 return AATypeFlags::kMSAA;
209 }
210 SK_ABORT("Invalid GrFSAAType.");
211 return AATypeFlags::kNone;
212}
213
Robert Phillipsf200a902017-01-30 13:27:37 -0500214GrTextureProxy* GrRenderTargetContext::asTextureProxy() {
Robert Phillipseaa86252016-11-08 13:49:39 +0000215 return fRenderTargetProxy->asTextureProxy();
216}
217
Greg Daniele252f082017-10-23 16:05:23 -0400218const GrTextureProxy* GrRenderTargetContext::asTextureProxy() const {
219 return fRenderTargetProxy->asTextureProxy();
220}
221
Robert Phillipsf200a902017-01-30 13:27:37 -0500222sk_sp<GrTextureProxy> GrRenderTargetContext::asTextureProxyRef() {
223 return sk_ref_sp(fRenderTargetProxy->asTextureProxy());
224}
225
Greg Daniele252f082017-10-23 16:05:23 -0400226GrMipMapped GrRenderTargetContext::mipMapped() const {
227 if (const GrTextureProxy* proxy = this->asTextureProxy()) {
228 return proxy->mipMapped();
229 }
230 return GrMipMapped::kNo;
231}
232
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400233GrRenderTargetOpList* GrRenderTargetContext::getRTOpList() {
joshualitt1de610a2016-01-06 08:26:09 -0800234 ASSERT_SINGLE_OWNER
robertphillipsa106c622015-10-16 09:07:06 -0700235 SkDEBUGCODE(this->validate();)
236
Robert Phillipsf2361d22016-10-25 14:20:06 -0400237 if (!fOpList || fOpList->isClosed()) {
Michael Ludwig6e17f1d2019-05-15 14:00:20 +0000238 fOpList = this->drawingManager()->newRTOpList(fRenderTargetProxy, fManagedOpList);
robertphillipsa106c622015-10-16 09:07:06 -0700239 }
240
Robert Phillipsdc83b892017-04-13 12:23:54 -0400241 return fOpList.get();
robertphillipsa106c622015-10-16 09:07:06 -0700242}
243
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400244GrOpList* GrRenderTargetContext::getOpList() {
245 return this->getRTOpList();
robertphillipsea461502015-05-26 11:38:03 -0700246}
247
Herb Derbycddab252018-07-16 11:19:04 -0400248void GrRenderTargetContext::drawGlyphRunList(
249 const GrClip& clip, const SkMatrix& viewMatrix,
Robert Phillipse4643cc2018-08-14 13:01:29 -0400250 const SkGlyphRunList& blob) {
joshualitt1de610a2016-01-06 08:26:09 -0800251 ASSERT_SINGLE_OWNER
robertphillips2d70dcb2015-10-06 07:38:23 -0700252 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700253 SkDEBUGCODE(this->validate();)
Herb Derbycddab252018-07-16 11:19:04 -0400254 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawGlyphRunList", fContext);
robertphillips2d70dcb2015-10-06 07:38:23 -0700255
Greg Danielbe7fc462019-01-03 16:40:42 -0500256 // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
257 // secondary command buffers because it would require stopping and starting a render pass which
258 // we don't have access to.
259 if (this->wrapsVkSecondaryCB()) {
260 return;
261 }
262
Herb Derby26cbe512018-05-24 14:39:01 -0400263 GrTextContext* atlasTextContext = this->drawingManager()->getTextContext();
Herb Derbycddab252018-07-16 11:19:04 -0400264 atlasTextContext->drawGlyphRunList(fContext, fTextTarget.get(), clip, viewMatrix,
Robert Phillipse4643cc2018-08-14 13:01:29 -0400265 fSurfaceProps, blob);
robertphillipsea461502015-05-26 11:38:03 -0700266}
267
Brian Osman11052242016-10-27 14:47:55 -0400268void GrRenderTargetContext::discard() {
joshualitt1de610a2016-01-06 08:26:09 -0800269 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700270 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700271 SkDEBUGCODE(this->validate();)
Robert Phillips6b47c7d2017-08-29 07:24:09 -0400272 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -0700273
Robert Phillips72152832017-01-25 17:31:35 -0500274 AutoCheckFlush acf(this->drawingManager());
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400275
Robert Phillips380b90c2017-08-30 07:41:07 -0400276 this->getRTOpList()->discard();
robertphillipsea461502015-05-26 11:38:03 -0700277}
278
Brian Osman11052242016-10-27 14:47:55 -0400279void GrRenderTargetContext::clear(const SkIRect* rect,
Brian Osman9a9baae2018-11-05 15:06:26 -0500280 const SkPMColor4f& color,
Chris Dalton344e9032017-12-11 15:42:09 -0700281 CanClearFullscreen canClearFullscreen) {
joshualitt1de610a2016-01-06 08:26:09 -0800282 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700283 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700284 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400285 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext);
robertphillipsea461502015-05-26 11:38:03 -0700286
Robert Phillips72152832017-01-25 17:31:35 -0500287 AutoCheckFlush acf(this->drawingManager());
Chris Dalton344e9032017-12-11 15:42:09 -0700288 this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color,
289 canClearFullscreen);
csmartdalton29df7602016-08-31 11:55:52 -0700290}
robertphillips9199a9f2016-07-13 07:48:43 -0700291
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500292void GrRenderTargetContextPriv::clear(const GrFixedClip& clip,
293 const SkPMColor4f& color,
294 CanClearFullscreen canClearFullscreen) {
295 ASSERT_SINGLE_OWNER_PRIV
296 RETURN_IF_ABANDONED_PRIV
297 SkDEBUGCODE(fRenderTargetContext->validate();)
298 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clear",
299 fRenderTargetContext->fContext);
300
301 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
302 fRenderTargetContext->internalClear(clip, color, canClearFullscreen);
303}
304
305static void clear_to_grpaint(const SkPMColor4f& color, GrPaint* paint) {
306 paint->setColor4f(color);
307 if (color.isOpaque()) {
308 // Can just rely on the src-over blend mode to do the right thing
309 paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
310 } else {
311 // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
312 // were src blended
313 paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
314 }
315}
316
317void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
318 const SkPMColor4f& color,
319 CanClearFullscreen canClearFullscreen) {
320 bool isFull = false;
321 if (!clip.hasWindowRectangles()) {
Robert Phillips0e35ce22019-04-05 10:57:28 -0400322 // TODO: wrt the shouldInitializeTextures path, it would be more performant to
323 // only clear the entire target if we knew it had not been cleared before. As
324 // is this could end up doing a lot of redundant clears.
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500325 isFull = !clip.scissorEnabled() ||
326 (CanClearFullscreen::kYes == canClearFullscreen &&
Robert Phillips0e35ce22019-04-05 10:57:28 -0400327 (this->caps()->preferFullscreenClears() || this->caps()->shouldInitializeTextures())) ||
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500328 clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
329 }
330
331 if (isFull) {
332 if (this->getRTOpList()->resetForFullscreenClear() &&
333 !this->caps()->performColorClearsAsDraws()) {
334 // The op list was emptied and native clears are allowed, so just use the load op
335 this->getRTOpList()->setColorLoadOp(GrLoadOp::kClear, color);
336 return;
337 } else {
338 // Will use an op for the clear, reset the load op to discard since the op will
339 // blow away the color buffer contents
340 this->getRTOpList()->setColorLoadOp(GrLoadOp::kDiscard);
341 }
342
343 // Must add an op to the list (either because we couldn't use a load op, or because the
344 // clear load op isn't supported)
345 if (this->caps()->performColorClearsAsDraws()) {
346 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
347 GrPaint paint;
348 clear_to_grpaint(color, &paint);
349 this->addDrawOp(GrFixedClip::Disabled(),
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400350 GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
351 rtRect));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500352 } else {
353 this->getRTOpList()->addOp(GrClearOp::Make(fContext, SkIRect::MakeEmpty(), color,
354 /* fullscreen */ true), *this->caps());
355 }
356 } else {
357 if (this->caps()->performPartialClearsAsDraws()) {
358 // performPartialClearsAsDraws() also returns true if any clear has to be a draw.
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500359 GrPaint paint;
360 clear_to_grpaint(color, &paint);
361
Michael Ludwig64b28a72019-05-28 12:02:00 -0400362 this->addDrawOp(clip,
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400363 GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
364 SkRect::Make(clip.scissorRect())));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500365 } else {
366 std::unique_ptr<GrOp> op(GrClearOp::Make(fContext, clip, color,
367 this->asSurfaceProxy()));
368 // This version of the clear op factory can return null if the clip doesn't intersect
369 // with the surface proxy's boundary
370 if (!op) {
371 return;
372 }
373 this->getRTOpList()->addOp(std::move(op), *this->caps());
374 }
375 }
376}
377
Brian Osman9a9baae2018-11-05 15:06:26 -0500378void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const SkPMColor4f& color) {
Robert Phillips784b7bf2016-12-09 13:35:02 -0500379 ASSERT_SINGLE_OWNER_PRIV
380 RETURN_IF_ABANDONED_PRIV
381 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400382 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "absClear",
383 fRenderTargetContext->fContext);
Robert Phillips784b7bf2016-12-09 13:35:02 -0500384
Robert Phillips72152832017-01-25 17:31:35 -0500385 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
Robert Phillips784b7bf2016-12-09 13:35:02 -0500386
Brian Salomonbb5711a2017-05-17 13:49:59 -0400387 SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth(),
388 fRenderTargetContext->fRenderTargetProxy->worstCaseHeight());
Robert Phillips784b7bf2016-12-09 13:35:02 -0500389
390 if (clearRect) {
391 if (clearRect->contains(rtRect)) {
392 clearRect = nullptr; // full screen
393 } else {
394 if (!rtRect.intersect(*clearRect)) {
395 return;
396 }
397 }
398 }
399
400 // TODO: in a post-MDB world this should be handled at the OpList level.
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500401 // This makes sure to always add an op to the list, instead of marking the clear as a load op.
402 // This code follows very similar logic to internalClear() below, but critical differences are
403 // highlighted in line related to absClear()'s unique behavior.
404 if (clearRect) {
405 if (fRenderTargetContext->caps()->performPartialClearsAsDraws()) {
Ethan Nicholas56d19a52018-10-15 11:26:20 -0400406 GrPaint paint;
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500407 clear_to_grpaint(color, &paint);
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400408
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500409 // Use the disabled clip; the rect geometry already matches the clear rectangle and
410 // if it were added to a scissor, that would be intersected with the logical surface
411 // bounds and not the worst case dimensions required here.
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400412 fRenderTargetContext->addDrawOp(
413 GrFixedClip::Disabled(),
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400414 GrFillRectOp::MakeNonAARect(fRenderTargetContext->fContext, std::move(paint),
415 SkMatrix::I(), SkRect::Make(rtRect)));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500416 } else {
417 // Must use the ClearOp factory that takes a boolean (false) instead of a surface
418 // proxy. The surface proxy variant would intersect the clip rect with its logical
419 // bounds, which is not desired in this special case.
420 fRenderTargetContext->getRTOpList()->addOp(
421 GrClearOp::Make(fRenderTargetContext->fContext, rtRect, color,
422 /* fullscreen */ false),
423 *fRenderTargetContext->caps());
csmartdalton29df7602016-08-31 11:55:52 -0700424 }
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500425 } else {
426 // Reset the oplist like in internalClear(), but do not rely on a load op for the clear
427 fRenderTargetContext->getRTOpList()->resetForFullscreenClear();
428 fRenderTargetContext->getRTOpList()->setColorLoadOp(GrLoadOp::kDiscard);
429
430 if (fRenderTargetContext->caps()->performColorClearsAsDraws()) {
431 // This draws a quad covering the worst case dimensions instead of just the logical
432 // width and height like in internalClear().
433 GrPaint paint;
434 clear_to_grpaint(color, &paint);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400435 fRenderTargetContext->addDrawOp(
436 GrFixedClip::Disabled(),
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400437 GrFillRectOp::MakeNonAARect(fRenderTargetContext->fContext, std::move(paint),
438 SkMatrix::I(), SkRect::Make(rtRect)));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500439 } else {
440 // Nothing special about this path in absClear compared to internalClear()
441 fRenderTargetContext->getRTOpList()->addOp(
442 GrClearOp::Make(fRenderTargetContext->fContext, SkIRect::MakeEmpty(), color,
443 /* fullscreen */ true),
444 *fRenderTargetContext->caps());
Ethan Nicholas56d19a52018-10-15 11:26:20 -0400445 }
robertphillips9199a9f2016-07-13 07:48:43 -0700446 }
robertphillipsea461502015-05-26 11:38:03 -0700447}
448
Brian Osman11052242016-10-27 14:47:55 -0400449void GrRenderTargetContext::drawPaint(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500450 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -0400451 const SkMatrix& viewMatrix) {
joshualitt1de610a2016-01-06 08:26:09 -0800452 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700453 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700454 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400455 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPaint", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -0700456
robertphillipsea461502015-05-26 11:38:03 -0700457 // set rect to be big enough to fill the space, but not super-huge, so we
458 // don't overflow fixed-point implementations
robertphillips13a7eee2016-08-31 15:06:24 -0700459
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400460 SkRect r = fRenderTargetProxy->getBoundsRect();
robertphillipsea461502015-05-26 11:38:03 -0700461
Michael Ludwig61a16512019-01-15 11:15:13 -0500462 // Check if we can optimize a clipped drawPaint(). We only do the transformation when there are
463 // no fragment processors because they may depend on having correct local coords and this path
464 // draws in device space without a local matrix. It currently handles converting clipRRect()
465 // to drawRRect() and solid colors to screen-filling drawRects() (which are then converted into
466 // clears if possible in drawRect).
Michael Ludwig3d6390e2018-10-09 11:45:16 -0400467 if (!paint.numTotalFragmentProcessors()) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500468 SkRRect rrect;
469 GrAA aa = GrAA::kNo;
470 if (clip.isRRect(r, &rrect, &aa)) {
471 if (rrect.isRect()) {
472 // Use drawFilledRect() with no clip and the reduced rectangle
473 this->drawFilledRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect.rect());
474 } else {
475 // Use drawRRect() with no clip
476 this->drawRRect(GrNoClip(), std::move(paint), aa, SkMatrix::I(), rrect,
477 GrStyle::SimpleFill());
478 }
479 } else {
480 // Use drawFilledRect() with no view matrix to draw a fullscreen quad, but preserve
481 // the clip. Since the paint has no FPs we can drop the view matrix without worrying
482 // about local coordinates. If the clip is simple, drawFilledRect() will turn this into
483 // a clear or a scissored clear.
484 this->drawFilledRect(clip, std::move(paint), aa, SkMatrix::I(), r);
Michael Ludwig3d6390e2018-10-09 11:45:16 -0400485 }
Michael Ludwig61a16512019-01-15 11:15:13 -0500486 return;
bsalomoncb31e512016-08-26 10:48:19 -0700487 }
488
Michael Ludwig61a16512019-01-15 11:15:13 -0500489 // Since the paint is not trivial, there's no way at this point drawRect() could have converted
490 // this drawPaint() into an optimized clear. drawRect() would then use GrFillRectOp without
491 // a local matrix, so we can simplify things and use the local matrix variant to draw a screen
492 // filling rect with the inverse view matrix for local coords, which works for all matrix
493 // conditions.
494 SkMatrix localMatrix;
495 if (!viewMatrix.invert(&localMatrix)) {
496 return;
robertphillipsea461502015-05-26 11:38:03 -0700497 }
Michael Ludwig61a16512019-01-15 11:15:13 -0500498
499 AutoCheckFlush acf(this->drawingManager());
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400500 std::unique_ptr<GrDrawOp> op = GrFillRectOp::Make(
Michael Ludwig64b28a72019-05-28 12:02:00 -0400501 fContext, std::move(paint), GrAAType::kNone, GrQuadAAFlags::kNone,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400502 GrQuad(r), GrQuad::MakeFromRect(r, localMatrix));
Michael Ludwig61a16512019-01-15 11:15:13 -0500503 this->addDrawOp(clip, std::move(op));
robertphillipsea461502015-05-26 11:38:03 -0700504}
505
robertphillipsea461502015-05-26 11:38:03 -0700506static inline bool rect_contains_inclusive(const SkRect& rect, const SkPoint& point) {
507 return point.fX >= rect.fLeft && point.fX <= rect.fRight &&
508 point.fY >= rect.fTop && point.fY <= rect.fBottom;
509}
510
csmartdalton97f6cd52016-07-13 13:37:08 -0700511// Attempts to crop a rect and optional local rect to the clip boundaries.
512// Returns false if the draw can be skipped entirely.
robertphillips13a7eee2016-08-31 15:06:24 -0700513static bool crop_filled_rect(int width, int height, const GrClip& clip,
csmartdalton97f6cd52016-07-13 13:37:08 -0700514 const SkMatrix& viewMatrix, SkRect* rect,
515 SkRect* localRect = nullptr) {
516 if (!viewMatrix.rectStaysRect()) {
517 return true;
518 }
519
csmartdalton97f6cd52016-07-13 13:37:08 -0700520 SkIRect clipDevBounds;
521 SkRect clipBounds;
csmartdalton97f6cd52016-07-13 13:37:08 -0700522
robertphillips13a7eee2016-08-31 15:06:24 -0700523 clip.getConservativeBounds(width, height, &clipDevBounds);
reeda39667c2016-08-22 06:39:49 -0700524 if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) {
525 return false;
526 }
csmartdalton97f6cd52016-07-13 13:37:08 -0700527
528 if (localRect) {
529 if (!rect->intersects(clipBounds)) {
530 return false;
531 }
Michael Ludwig904657d2019-04-12 10:57:24 -0400532 // localRect is force-sorted after clipping, so this is a sanity check to make sure callers
533 // aren't intentionally using inverted local rectangles.
534 SkASSERT(localRect->isSorted());
csmartdalton97f6cd52016-07-13 13:37:08 -0700535 const SkScalar dx = localRect->width() / rect->width();
536 const SkScalar dy = localRect->height() / rect->height();
537 if (clipBounds.fLeft > rect->fLeft) {
538 localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx;
539 rect->fLeft = clipBounds.fLeft;
540 }
541 if (clipBounds.fTop > rect->fTop) {
542 localRect->fTop += (clipBounds.fTop - rect->fTop) * dy;
543 rect->fTop = clipBounds.fTop;
544 }
545 if (clipBounds.fRight < rect->fRight) {
546 localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx;
547 rect->fRight = clipBounds.fRight;
548 }
549 if (clipBounds.fBottom < rect->fBottom) {
550 localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy;
551 rect->fBottom = clipBounds.fBottom;
552 }
Michael Ludwig904657d2019-04-12 10:57:24 -0400553 // Ensure local coordinates remain sorted after clipping. If the original dstRect was very
554 // large, numeric precision can invert the localRect
555 localRect->sort();
csmartdalton97f6cd52016-07-13 13:37:08 -0700556 return true;
557 }
558
559 return rect->intersect(clipBounds);
560}
561
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400562GrQuadAAFlags set_edge_flag(GrQuadAAFlags currentFlags, GrQuadAAFlags edge, GrAA edgeState) {
563 if (edgeState == GrAA::kNo) {
564 // Turn off 'edge' in currentFlags
565 return currentFlags & (~edge);
566 } else {
567 // Turn on 'edge' in currentFlags
568 return currentFlags | edge;
569 }
570}
571
Michael Ludwig61a16512019-01-15 11:15:13 -0500572bool GrRenderTargetContext::drawFilledRectAsClear(const GrClip& clip, GrPaint&& paint, GrAA aa,
573 const SkMatrix& viewMatrix, const SkRect& rect) {
574 // Rules for a filled rect to become a clear [+scissor]:
575 // 1. The paint is a constant blend color with no other FPs
576 // 2. The view matrix maps rectangles to rectangles, or the transformed quad fully covers
577 // the render target (or clear region in #3).
578 // 3. The clip is an intersection of rectangles, so the clear region will be the
579 // intersection of the clip and the provided rect.
580 // 4. The clear region aligns with pixel bounds
581 // 5. There are no user stencil settings (and since the clip was IOR, the clip won't need
582 // to use the stencil either).
583 // If all conditions pass, the filled rect can either be a fullscreen clear (if it's big
584 // enough), or the rectangle geometry will be used as the scissor clip on the clear.
585 // If everything passes but rule #4, this submits a simplified fill rect op instead so that the
586 // rounding differences between clip and draws don't fight each other.
587 // NOTE: we route draws into clear() regardless of performColorClearsAsDraws() since the
588 // clear call is allowed to reset the oplist even when it also happens to use a GrFillRectOp.
589
590 SkPMColor4f clearColor;
591 if (paint.numCoverageFragmentProcessors() > 0 || !paint.isConstantBlendedColor(&clearColor)) {
592 return false;
593 }
594
595 const SkRect rtRect = fRenderTargetProxy->getBoundsRect();
596 // Will be the intersection of render target, clip, and quad
597 SkRect combinedRect = rtRect;
598
599 SkRRect clipRRect;
600 GrAA clipAA;
601 if (!clip.quickContains(rtRect)) {
602 // If the clip is an rrect with no rounding, then it can replace the full RT bounds as the
603 // limiting region, although we will have to worry about AA. If the clip is anything
604 // more complicated, just punt to the regular fill rect op.
605 if (!clip.isRRect(rtRect, &clipRRect, &clipAA) || !clipRRect.isRect()) {
606 return false;
607 }
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400608
Michael Ludwig43252702019-05-16 15:04:36 -0400609 combinedRect = clipRRect.rect();
Michael Ludwig61a16512019-01-15 11:15:13 -0500610 } else {
611 // The clip is outside the render target, so the clip can be ignored
612 clipAA = GrAA::kNo;
613 }
614
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400615 GrQuadAAFlags edgeFlags; // To account for clip and draw mixing AA modes
Michael Ludwig61a16512019-01-15 11:15:13 -0500616 if (viewMatrix.rectStaysRect()) {
617 // Skip the extra overhead of inverting the view matrix to see if rtRect is contained in the
618 // drawn rectangle, and instead just intersect rtRect with the transformed rect. It will be
619 // the new clear region.
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400620 SkRect drawRect = viewMatrix.mapRect(rect);
621 if (!combinedRect.intersect(drawRect)) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500622 // No intersection means nothing should be drawn, so return true but don't add an op
623 return true;
624 }
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400625
626 // In this case, edge flags start based on draw's AA and then switch per-edge to the clip's
627 // AA setting if that edge was inset.
628 edgeFlags = aa == GrAA::kNo ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll;
629 if (combinedRect.fLeft > drawRect.fLeft) {
630 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kLeft, clipAA);
631 }
632 if (combinedRect.fTop > drawRect.fTop) {
633 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kTop, clipAA);
634 }
635 if (combinedRect.fRight < drawRect.fRight) {
636 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kRight, clipAA);
637 }
638 if (combinedRect.fBottom < drawRect.fBottom) {
639 edgeFlags = set_edge_flag(edgeFlags, GrQuadAAFlags::kBottom, clipAA);
640 }
Michael Ludwig61a16512019-01-15 11:15:13 -0500641 } else {
642 // If the transformed rectangle does not contain the combined rt and clip, the draw is too
643 // complex to be implemented as a clear
644 SkMatrix invM;
645 if (!viewMatrix.invert(&invM)) {
646 return false;
647 }
648 // The clip region in the rect's local space, so the test becomes the local rect containing
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400649 // the quad's points. If clip is non-AA, test rounded out region to avoid the scenario where
650 // the draw contains the unrounded non-aa clip, but does not contain the rounded version. Be
651 // conservative since we don't know how the GPU would round.
652 SkRect conservative;
653 if (clipAA == GrAA::kNo) {
654 conservative = SkRect::Make(combinedRect.roundOut());
655 } else {
656 conservative = combinedRect;
657 }
658 GrQuad quad = GrQuad::MakeFromRect(conservative, invM);
Michael Ludwig61a16512019-01-15 11:15:13 -0500659 if (!rect_contains_inclusive(rect, quad.point(0)) ||
660 !rect_contains_inclusive(rect, quad.point(1)) ||
661 !rect_contains_inclusive(rect, quad.point(2)) ||
662 !rect_contains_inclusive(rect, quad.point(3))) {
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400663 // No containment, so combinedRect can't be filled by a solid color
Michael Ludwig61a16512019-01-15 11:15:13 -0500664 return false;
665 }
666 // 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 -0400667 // inside the quad to be drawn, which also means the edge AA flags respect the clip AA
668 edgeFlags = clipAA == GrAA::kNo ? GrQuadAAFlags::kNone : GrQuadAAFlags::kAll;
Michael Ludwig61a16512019-01-15 11:15:13 -0500669 }
670
671 // Almost every condition is met; now it requires that the combined rect align with pixel
672 // boundaries in order for it to become a scissor-clear. Ignore the AA status in this case
673 // since non-AA with partial-pixel coordinates can be rounded differently on the GPU,
674 // leading to unexpected differences between a scissor test and a rasterized quad.
675 // Also skip very small rectangles since the scissor+clear doesn't by us much then.
676 if (combinedRect.contains(rtRect)) {
677 // Full screen clear
678 this->clear(nullptr, clearColor, CanClearFullscreen::kYes);
679 return true;
680 } else if (GrClip::IsPixelAligned(combinedRect) &&
681 combinedRect.width() > 256 && combinedRect.height() > 256) {
682 // Scissor + clear (round shouldn't do anything since we are pixel aligned)
683 SkIRect scissorRect;
684 combinedRect.round(&scissorRect);
685 this->clear(&scissorRect, clearColor, CanClearFullscreen::kNo);
686 return true;
687 }
688
689 // If we got here, we can't use a scissor + clear, but combinedRect represents the correct
690 // geometry combination of quad + clip so we can perform a simplified fill rect op. We do this
691 // mostly to avoid mismatches in rounding logic on the CPU vs. the GPU, which frequently appears
692 // when drawing and clipping something to the same non-AA rect that never-the-less has
693 // non-integer coordinates.
Michael Ludwig76ec80a2019-05-13 13:30:53 -0400694 aa = edgeFlags == GrQuadAAFlags::kNone ? GrAA::kNo : GrAA::kYes;
Chris Dalton7d6748e2019-03-13 00:34:52 -0600695 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig61a16512019-01-15 11:15:13 -0500696 this->addDrawOp(GrFixedClip::Disabled(),
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400697 GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400698 GrQuad(combinedRect), GrQuad(combinedRect)));
Michael Ludwig61a16512019-01-15 11:15:13 -0500699 return true;
700}
701
702void GrRenderTargetContext::drawFilledRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500703 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500704 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -0400705 const SkMatrix& viewMatrix,
706 const SkRect& rect,
707 const GrUserStencilSettings* ss) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500708
709 if (!ss) {
710 if (this->drawFilledRectAsClear(clip, std::move(paint), aa, viewMatrix, rect)) {
711 return;
712 }
713 // Fall through to fill rect op
714 assert_alive(paint);
715 }
716
csmartdalton97f6cd52016-07-13 13:37:08 -0700717 SkRect croppedRect = rect;
Robert Phillips784b7bf2016-12-09 13:35:02 -0500718 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500719 // The rectangle would not be drawn, so no need to add a draw op to the list
720 return;
csmartdalton97f6cd52016-07-13 13:37:08 -0700721 }
robertphillips44302392016-07-08 14:43:03 -0700722
Chris Dalton7d6748e2019-03-13 00:34:52 -0600723 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400724 GrQuadAAFlags edgeFlags = aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
725 this->addDrawOp(clip,
726 GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400727 GrQuad::MakeFromRect(croppedRect, viewMatrix),
728 GrQuad(croppedRect), ss));
robertphillips391395d2016-03-02 09:26:36 -0800729}
730
Brian Osman11052242016-10-27 14:47:55 -0400731void GrRenderTargetContext::drawRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500732 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500733 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -0400734 const SkMatrix& viewMatrix,
735 const SkRect& rect,
736 const GrStyle* style) {
bsalomon6663acf2016-05-10 09:14:17 -0700737 if (!style) {
738 style = &GrStyle::SimpleFill();
739 }
joshualitt1de610a2016-01-06 08:26:09 -0800740 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700741 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700742 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400743 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRect", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -0700744
bsalomon6663acf2016-05-10 09:14:17 -0700745 // Path effects should've been devolved to a path in SkGpuDevice
746 SkASSERT(!style->pathEffect());
robertphillipsea461502015-05-26 11:38:03 -0700747
Robert Phillips72152832017-01-25 17:31:35 -0500748 AutoCheckFlush acf(this->drawingManager());
robertphillipsea461502015-05-26 11:38:03 -0700749
bsalomon6663acf2016-05-10 09:14:17 -0700750 const SkStrokeRec& stroke = style->strokeRec();
Robert Phillips8c8b0462018-08-24 16:18:03 -0400751 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
Michael Ludwig61a16512019-01-15 11:15:13 -0500752 this->drawFilledRect(clip, std::move(paint), aa, viewMatrix, rect);
753 return;
bsalomona7d85ba2016-07-06 11:54:59 -0700754 } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
755 stroke.getStyle() == SkStrokeRec::kHairline_Style) {
756 if ((!rect.width() || !rect.height()) &&
757 SkStrokeRec::kHairline_Style != stroke.getStyle()) {
758 SkScalar r = stroke.getWidth() / 2;
759 // TODO: Move these stroke->fill fallbacks to GrShape?
760 switch (stroke.getJoin()) {
761 case SkPaint::kMiter_Join:
Brian Salomon82f44312017-01-11 13:42:54 -0500762 this->drawRect(
763 clip, std::move(paint), aa, viewMatrix,
764 {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r},
765 &GrStyle::SimpleFill());
bsalomona7d85ba2016-07-06 11:54:59 -0700766 return;
767 case SkPaint::kRound_Join:
768 // Raster draws nothing when both dimensions are empty.
769 if (rect.width() || rect.height()){
770 SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
Brian Salomon82f44312017-01-11 13:42:54 -0500771 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect,
772 GrStyle::SimpleFill());
bsalomona7d85ba2016-07-06 11:54:59 -0700773 return;
774 }
775 case SkPaint::kBevel_Join:
776 if (!rect.width()) {
Brian Salomon82f44312017-01-11 13:42:54 -0500777 this->drawRect(clip, std::move(paint), aa, viewMatrix,
bsalomona7d85ba2016-07-06 11:54:59 -0700778 {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
779 &GrStyle::SimpleFill());
780 } else {
Brian Salomon82f44312017-01-11 13:42:54 -0500781 this->drawRect(clip, std::move(paint), aa, viewMatrix,
bsalomona7d85ba2016-07-06 11:54:59 -0700782 {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
783 &GrStyle::SimpleFill());
784 }
785 return;
786 }
787 }
robertphillips44302392016-07-08 14:43:03 -0700788
Brian Salomonbaaf4392017-06-15 09:59:23 -0400789 std::unique_ptr<GrDrawOp> op;
robertphillips44302392016-07-08 14:43:03 -0700790
Chris Dalton7d6748e2019-03-13 00:34:52 -0600791 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500792 op = GrStrokeRectOp::Make(fContext, std::move(paint), aaType, viewMatrix, rect, stroke);
793 // op may be null if the stroke is not supported or if using coverage aa and the view matrix
794 // does not preserve rectangles.
Brian Salomon42521e82016-12-07 16:44:58 -0500795 if (op) {
Brian Salomonbaaf4392017-06-15 09:59:23 -0400796 this->addDrawOp(clip, std::move(op));
robertphillips44302392016-07-08 14:43:03 -0700797 return;
robertphillips4bc31812016-03-01 12:22:49 -0800798 }
robertphillips4bc31812016-03-01 12:22:49 -0800799 }
Mike Klein16885072018-12-11 09:54:31 -0500800 assert_alive(paint);
Brian Salomon2fad74a2017-12-20 13:28:55 -0500801 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style));
robertphillipsea461502015-05-26 11:38:03 -0700802}
803
Michael Ludwig69858532018-11-28 15:34:34 -0500804void GrRenderTargetContext::drawQuadSet(const GrClip& clip, GrPaint&& paint, GrAA aa,
805 const SkMatrix& viewMatrix, const QuadSetEntry quads[],
806 int cnt) {
Chris Dalton7d6748e2019-03-13 00:34:52 -0600807 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig69858532018-11-28 15:34:34 -0500808 this->addDrawOp(clip, GrFillRectOp::MakeSet(fContext, std::move(paint), aaType, viewMatrix,
809 quads, cnt));
810}
811
Robert Phillipsec2249f2016-11-09 08:54:35 -0500812int GrRenderTargetContextPriv::maxWindowRectangles() const {
813 return fRenderTargetContext->fRenderTargetProxy->maxWindowRectangles(
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400814 *fRenderTargetContext->caps());
Robert Phillipsec2249f2016-11-09 08:54:35 -0500815}
816
Jim Van Verth6a40abc2017-11-02 16:56:09 +0000817void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
robertphillips976f5f02016-06-03 10:59:20 -0700818 ASSERT_SINGLE_OWNER_PRIV
819 RETURN_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -0400820 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400821 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clearStencilClip",
822 fRenderTargetContext->fContext);
robertphillips976f5f02016-06-03 10:59:20 -0700823
Robert Phillips72152832017-01-25 17:31:35 -0500824 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
Robert Phillipsb9a02a12017-04-06 11:08:40 -0400825
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500826 fRenderTargetContext->internalStencilClear(clip, insideStencilMask);
827}
828
829void GrRenderTargetContext::internalStencilClear(const GrFixedClip& clip, bool insideStencilMask) {
830 if (this->caps()->performStencilClearsAsDraws()) {
831 const GrUserStencilSettings* ss = GrStencilSettings::SetClipBitSettings(insideStencilMask);
832 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
833
834 // Configure the paint to have no impact on the color buffer
835 GrPaint paint;
Michael Ludwig0cb2fde2019-05-28 13:14:41 -0400836 paint.setXPFactory(GrDisableColorXPFactory::Get());
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500837
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 Ludwigaa1b6b32019-05-29 14:43:13 -0400841 this->addDrawOp(clip, GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
842 rtRect, ss));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500843 } 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
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400894void GrRenderTargetContextPriv::stencilRect(const GrClip& clip,
Brian Osman11052242016-10-27 14:47:55 -0400895 const GrUserStencilSettings* ss,
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400896 GrPaint&& paint,
Chris Dalton09e56892019-03-13 00:22:01 -0600897 GrAA doStencilMSAA,
Brian Osman11052242016-10-27 14:47:55 -0400898 const SkMatrix& viewMatrix,
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400899 const SkRect& rect,
900 const SkMatrix* localMatrix) {
robertphillips976f5f02016-06-03 10:59:20 -0700901 ASSERT_SINGLE_OWNER_PRIV
902 RETURN_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -0400903 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400904 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilRect",
905 fRenderTargetContext->fContext);
906
Robert Phillips72152832017-01-25 17:31:35 -0500907 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
robertphillips976f5f02016-06-03 10:59:20 -0700908
Chris Dalton09e56892019-03-13 00:22:01 -0600909 auto aaType = (GrAA::kYes == doStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400910
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400911 GrQuad localQuad = localMatrix ? GrQuad::MakeFromRect(rect, *localMatrix)
912 : GrQuad(rect);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400913 std::unique_ptr<GrDrawOp> op = GrFillRectOp::Make(
Michael Ludwig64b28a72019-05-28 12:02:00 -0400914 fRenderTargetContext->fContext, std::move(paint), aaType, GrQuadAAFlags::kNone,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400915 GrQuad::MakeFromRect(rect, viewMatrix), localQuad, ss);
Brian Salomonbaaf4392017-06-15 09:59:23 -0400916 fRenderTargetContext->addDrawOp(clip, std::move(op));
robertphillips976f5f02016-06-03 10:59:20 -0700917}
918
Michael Ludwig136f45a2019-02-19 11:44:41 -0500919void GrRenderTargetContext::fillRectWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa,
Michael Ludwig75451902019-01-23 11:14:29 -0500920 GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix,
Michael Ludwig136f45a2019-02-19 11:44:41 -0500921 const SkRect& rect, const SkRect* localRect) {
Michael Ludwig75451902019-01-23 11:14:29 -0500922 ASSERT_SINGLE_OWNER
923 RETURN_IF_ABANDONED
924 SkDEBUGCODE(this->validate();)
925 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithEdgeAA", fContext);
926
Chris Dalton7d6748e2019-03-13 00:34:52 -0600927 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig136f45a2019-02-19 11:44:41 -0500928 std::unique_ptr<GrDrawOp> op;
Michael Ludwig75451902019-01-23 11:14:29 -0500929
Michael Ludwig136f45a2019-02-19 11:44:41 -0500930 if (localRect) {
931 // If local coordinates are provided, skip the optimization check to go through
932 // drawFilledRect, and also calculate clipped local coordinates
933 SkRect croppedRect = rect;
934 SkRect croppedLocalRect = *localRect;
935 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect,
936 &croppedLocalRect)) {
937 return;
938 }
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400939 op = GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeAA,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400940 GrQuad::MakeFromRect(croppedRect, viewMatrix),
941 GrQuad(croppedLocalRect));
Michael Ludwig136f45a2019-02-19 11:44:41 -0500942 } else {
943 // If aaType turns into MSAA, make sure to keep quads with no AA edges as MSAA. Sending
944 // those to drawFilledRect() would have it turn off MSAA in that case, which breaks seaming
945 // with any partial AA edges that kept MSAA.
946 if (aaType != GrAAType::kMSAA &&
947 (edgeAA == GrQuadAAFlags::kNone || edgeAA == GrQuadAAFlags::kAll)) {
948 // This is equivalent to a regular filled rect draw, so route through there to take
949 // advantage of draw->clear optimizations
950 this->drawFilledRect(clip, std::move(paint), GrAA(edgeAA == GrQuadAAFlags::kAll),
951 viewMatrix, rect);
952 return;
953 }
954
955 SkRect croppedRect = rect;
956 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
957 return;
958 }
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400959 op = GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeAA,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400960 GrQuad::MakeFromRect(croppedRect, viewMatrix),
961 GrQuad(croppedRect));
Michael Ludwig75451902019-01-23 11:14:29 -0500962 }
963
964 AutoCheckFlush acf(this->drawingManager());
Michael Ludwig136f45a2019-02-19 11:44:41 -0500965 this->addDrawOp(clip, std::move(op));
Michael Ludwig75451902019-01-23 11:14:29 -0500966}
967
Michael Ludwigce62dec2019-02-19 11:48:46 -0500968void GrRenderTargetContext::fillQuadWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa,
969 GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix,
970 const SkPoint quad[4], const SkPoint localQuad[4]) {
971 ASSERT_SINGLE_OWNER
972 RETURN_IF_ABANDONED
973 SkDEBUGCODE(this->validate();)
974 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillQuadWithEdgeAA", fContext);
975
Chris Dalton7d6748e2019-03-13 00:34:52 -0600976 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwigce62dec2019-02-19 11:48:46 -0500977
978 AutoCheckFlush acf(this->drawingManager());
Michael Ludwig64b28a72019-05-28 12:02:00 -0400979 const SkPoint* localPoints = localQuad ? localQuad : quad;
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400980 this->addDrawOp(clip,
981 GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeAA,
Michael Ludwigde4c58c2019-06-04 09:12:59 -0400982 GrQuad::MakeFromSkQuad(quad, viewMatrix),
983 GrQuad::MakeFromSkQuad(localPoints, SkMatrix::I())));
Michael Ludwigce62dec2019-02-19 11:48:46 -0500984}
985
Michael Ludwigd54ca8f2019-02-13 13:25:21 -0500986// Creates a paint for GrFillRectOp that matches behavior of GrTextureOp
987static void draw_texture_to_grpaint(sk_sp<GrTextureProxy> proxy, const SkRect* domain,
988 GrSamplerState::Filter filter, SkBlendMode mode,
989 const SkPMColor4f& color, sk_sp<GrColorSpaceXform> csXform,
990 GrPaint* paint) {
991 paint->setColor4f(color);
992 paint->setXPFactory(SkBlendMode_AsXPFactory(mode));
993
994 std::unique_ptr<GrFragmentProcessor> fp;
995 if (domain) {
Michael Ludwigce62dec2019-02-19 11:48:46 -0500996 SkRect correctedDomain = *domain;
997 if (filter == GrSamplerState::Filter::kBilerp) {
998 // Inset by 1/2 pixel, which GrTextureOp and GrTextureAdjuster handle automatically
999 correctedDomain.inset(0.5f, 0.5f);
1000 }
1001 fp = GrTextureDomainEffect::Make(std::move(proxy), SkMatrix::I(), correctedDomain,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001002 GrTextureDomain::kClamp_Mode, filter);
1003 } else {
1004 fp = GrSimpleTextureEffect::Make(std::move(proxy), SkMatrix::I(), filter);
1005 }
1006
1007 fp = GrColorSpaceXformEffect::Make(std::move(fp), csXform);
1008 paint->addColorFragmentProcessor(std::move(fp));
1009}
1010
Brian Salomonbe3c1d22018-05-21 12:54:39 -04001011void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001012 GrSamplerState::Filter filter, SkBlendMode mode,
1013 const SkPMColor4f& color, const SkRect& srcRect,
Michael Ludwig136f45a2019-02-19 11:44:41 -05001014 const SkRect& dstRect, GrAA aa, GrQuadAAFlags aaFlags,
Brian Salomonb80ffee2018-05-23 16:39:39 -04001015 SkCanvas::SrcRectConstraint constraint,
Brian Salomonbe3c1d22018-05-21 12:54:39 -04001016 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -05001017 sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
Brian Salomon34169692017-08-28 15:32:01 -04001018 ASSERT_SINGLE_OWNER
1019 RETURN_IF_ABANDONED
1020 SkDEBUGCODE(this->validate();)
Brian Salomonbe3c1d22018-05-21 12:54:39 -04001021 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTexture", fContext);
Brian Salomonf1709042018-10-03 11:57:00 -04001022 if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
1023 srcRect.contains(proxy->getWorstCaseBoundsRect())) {
1024 constraint = SkCanvas::kFast_SrcRectConstraint;
Brian Salomon34169692017-08-28 15:32:01 -04001025 }
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001026
Chris Dalton7d6748e2019-03-13 00:34:52 -06001027 GrAAType aaType = this->chooseAAType(aa);
Brian Salomonff9d6d32017-08-30 10:27:49 -04001028 SkRect clippedDstRect = dstRect;
1029 SkRect clippedSrcRect = srcRect;
1030 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &clippedDstRect,
1031 &clippedSrcRect)) {
1032 return;
1033 }
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001034
1035 AutoCheckFlush acf(this->drawingManager());
1036
1037 std::unique_ptr<GrDrawOp> op;
1038 if (mode != SkBlendMode::kSrcOver) {
1039 // Emulation mode with GrPaint and GrFillRectOp
1040 if (filter != GrSamplerState::Filter::kNearest &&
1041 !GrTextureOp::GetFilterHasEffect(viewMatrix, clippedSrcRect, clippedDstRect)) {
1042 filter = GrSamplerState::Filter::kNearest;
1043 }
1044
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001045 GrPaint paint;
1046 draw_texture_to_grpaint(std::move(proxy),
Michael Ludwigce62dec2019-02-19 11:48:46 -05001047 constraint == SkCanvas::kStrict_SrcRectConstraint ? &srcRect : nullptr,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001048 filter, mode, color, std::move(textureColorSpaceXform), &paint);
Michael Ludwig4a0cf502019-05-30 12:54:09 -04001049 op = GrFillRectOp::Make(fContext, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -04001050 GrQuad::MakeFromRect(clippedDstRect, viewMatrix),
1051 GrQuad(clippedSrcRect));
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001052 } else {
1053 // Can use a lighter weight op that can chain across proxies
1054 op = GrTextureOp::Make(fContext, std::move(proxy), filter, color, clippedSrcRect,
1055 clippedDstRect, aaType, aaFlags, constraint, viewMatrix,
1056 std::move(textureColorSpaceXform));
1057 }
1058
Brian Salomon2213ee92018-10-02 10:44:21 -04001059 this->addDrawOp(clip, std::move(op));
Brian Salomon34169692017-08-28 15:32:01 -04001060}
1061
Michael Ludwigce62dec2019-02-19 11:48:46 -05001062void GrRenderTargetContext::drawTextureQuad(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
1063 GrSamplerState::Filter filter, SkBlendMode mode,
1064 const SkPMColor4f& color, const SkPoint srcQuad[4],
1065 const SkPoint dstQuad[4], GrAA aa,
1066 GrQuadAAFlags aaFlags, const SkRect* domain,
1067 const SkMatrix& viewMatrix,
1068 sk_sp<GrColorSpaceXform> texXform) {
1069 ASSERT_SINGLE_OWNER
1070 RETURN_IF_ABANDONED
1071 SkDEBUGCODE(this->validate();)
1072 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureQuad", fContext);
1073 if (domain && domain->contains(proxy->getWorstCaseBoundsRect())) {
1074 domain = nullptr;
1075 }
1076
Chris Dalton7d6748e2019-03-13 00:34:52 -06001077 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwigce62dec2019-02-19 11:48:46 -05001078
1079 // Unlike drawTexture(), don't bother cropping or optimizing the filter type since we're
1080 // sampling an arbitrary quad of the texture.
1081 AutoCheckFlush acf(this->drawingManager());
1082 std::unique_ptr<GrDrawOp> op;
1083 if (mode != SkBlendMode::kSrcOver) {
1084 // Emulation mode, but don't bother converting to kNearest filter since it's an arbitrary
1085 // quad that is being drawn, which makes the tests too expensive here
1086 GrPaint paint;
1087 draw_texture_to_grpaint(
1088 std::move(proxy), domain, filter, mode, color, std::move(texXform), &paint);
Michael Ludwig4a0cf502019-05-30 12:54:09 -04001089 op = GrFillRectOp::Make(fContext, std::move(paint), aaType, aaFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -04001090 GrQuad::MakeFromSkQuad(dstQuad, viewMatrix),
1091 GrQuad::MakeFromSkQuad(srcQuad, SkMatrix::I()));
Michael Ludwigce62dec2019-02-19 11:48:46 -05001092 } else {
1093 // Use lighter weight GrTextureOp
1094 op = GrTextureOp::MakeQuad(fContext, std::move(proxy), filter, color, srcQuad, dstQuad,
1095 aaType, aaFlags, domain, viewMatrix, std::move(texXform));
1096 }
1097
1098 this->addDrawOp(clip, std::move(op));
1099}
1100
Brian Salomond7065e72018-10-12 11:42:02 -04001101void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetEntry set[], int cnt,
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001102 GrSamplerState::Filter filter, SkBlendMode mode,
Michael Ludwig31ba7182019-04-03 10:38:06 -04001103 GrAA aa, SkCanvas::SrcRectConstraint constraint,
1104 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -05001105 sk_sp<GrColorSpaceXform> texXform) {
Brian Salomond7065e72018-10-12 11:42:02 -04001106 ASSERT_SINGLE_OWNER
1107 RETURN_IF_ABANDONED
1108 SkDEBUGCODE(this->validate();)
1109 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureSet", fContext);
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001110
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001111 if (mode != SkBlendMode::kSrcOver ||
Robert Phillips9da87e02019-02-04 13:26:26 -05001112 !fContext->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001113 // Draw one at a time with GrFillRectOp and a GrPaint that emulates what GrTextureOp does
Michael Ludwig7ae2ab52019-03-05 16:00:20 -05001114 SkMatrix ctm;
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001115 for (int i = 0; i < cnt; ++i) {
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001116 float alpha = set[i].fAlpha;
Michael Ludwig7ae2ab52019-03-05 16:00:20 -05001117 ctm = viewMatrix;
1118 if (set[i].fPreViewMatrix) {
1119 ctm.preConcat(*set[i].fPreViewMatrix);
1120 }
1121
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001122 if (set[i].fDstClipQuad == nullptr) {
Michael Ludwigce62dec2019-02-19 11:48:46 -05001123 // Stick with original rectangles, which allows the ops to know more about what's
1124 // being drawn.
1125 this->drawTexture(clip, set[i].fProxy, filter, mode, {alpha, alpha, alpha, alpha},
1126 set[i].fSrcRect, set[i].fDstRect, aa, set[i].fAAFlags,
Michael Ludwig31ba7182019-04-03 10:38:06 -04001127 constraint, ctm, texXform);
Michael Ludwigce62dec2019-02-19 11:48:46 -05001128 } else {
1129 // Generate interpolated texture coordinates to match the dst clip
1130 SkPoint srcQuad[4];
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001131 GrMapRectPoints(set[i].fDstRect, set[i].fSrcRect, set[i].fDstClipQuad, srcQuad, 4);
Michael Ludwig31ba7182019-04-03 10:38:06 -04001132 const SkRect* domain = constraint == SkCanvas::kStrict_SrcRectConstraint
1133 ? &set[i].fSrcRect : nullptr;
Michael Ludwigce62dec2019-02-19 11:48:46 -05001134 this->drawTextureQuad(clip, set[i].fProxy, filter, mode,
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001135 {alpha, alpha, alpha, alpha}, srcQuad, set[i].fDstClipQuad,
Michael Ludwig31ba7182019-04-03 10:38:06 -04001136 aa, set[i].fAAFlags, domain, ctm, texXform);
Michael Ludwigce62dec2019-02-19 11:48:46 -05001137 }
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001138 }
1139 } else {
1140 // Can use a single op, avoiding GrPaint creation, and can batch across proxies
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001141 AutoCheckFlush acf(this->drawingManager());
Chris Dalton7d6748e2019-03-13 00:34:52 -06001142 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig31ba7182019-04-03 10:38:06 -04001143 auto op = GrTextureOp::MakeSet(fContext, set, cnt, filter, aaType, constraint, viewMatrix,
Michael Ludwig009b92e2019-02-15 16:03:53 -05001144 std::move(texXform));
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001145 this->addDrawOp(clip, std::move(op));
1146 }
Brian Salomond7065e72018-10-12 11:42:02 -04001147}
1148
Brian Osman11052242016-10-27 14:47:55 -04001149void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001150 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001151 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001152 const SkMatrix& viewMatrix,
1153 const SkRect& rectToDraw,
1154 const SkMatrix& localMatrix) {
joshualitt1de610a2016-01-06 08:26:09 -08001155 ASSERT_SINGLE_OWNER
joshualittb6b513b2015-08-21 10:25:18 -07001156 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001157 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001158 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "fillRectWithLocalMatrix", fContext);
joshualittb6b513b2015-08-21 10:25:18 -07001159
csmartdalton97f6cd52016-07-13 13:37:08 -07001160 SkRect croppedRect = rectToDraw;
robertphillips13a7eee2016-08-31 15:06:24 -07001161 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &croppedRect)) {
csmartdalton97f6cd52016-07-13 13:37:08 -07001162 return;
1163 }
1164
Robert Phillips72152832017-01-25 17:31:35 -05001165 AutoCheckFlush acf(this->drawingManager());
csmartdaltona7f29642016-07-07 08:49:11 -07001166
Chris Dalton7d6748e2019-03-13 00:34:52 -06001167 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig4a0cf502019-05-30 12:54:09 -04001168 GrQuadAAFlags edgeFlags = aa == GrAA::kYes ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone;
1169 this->addDrawOp(clip,
1170 GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeFlags,
Michael Ludwigde4c58c2019-06-04 09:12:59 -04001171 GrQuad::MakeFromRect(croppedRect, viewMatrix),
1172 GrQuad::MakeFromRect(croppedRect, localMatrix)));
robertphillipsea461502015-05-26 11:38:03 -07001173}
1174
Brian Osman11052242016-10-27 14:47:55 -04001175void GrRenderTargetContext::drawVertices(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001176 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -04001177 const SkMatrix& viewMatrix,
Brian Osmanae0c50c2017-05-25 16:56:34 -04001178 sk_sp<SkVertices> vertices,
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001179 const SkVertices::Bone bones[],
Ruiqi Mao4ec72f72018-07-10 17:21:07 -04001180 int boneCount,
Brian Osmanae0c50c2017-05-25 16:56:34 -04001181 GrPrimitiveType* overridePrimType) {
Brian Salomon199fb872017-02-06 09:41:10 -05001182 ASSERT_SINGLE_OWNER
1183 RETURN_IF_ABANDONED
1184 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001185 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawVertices", fContext);
Brian Salomon199fb872017-02-06 09:41:10 -05001186
1187 AutoCheckFlush acf(this->drawingManager());
1188
1189 SkASSERT(vertices);
Chris Dalton7d6748e2019-03-13 00:34:52 -06001190 GrAAType aaType = this->chooseAAType(GrAA::kNo);
Brian Salomonf3569f02017-10-24 12:52:33 -04001191 std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
Ruiqi Mao4ec72f72018-07-10 17:21:07 -04001192 fContext, std::move(paint), std::move(vertices), bones, boneCount, viewMatrix, aaType,
Brian Salomonf3569f02017-10-24 12:52:33 -04001193 this->colorSpaceInfo().refColorSpaceXformFromSRGB(), overridePrimType);
Brian Salomonc2f42542017-07-12 14:11:22 -04001194 this->addDrawOp(clip, std::move(op));
robertphillipsea461502015-05-26 11:38:03 -07001195}
1196
1197///////////////////////////////////////////////////////////////////////////////
1198
Brian Osman4d92b892019-03-24 00:53:23 +00001199void GrRenderTargetContext::drawAtlas(const GrClip& clip,
1200 GrPaint&& paint,
1201 const SkMatrix& viewMatrix,
1202 int spriteCount,
1203 const SkRSXform xform[],
1204 const SkRect texRect[],
1205 const SkColor colors[]) {
1206 ASSERT_SINGLE_OWNER
1207 RETURN_IF_ABANDONED
1208 SkDEBUGCODE(this->validate();)
1209 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawAtlas", fContext);
1210
1211 AutoCheckFlush acf(this->drawingManager());
1212
1213 GrAAType aaType = this->chooseAAType(GrAA::kNo);
1214 std::unique_ptr<GrDrawOp> op = GrDrawAtlasOp::Make(fContext, std::move(paint), viewMatrix,
1215 aaType, spriteCount, xform, texRect, colors);
1216 this->addDrawOp(clip, std::move(op));
1217}
1218
1219///////////////////////////////////////////////////////////////////////////////
1220
Brian Osman11052242016-10-27 14:47:55 -04001221void GrRenderTargetContext::drawRRect(const GrClip& origClip,
Brian Salomon82f44312017-01-11 13:42:54 -05001222 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001223 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001224 const SkMatrix& viewMatrix,
1225 const SkRRect& rrect,
1226 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08001227 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07001228 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001229 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001230 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRRect", fContext);
Robert Phillips85290802018-07-02 13:14:28 -04001231
1232 const SkStrokeRec& stroke = style.strokeRec();
1233 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07001234 return;
1235 }
1236
bsalomon7f0d9f32016-08-15 14:49:10 -07001237 GrNoClip noclip;
1238 const GrClip* clip = &origClip;
1239#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1240 // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
Brian Salomon42521e82016-12-07 16:44:58 -05001241 // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it
bsalomon7f0d9f32016-08-15 14:49:10 -07001242 // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
1243 // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
Michael Ludwig28398842019-03-25 10:24:24 -04001244 // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. This
1245 // only works for filled rrects since the stroke width outsets beyond the rrect itself.
bsalomon7f0d9f32016-08-15 14:49:10 -07001246 SkRRect devRRect;
Michael Ludwig28398842019-03-25 10:24:24 -04001247 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.transform(viewMatrix, &devRRect) &&
1248 clip->quickContains(devRRect)) {
bsalomon7f0d9f32016-08-15 14:49:10 -07001249 clip = &noclip;
1250 }
1251#endif
bsalomon6663acf2016-05-10 09:14:17 -07001252 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
ksakamotoec7f2ac2016-07-05 03:54:53 -07001253
Robert Phillips72152832017-01-25 17:31:35 -05001254 AutoCheckFlush acf(this->drawingManager());
csmartdaltona7f29642016-07-07 08:49:11 -07001255
Chris Dalton7d6748e2019-03-13 00:34:52 -06001256 GrAAType aaType = this->chooseAAType(aa);
Chris Dalton133944a2018-11-16 23:30:29 -05001257
Chris Dalton0dffbab2019-03-27 13:08:50 -06001258 std::unique_ptr<GrDrawOp> op;
1259 if (style.isSimpleFill()) {
1260 assert_alive(paint);
1261 op = GrFillRRectOp::Make(
1262 fContext, aaType, viewMatrix, rrect, *this->caps(), std::move(paint));
1263 }
Greg Daniel2655ede2019-04-10 00:49:28 +00001264 if (!op && GrAAType::kCoverage == aaType) {
Chris Dalton0dffbab2019-03-27 13:08:50 -06001265 assert_alive(paint);
1266 op = GrOvalOpFactory::MakeRRectOp(
Greg Daniel2655ede2019-04-10 00:49:28 +00001267 fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
1268
Chris Dalton0dffbab2019-03-27 13:08:50 -06001269 }
1270 if (op) {
1271 this->addDrawOp(*clip, std::move(op));
1272 return;
robertphillipsea461502015-05-26 11:38:03 -07001273 }
robertphillipsb56f9272016-02-25 11:03:52 -08001274
Mike Klein16885072018-12-11 09:54:31 -05001275 assert_alive(paint);
Brian Salomon2fad74a2017-12-20 13:28:55 -05001276 this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix,
1277 GrShape(rrect, style));
robertphillipsea461502015-05-26 11:38:03 -07001278}
1279
Jim Van Verthc5903412016-11-17 15:27:09 -05001280///////////////////////////////////////////////////////////////////////////////
1281
Jim Van Verth3af1af92017-05-18 15:06:54 -04001282static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
1283 SkPoint3 result;
1284 m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
1285 result.fZ = pt.fZ;
1286 return result;
1287}
1288
1289bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
Jim Van Verth3af1af92017-05-18 15:06:54 -04001290 const SkMatrix& viewMatrix,
1291 const SkPath& path,
1292 const SkDrawShadowRec& rec) {
Jim Van Verthc5903412016-11-17 15:27:09 -05001293 ASSERT_SINGLE_OWNER
Robert Phillips6a6de562019-02-15 15:19:15 -05001294 if (fContext->priv().abandoned()) {
Jim Van Verth3af1af92017-05-18 15:06:54 -04001295 return true;
1296 }
Jim Van Verthc5903412016-11-17 15:27:09 -05001297 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001298 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFastShadow", fContext);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001299
1300 // check z plane
1301 bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1302 !SkScalarNearlyZero(rec.fZPlaneParams.fY));
1303 bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1304 if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1305 return false;
1306 }
1307
1308 SkRRect rrect;
1309 SkRect rect;
1310 // we can only handle rects, circles, and rrects with circular corners
Mike Reed242135a2018-02-22 13:41:39 -05001311 bool isRRect = path.isRRect(&rrect) && SkRRectPriv::IsSimpleCircular(rrect) &&
Jim Van Verth3af1af92017-05-18 15:06:54 -04001312 rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero;
1313 if (!isRRect &&
1314 path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1315 rect.width() > SK_ScalarNearlyZero) {
1316 rrect.setOval(rect);
1317 isRRect = true;
1318 }
1319 if (!isRRect && path.isRect(&rect)) {
1320 rrect.setRect(rect);
1321 isRRect = true;
1322 }
1323
1324 if (!isRRect) {
1325 return false;
1326 }
1327
Jim Van Verthc5903412016-11-17 15:27:09 -05001328 if (rrect.isEmpty()) {
Jim Van Verth3af1af92017-05-18 15:06:54 -04001329 return true;
Jim Van Verthc5903412016-11-17 15:27:09 -05001330 }
1331
Robert Phillips72152832017-01-25 17:31:35 -05001332 AutoCheckFlush acf(this->drawingManager());
Jim Van Verthc5903412016-11-17 15:27:09 -05001333
Jim Van Verth3af1af92017-05-18 15:06:54 -04001334 // transform light
1335 SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
1336
1337 // 1/scale
1338 SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1339 SkScalarInvert(viewMatrix[SkMatrix::kMScaleX]) :
1340 sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1341 viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1342
1343 SkScalar occluderHeight = rec.fZPlaneParams.fZ;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001344 bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1345
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001346 if (SkColorGetA(rec.fAmbientColor) > 0) {
Jim Van Verth1af03d42017-07-31 09:34:58 -04001347 SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1348 const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1349 const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001350
1351 // Outset the shadow rrect to the border of the penumbra
1352 SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1353 SkRRect ambientRRect;
1354 SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1355 // If the rrect was an oval then its outset will also be one.
1356 // We set it explicitly to avoid errors.
1357 if (rrect.isOval()) {
1358 ambientRRect = SkRRect::MakeOval(outsetRect);
1359 } else {
Mike Reed242135a2018-02-22 13:41:39 -05001360 SkScalar outsetRad = SkRRectPriv::GetSimpleRadii(rrect).fX + ambientPathOutset;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001361 ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1362 }
1363
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001364 GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001365 if (transparent) {
1366 // set a large inset to force a fill
1367 devSpaceInsetWidth = ambientRRect.width();
1368 }
Jim Van Verth39e71652018-04-23 18:08:45 +00001369
Robert Phillips7c525e62018-06-12 10:11:12 -04001370 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1371 ambientColor,
1372 viewMatrix,
Brian Salomon05969092017-07-13 11:20:51 -04001373 ambientRRect,
1374 devSpaceAmbientBlur,
Jim Van Verthfb186392018-09-11 11:37:46 -04001375 devSpaceInsetWidth);
Robert Phillipse5763782019-04-17 14:38:24 -04001376 if (op) {
1377 this->addDrawOp(clip, std::move(op));
1378 }
Jim Van Verthc5903412016-11-17 15:27:09 -05001379 }
Jim Van Verth3af1af92017-05-18 15:06:54 -04001380
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001381 if (SkColorGetA(rec.fSpotColor) > 0) {
Jim Van Verth1af03d42017-07-31 09:34:58 -04001382 SkScalar devSpaceSpotBlur;
1383 SkScalar spotScale;
1384 SkVector spotOffset;
1385 SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1386 devLightPos.fZ, rec.fLightRadius,
1387 &devSpaceSpotBlur, &spotScale, &spotOffset);
1388 // handle scale of radius due to CTM
Jim Van Verth3af1af92017-05-18 15:06:54 -04001389 const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1390
Jim Van Verth3af1af92017-05-18 15:06:54 -04001391 // Adjust translate for the effect of the scale.
1392 spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1393 spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1394 // This offset is in dev space, need to transform it into source space.
1395 SkMatrix ctmInverse;
1396 if (viewMatrix.invert(&ctmInverse)) {
1397 ctmInverse.mapPoints(&spotOffset, 1);
1398 } else {
1399 // Since the matrix is a similarity, this should never happen, but just in case...
1400 SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1401 SkASSERT(false);
1402 }
1403
1404 // Compute the transformed shadow rrect
1405 SkRRect spotShadowRRect;
1406 SkMatrix shadowTransform;
1407 shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1408 rrect.transform(shadowTransform, &spotShadowRRect);
Mike Reed242135a2018-02-22 13:41:39 -05001409 SkScalar spotRadius = SkRRectPriv::GetSimpleRadii(spotShadowRRect).fX;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001410
1411 // Compute the insetWidth
Jim Van Verth1af03d42017-07-31 09:34:58 -04001412 SkScalar blurOutset = srcSpaceSpotBlur;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001413 SkScalar insetWidth = blurOutset;
1414 if (transparent) {
1415 // If transparent, just do a fill
1416 insetWidth += spotShadowRRect.width();
1417 } else {
1418 // For shadows, instead of using a stroke we specify an inset from the penumbra
1419 // border. We want to extend this inset area so that it meets up with the caster
1420 // geometry. The inset geometry will by default already be inset by the blur width.
1421 //
1422 // We compare the min and max corners inset by the radius between the original
1423 // rrect and the shadow rrect. The distance between the two plus the difference
1424 // between the scaled radius and the original radius gives the distance from the
1425 // transformed shadow shape to the original shape in that corner. The max
1426 // of these gives the maximum distance we need to cover.
1427 //
1428 // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1429 // that to get the full insetWidth.
1430 SkScalar maxOffset;
1431 if (rrect.isRect()) {
1432 // Manhattan distance works better for rects
1433 maxOffset = SkTMax(SkTMax(SkTAbs(spotShadowRRect.rect().fLeft -
1434 rrect.rect().fLeft),
1435 SkTAbs(spotShadowRRect.rect().fTop -
1436 rrect.rect().fTop)),
1437 SkTMax(SkTAbs(spotShadowRRect.rect().fRight -
1438 rrect.rect().fRight),
1439 SkTAbs(spotShadowRRect.rect().fBottom -
1440 rrect.rect().fBottom)));
1441 } else {
Mike Reed242135a2018-02-22 13:41:39 -05001442 SkScalar dr = spotRadius - SkRRectPriv::GetSimpleRadii(rrect).fX;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001443 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1444 rrect.rect().fLeft + dr,
1445 spotShadowRRect.rect().fTop -
1446 rrect.rect().fTop + dr);
1447 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1448 rrect.rect().fRight - dr,
1449 spotShadowRRect.rect().fBottom -
1450 rrect.rect().fBottom - dr);
Cary Clarkdf429f32017-11-08 11:44:31 -05001451 maxOffset = SkScalarSqrt(SkTMax(SkPointPriv::LengthSqd(upperLeftOffset),
1452 SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001453 }
Jim Van Verth4c8c1e82018-04-23 17:14:48 -04001454 insetWidth += SkTMax(blurOutset, maxOffset);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001455 }
1456
1457 // Outset the shadow rrect to the border of the penumbra
1458 SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1459 if (spotShadowRRect.isOval()) {
1460 spotShadowRRect = SkRRect::MakeOval(outsetRect);
1461 } else {
1462 SkScalar outsetRad = spotRadius + blurOutset;
1463 spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1464 }
1465
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001466 GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
Jim Van Verth34d6e4b2017-06-09 11:09:03 -04001467
Robert Phillips7c525e62018-06-12 10:11:12 -04001468 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1469 spotColor,
1470 viewMatrix,
Brian Salomon05969092017-07-13 11:20:51 -04001471 spotShadowRRect,
Jim Van Verth1af03d42017-07-31 09:34:58 -04001472 2.0f * devSpaceSpotBlur,
Brian Salomon05969092017-07-13 11:20:51 -04001473 insetWidth);
Robert Phillipse5763782019-04-17 14:38:24 -04001474 if (op) {
1475 this->addDrawOp(clip, std::move(op));
1476 }
Jim Van Verth3af1af92017-05-18 15:06:54 -04001477 }
1478
1479 return true;
Jim Van Verthc5903412016-11-17 15:27:09 -05001480}
1481
1482///////////////////////////////////////////////////////////////////////////////
1483
Brian Osman11052242016-10-27 14:47:55 -04001484bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001485 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001486 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001487 const SkMatrix& viewMatrix,
1488 const SkRRect& origOuter,
1489 const SkRRect& origInner) {
robertphillips00095892016-02-29 13:50:40 -08001490 SkASSERT(!origInner.isEmpty());
1491 SkASSERT(!origOuter.isEmpty());
1492
Brian Salomon65749212017-12-01 16:01:47 -05001493 SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
1494
Chris Dalton7d6748e2019-03-13 00:34:52 -06001495 GrAAType aaType = this->chooseAAType(aa);
Brian Salomon45839f92017-12-04 09:02:35 -05001496
1497 if (GrAAType::kMSAA == aaType) {
1498 return false;
1499 }
1500
Greg Daniel2655ede2019-04-10 00:49:28 +00001501 if (GrAAType::kCoverage == aaType && SkRRectPriv::IsCircle(*inner)
1502 && SkRRectPriv::IsCircle(*outer)) {
Brian Salomon65749212017-12-01 16:01:47 -05001503 auto outerR = outer->width() / 2.f;
1504 auto innerR = inner->width() / 2.f;
1505 auto cx = outer->getBounds().fLeft + outerR;
1506 auto cy = outer->getBounds().fTop + outerR;
1507 if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) &&
1508 SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) {
1509 auto avgR = (innerR + outerR) / 2.f;
1510 auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR);
1511 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
1512 stroke.setStrokeStyle(outerR - innerR);
Greg Daniel2655ede2019-04-10 00:49:28 +00001513 auto op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix,
Robert Phillips7c525e62018-06-12 10:11:12 -04001514 circleBounds, GrStyle(stroke, nullptr),
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001515 this->caps()->shaderCaps());
Brian Salomon65749212017-12-01 16:01:47 -05001516 if (op) {
1517 this->addDrawOp(clip, std::move(op));
1518 return true;
1519 }
Mike Klein16885072018-12-11 09:54:31 -05001520 assert_alive(paint);
Brian Salomon65749212017-12-01 16:01:47 -05001521 }
1522 }
1523
Ethan Nicholas0f3c7322017-11-09 14:51:17 -05001524 GrClipEdgeType innerEdgeType, outerEdgeType;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001525 if (GrAAType::kCoverage == aaType) {
Ethan Nicholas1706f842017-11-10 11:58:19 -05001526 innerEdgeType = GrClipEdgeType::kInverseFillAA;
1527 outerEdgeType = GrClipEdgeType::kFillAA;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001528 } else {
Ethan Nicholas1706f842017-11-10 11:58:19 -05001529 innerEdgeType = GrClipEdgeType::kInverseFillBW;
1530 outerEdgeType = GrClipEdgeType::kFillBW;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001531 }
robertphillips00095892016-02-29 13:50:40 -08001532
robertphillips00095892016-02-29 13:50:40 -08001533 SkMatrix inverseVM;
1534 if (!viewMatrix.isIdentity()) {
1535 if (!origInner.transform(viewMatrix, inner.writable())) {
1536 return false;
1537 }
1538 if (!origOuter.transform(viewMatrix, outer.writable())) {
1539 return false;
1540 }
1541 if (!viewMatrix.invert(&inverseVM)) {
1542 return false;
1543 }
1544 } else {
1545 inverseVM.reset();
halcanary9d524f22016-03-29 09:03:52 -07001546 }
robertphillips00095892016-02-29 13:50:40 -08001547
Ethan Nicholaseace9352018-10-15 20:09:54 +00001548 const auto& caps = *this->caps()->shaderCaps();
robertphillips00095892016-02-29 13:50:40 -08001549 // TODO these need to be a geometry processors
Ethan Nicholaseace9352018-10-15 20:09:54 +00001550 auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps);
robertphillips00095892016-02-29 13:50:40 -08001551 if (!innerEffect) {
1552 return false;
1553 }
1554
Ethan Nicholaseace9352018-10-15 20:09:54 +00001555 auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps);
robertphillips00095892016-02-29 13:50:40 -08001556 if (!outerEffect) {
1557 return false;
1558 }
1559
Brian Salomon82f44312017-01-11 13:42:54 -05001560 paint.addCoverageFragmentProcessor(std::move(innerEffect));
1561 paint.addCoverageFragmentProcessor(std::move(outerEffect));
robertphillips00095892016-02-29 13:50:40 -08001562
1563 SkRect bounds = outer->getBounds();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001564 if (GrAAType::kCoverage == aaType) {
robertphillips00095892016-02-29 13:50:40 -08001565 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1566 }
halcanary9d524f22016-03-29 09:03:52 -07001567
Brian Salomon82f44312017-01-11 13:42:54 -05001568 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds,
1569 inverseVM);
robertphillips00095892016-02-29 13:50:40 -08001570 return true;
1571}
1572
Brian Osman11052242016-10-27 14:47:55 -04001573void GrRenderTargetContext::drawDRRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001574 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001575 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001576 const SkMatrix& viewMatrix,
1577 const SkRRect& outer,
1578 const SkRRect& inner) {
robertphillips00095892016-02-29 13:50:40 -08001579 ASSERT_SINGLE_OWNER
1580 RETURN_IF_ABANDONED
1581 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001582 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawDRRect", fContext);
robertphillips00095892016-02-29 13:50:40 -08001583
1584 SkASSERT(!outer.isEmpty());
1585 SkASSERT(!inner.isEmpty());
1586
Robert Phillips72152832017-01-25 17:31:35 -05001587 AutoCheckFlush acf(this->drawingManager());
robertphillips00095892016-02-29 13:50:40 -08001588
Brian Salomon82f44312017-01-11 13:42:54 -05001589 if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) {
robertphillips00095892016-02-29 13:50:40 -08001590 return;
1591 }
Mike Klein16885072018-12-11 09:54:31 -05001592 assert_alive(paint);
robertphillips00095892016-02-29 13:50:40 -08001593
1594 SkPath path;
1595 path.setIsVolatile(true);
1596 path.addRRect(inner);
1597 path.addRRect(outer);
1598 path.setFillType(SkPath::kEvenOdd_FillType);
Brian Salomon2fad74a2017-12-20 13:28:55 -05001599 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path));
robertphillips00095892016-02-29 13:50:40 -08001600}
1601
robertphillipsea461502015-05-26 11:38:03 -07001602///////////////////////////////////////////////////////////////////////////////
1603
Brian Osman11052242016-10-27 14:47:55 -04001604void GrRenderTargetContext::drawRegion(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001605 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001606 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001607 const SkMatrix& viewMatrix,
1608 const SkRegion& region,
Stan Iliev73d8fd92017-08-02 15:36:24 -04001609 const GrStyle& style,
1610 const GrUserStencilSettings* ss) {
msarettcc319b92016-08-25 18:07:18 -07001611 ASSERT_SINGLE_OWNER
1612 RETURN_IF_ABANDONED
1613 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001614 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRegion", fContext);
msarettcc319b92016-08-25 18:07:18 -07001615
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001616 if (GrAA::kYes == aa) {
Brian Salomonfc527d22016-12-14 21:07:01 -05001617 // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
Brian Salomonc57c7c92016-12-06 14:47:34 -05001618 // to see whether aa is really required.
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001619 if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
Brian Salomon34169692017-08-28 15:32:01 -04001620 SkScalarIsInt(viewMatrix.getTranslateX()) &&
1621 SkScalarIsInt(viewMatrix.getTranslateY())) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001622 aa = GrAA::kNo;
1623 }
Brian Salomonc57c7c92016-12-06 14:47:34 -05001624 }
msarettcc319b92016-08-25 18:07:18 -07001625 bool complexStyle = !style.isSimpleFill();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001626 if (complexStyle || GrAA::kYes == aa) {
msarettcc319b92016-08-25 18:07:18 -07001627 SkPath path;
1628 region.getBoundaryPath(&path);
Robert Phillips46a13382018-08-23 13:53:01 -04001629 path.setIsVolatile(true);
1630
Brian Salomon82f44312017-01-11 13:42:54 -05001631 return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
msarettcc319b92016-08-25 18:07:18 -07001632 }
1633
Chris Dalton7d6748e2019-03-13 00:34:52 -06001634 GrAAType aaType = this->chooseAAType(GrAA::kNo);
Robert Phillips7c525e62018-06-12 10:11:12 -04001635 std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(fContext, std::move(paint), viewMatrix, region,
1636 aaType, ss);
Brian Salomonf0366322017-07-11 15:53:05 -04001637 this->addDrawOp(clip, std::move(op));
msarettcc319b92016-08-25 18:07:18 -07001638}
1639
Brian Osman11052242016-10-27 14:47:55 -04001640void GrRenderTargetContext::drawOval(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001641 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001642 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001643 const SkMatrix& viewMatrix,
1644 const SkRect& oval,
1645 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08001646 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07001647 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001648 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001649 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawOval", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -07001650
Robert Phillips7484d202018-07-03 09:09:08 -04001651 const SkStrokeRec& stroke = style.strokeRec();
1652
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001653 if (oval.isEmpty() && !style.pathEffect()) {
Robert Phillips7484d202018-07-03 09:09:08 -04001654 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1655 return;
1656 }
1657
1658 this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001659 return;
robertphillipsea461502015-05-26 11:38:03 -07001660 }
1661
Robert Phillips72152832017-01-25 17:31:35 -05001662 AutoCheckFlush acf(this->drawingManager());
csmartdaltona7f29642016-07-07 08:49:11 -07001663
Chris Dalton7d6748e2019-03-13 00:34:52 -06001664 GrAAType aaType = this->chooseAAType(aa);
Chris Dalton0dffbab2019-03-27 13:08:50 -06001665
1666 std::unique_ptr<GrDrawOp> op;
1667 if (style.isSimpleFill()) {
Chris Dalton82eb9e72019-03-21 14:26:39 -06001668 // GrFillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate
1669 // the arc equation. This same special geometry and fragment branch also turn out to be a
1670 // substantial optimization for drawing ovals (namely, by not evaluating the arc equation
1671 // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw
1672 // ovals the exact same way we do round rects.
Chris Daltonebc38c92018-11-28 16:58:09 -07001673 //
Greg Daniel2655ede2019-04-10 00:49:28 +00001674 // However, we still don't draw true circles as round rects in coverage mode, because it can
1675 // cause perf regressions on some platforms as compared to the dedicated circle Op.
1676 if (GrAAType::kCoverage != aaType || oval.height() != oval.width()) {
Chris Daltonbf341ae2019-03-27 00:28:22 +00001677 assert_alive(paint);
Chris Dalton0dffbab2019-03-27 13:08:50 -06001678 op = GrFillRRectOp::Make(fContext, aaType, viewMatrix, SkRRect::MakeOval(oval),
1679 *this->caps(), std::move(paint));
Chris Daltonbf341ae2019-03-27 00:28:22 +00001680 }
Chris Dalton0dffbab2019-03-27 13:08:50 -06001681 }
Greg Daniel2655ede2019-04-10 00:49:28 +00001682 if (!op && GrAAType::kCoverage == aaType) {
Chris Dalton0dffbab2019-03-27 13:08:50 -06001683 assert_alive(paint);
Greg Daniel2655ede2019-04-10 00:49:28 +00001684 op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1685 this->caps()->shaderCaps());
Chris Dalton0dffbab2019-03-27 13:08:50 -06001686 }
1687 if (op) {
1688 this->addDrawOp(clip, std::move(op));
1689 return;
robertphillipsea461502015-05-26 11:38:03 -07001690 }
robertphillipsb56f9272016-02-25 11:03:52 -08001691
Mike Klein16885072018-12-11 09:54:31 -05001692 assert_alive(paint);
Brian Salomon5209d7f2018-04-20 16:52:42 -04001693 this->drawShapeUsingPathRenderer(
1694 clip, std::move(paint), aa, viewMatrix,
1695 GrShape(SkRRect::MakeOval(oval), SkPath::kCW_Direction, 2, false, style));
robertphillipsea461502015-05-26 11:38:03 -07001696}
1697
Brian Osman11052242016-10-27 14:47:55 -04001698void GrRenderTargetContext::drawArc(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001699 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001700 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001701 const SkMatrix& viewMatrix,
1702 const SkRect& oval,
1703 SkScalar startAngle,
1704 SkScalar sweepAngle,
1705 bool useCenter,
1706 const GrStyle& style) {
Robert Phillipsf1d0ced2017-02-10 09:31:01 -05001707 ASSERT_SINGLE_OWNER
1708 RETURN_IF_ABANDONED
1709 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001710 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawArc", fContext);
Robert Phillipsf1d0ced2017-02-10 09:31:01 -05001711
1712 AutoCheckFlush acf(this->drawingManager());
1713
Chris Dalton7d6748e2019-03-13 00:34:52 -06001714 GrAAType aaType = this->chooseAAType(aa);
Greg Daniel2655ede2019-04-10 00:49:28 +00001715 if (GrAAType::kCoverage == aaType) {
1716 const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
1717 std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(fContext,
1718 std::move(paint),
1719 viewMatrix,
1720 oval,
1721 startAngle,
1722 sweepAngle,
1723 useCenter,
1724 style,
1725 shaderCaps);
1726 if (op) {
1727 this->addDrawOp(clip, std::move(op));
1728 return;
1729 }
1730 assert_alive(paint);
bsalomon4f3a0ca2016-08-22 13:14:26 -07001731 }
Brian Salomone4949402018-04-26 15:22:04 -04001732 this->drawShapeUsingPathRenderer(
1733 clip, std::move(paint), aa, viewMatrix,
1734 GrShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style));
bsalomon4f3a0ca2016-08-22 13:14:26 -07001735}
1736
Brian Osman11052242016-10-27 14:47:55 -04001737void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001738 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -04001739 const SkMatrix& viewMatrix,
Brian Salomon2a943df2018-05-04 13:43:19 -04001740 sk_sp<GrTextureProxy> image,
1741 sk_sp<GrColorSpaceXform> csxf,
1742 GrSamplerState::Filter filter,
Brian Osman11052242016-10-27 14:47:55 -04001743 std::unique_ptr<SkLatticeIter> iter,
1744 const SkRect& dst) {
joshualitt1de610a2016-01-06 08:26:09 -08001745 ASSERT_SINGLE_OWNER
joshualitt33a5fce2015-11-18 13:28:51 -08001746 RETURN_IF_ABANDONED
1747 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001748 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawImageLattice", fContext);
joshualitt33a5fce2015-11-18 13:28:51 -08001749
Robert Phillips72152832017-01-25 17:31:35 -05001750 AutoCheckFlush acf(this->drawingManager());
joshualitt33a5fce2015-11-18 13:28:51 -08001751
Brian Salomon2a943df2018-05-04 13:43:19 -04001752 std::unique_ptr<GrDrawOp> op =
Robert Phillips7c525e62018-06-12 10:11:12 -04001753 GrLatticeOp::MakeNonAA(fContext, std::move(paint), viewMatrix, std::move(image),
1754 std::move(csxf), filter, std::move(iter), dst);
Brian Salomon815486c2017-07-11 08:52:13 -04001755 this->addDrawOp(clip, std::move(op));
joshualitt33a5fce2015-11-18 13:28:51 -08001756}
1757
Greg Daniel64cc9aa2018-10-19 13:54:56 -04001758void GrRenderTargetContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
1759 const SkRect& bounds) {
1760 std::unique_ptr<GrOp> op(GrDrawableOp::Make(fContext, std::move(drawable), bounds));
1761 SkASSERT(op);
1762 this->getRTOpList()->addOp(std::move(op), *this->caps());
1763}
1764
Brian Salomon031b0ba2019-05-23 11:05:26 -04001765sk_sp<GrRenderTargetContext> GrRenderTargetContext::rescale(const SkImageInfo& info,
1766 const SkIRect& srcRect,
1767 SkSurface::RescaleGamma rescaleGamma,
1768 SkFilterQuality rescaleQuality) {
Brian Salomonab32f652019-05-10 14:24:50 -04001769 auto direct = fContext->priv().asDirectContext();
1770 if (!direct) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001771 return nullptr;
Brian Salomonab32f652019-05-10 14:24:50 -04001772 }
1773 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001774 return nullptr;
1775 }
1776
1777 // We currently don't know our own alpha type, we assume it's premul if we have an alpha channel
1778 // and opaque otherwise.
1779 if (!GrPixelConfigIsAlphaOnly(fRenderTargetProxy->config()) &&
1780 info.alphaType() != kPremul_SkAlphaType) {
1781 return nullptr;
1782 }
1783
1784 int srcW = srcRect.width();
1785 int srcH = srcRect.height();
1786 int srcX = srcRect.fLeft;
1787 int srcY = srcRect.fTop;
Greg Danielc5167c02019-06-05 17:36:53 +00001788 sk_sp<GrSurfaceContext> srcContext = sk_ref_sp(this);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001789 SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint;
Greg Danielc5167c02019-06-05 17:36:53 +00001790 if (!this->asTextureProxy()) {
1791 GrSurfaceDesc desc;
1792 desc.fWidth = srcW;
1793 desc.fHeight = srcH;
1794 desc.fConfig = fRenderTargetProxy->config();
1795 auto sContext = direct->priv().makeDeferredSurfaceContext(
1796 fRenderTargetProxy->backendFormat().makeTexture2D(), desc, this->origin(),
1797 GrMipMapped::kNo, SkBackingFit::kApprox, SkBudgeted::kNo,
1798 this->colorSpaceInfo().refColorSpace());
1799 if (!sContext) {
1800 return nullptr;
1801 }
1802 if (!sContext->copy(fRenderTargetProxy.get(), srcRect, {0, 0})) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001803 return nullptr;
1804 }
1805 srcX = 0;
1806 srcY = 0;
1807 constraint = SkCanvas::kFast_SrcRectConstraint;
Greg Danielc5167c02019-06-05 17:36:53 +00001808 srcContext = std::move(sContext);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001809 }
1810
1811 float sx = (float)info.width() / srcW;
1812 float sy = (float)info.height() / srcH;
1813
1814 // How many bilerp/bicubic steps to do in X and Y. + means upscaling, - means downscaling.
1815 int stepsX;
1816 int stepsY;
1817 if (rescaleQuality > kNone_SkFilterQuality) {
1818 stepsX = static_cast<int>((sx > 1.f) ? std::ceil(std::log2f(sx))
1819 : std::floor(std::log2f(sx)));
1820 stepsY = static_cast<int>((sy > 1.f) ? std::ceil(std::log2f(sy))
1821 : std::floor(std::log2f(sy)));
1822 } else {
1823 stepsX = sx != 1.f;
1824 stepsY = sy != 1.f;
1825 }
1826 SkASSERT(stepsX || stepsY);
1827 // Assume we should ignore the rescale linear request if the surface has no color space since
1828 // it's unclear how we'd linearize from an unknown color space.
1829 if (rescaleGamma == SkSurface::RescaleGamma::kLinear &&
Greg Danielc5167c02019-06-05 17:36:53 +00001830 srcContext->colorSpaceInfo().colorSpace() &&
1831 !srcContext->colorSpaceInfo().colorSpace()->gammaIsLinear()) {
1832 auto cs = srcContext->colorSpaceInfo().colorSpace()->makeLinearGamma();
Brian Salomon031b0ba2019-05-23 11:05:26 -04001833 auto backendFormat = this->caps()->getBackendFormatFromGrColorType(GrColorType::kRGBA_F16,
1834 GrSRGBEncoded::kNo);
Greg Danielc5167c02019-06-05 17:36:53 +00001835 auto xform = GrColorSpaceXform::Make(srcContext->colorSpaceInfo().colorSpace(),
1836 kPremul_SkAlphaType, cs.get(), kPremul_SkAlphaType);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001837 // We'll fall back to kRGBA_8888 if half float not supported.
1838 auto linearRTC = fContext->priv().makeDeferredRenderTargetContextWithFallback(
Greg Danielc5167c02019-06-05 17:36:53 +00001839 backendFormat, SkBackingFit::kExact, srcW, srcH, kRGBA_half_GrPixelConfig,
1840 std::move(cs), 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001841 if (!linearRTC) {
1842 return nullptr;
1843 }
Greg Danielc5167c02019-06-05 17:36:53 +00001844 linearRTC->drawTexture(GrNoClip(), srcContext->asTextureProxyRef(),
Brian Salomon031b0ba2019-05-23 11:05:26 -04001845 GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
1846 SK_PMColor4fWHITE, SkRect::Make(srcRect), SkRect::MakeWH(srcW, srcH),
1847 GrAA::kNo, GrQuadAAFlags::kNone, constraint, SkMatrix::I(),
1848 std::move(xform));
Greg Danielc5167c02019-06-05 17:36:53 +00001849 srcContext = std::move(linearRTC);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001850 srcX = 0;
1851 srcY = 0;
1852 constraint = SkCanvas::kFast_SrcRectConstraint;
1853 }
1854 while (stepsX || stepsY) {
1855 int nextW = info.width();
1856 int nextH = info.height();
1857 if (stepsX < 0) {
1858 nextW = info.width() << (-stepsX - 1);
1859 stepsX++;
1860 } else if (stepsX != 0) {
1861 if (stepsX > 1) {
1862 nextW = srcW * 2;
1863 }
1864 --stepsX;
1865 }
1866 if (stepsY < 0) {
1867 nextH = info.height() << (-stepsY - 1);
1868 stepsY++;
1869 } else if (stepsY != 0) {
1870 if (stepsY > 1) {
1871 nextH = srcH * 2;
1872 }
1873 --stepsY;
1874 }
Greg Danielc5167c02019-06-05 17:36:53 +00001875 GrBackendFormat backendFormat =
1876 srcContext->asSurfaceProxy()->backendFormat().makeTexture2D();
1877 GrPixelConfig config = srcContext->asSurfaceProxy()->config();
1878 auto cs = srcContext->colorSpaceInfo().refColorSpace();
Brian Salomon900dda82019-06-03 13:12:55 -04001879 sk_sp<GrColorSpaceXform> xform;
Brian Salomon031b0ba2019-05-23 11:05:26 -04001880 if (!stepsX && !stepsY) {
1881 // Might as well fold conversion to final info in the last step.
1882 backendFormat = this->caps()->getBackendFormatFromColorType(info.colorType());
1883 config = this->caps()->getConfigFromBackendFormat(backendFormat, info.colorType());
1884 cs = info.refColorSpace();
Greg Danielc5167c02019-06-05 17:36:53 +00001885 xform = GrColorSpaceXform::Make(srcContext->colorSpaceInfo().colorSpace(),
Brian Salomon900dda82019-06-03 13:12:55 -04001886 kPremul_SkAlphaType, cs.get(), info.alphaType());
Brian Salomon031b0ba2019-05-23 11:05:26 -04001887 }
Greg Danielc5167c02019-06-05 17:36:53 +00001888 auto nextRTC = fContext->priv().makeDeferredRenderTargetContextWithFallback(
Brian Salomon031b0ba2019-05-23 11:05:26 -04001889 backendFormat, SkBackingFit::kExact, nextW, nextH, config, std::move(cs), 1,
1890 GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
Greg Danielc5167c02019-06-05 17:36:53 +00001891 if (!nextRTC) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001892 return nullptr;
1893 }
1894 auto dstRect = SkRect::MakeWH(nextW, nextH);
1895 if (rescaleQuality == kHigh_SkFilterQuality) {
1896 SkMatrix matrix;
1897 matrix.setScaleTranslate((float)srcW / nextW, (float)srcH / nextH, srcX, srcY);
1898 std::unique_ptr<GrFragmentProcessor> fp;
Brian Salomona86fc7a2019-05-28 20:42:58 -04001899 auto dir = GrBicubicEffect::Direction::kXY;
1900 if (nextW == srcW) {
1901 dir = GrBicubicEffect::Direction::kY;
1902 } else if (nextH == srcH) {
1903 dir = GrBicubicEffect::Direction::kX;
1904 }
Greg Danielc5167c02019-06-05 17:36:53 +00001905 if (srcW != srcContext->width() || srcH != srcContext->height()) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001906 auto domain = GrTextureDomain::MakeTexelDomain(
1907 SkIRect::MakeXYWH(srcX, srcY, srcW, srcH), GrTextureDomain::kClamp_Mode);
Greg Danielc5167c02019-06-05 17:36:53 +00001908 fp = GrBicubicEffect::Make(srcContext->asTextureProxyRef(), matrix, domain, dir,
1909 kPremul_SkAlphaType);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001910 } else {
Greg Danielc5167c02019-06-05 17:36:53 +00001911 fp = GrBicubicEffect::Make(srcContext->asTextureProxyRef(), matrix, dir,
1912 kPremul_SkAlphaType);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001913 }
Brian Salomon900dda82019-06-03 13:12:55 -04001914 if (xform) {
1915 fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(xform));
1916 }
Brian Salomon031b0ba2019-05-23 11:05:26 -04001917 GrPaint paint;
1918 paint.addColorFragmentProcessor(std::move(fp));
1919 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Greg Danielc5167c02019-06-05 17:36:53 +00001920 nextRTC->drawFilledRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
Brian Salomon031b0ba2019-05-23 11:05:26 -04001921 dstRect);
1922 } else {
1923 auto filter = rescaleQuality == kNone_SkFilterQuality ? GrSamplerState::Filter::kNearest
1924 : GrSamplerState::Filter::kBilerp;
1925 auto srcSubset = SkRect::MakeXYWH(srcX, srcY, srcW, srcH);
Greg Danielc5167c02019-06-05 17:36:53 +00001926 nextRTC->drawTexture(GrNoClip(), srcContext->asTextureProxyRef(), filter,
1927 SkBlendMode::kSrc, SK_PMColor4fWHITE, srcSubset, dstRect,
1928 GrAA::kNo, GrQuadAAFlags::kNone, constraint, SkMatrix::I(),
1929 std::move(xform));
Brian Salomon031b0ba2019-05-23 11:05:26 -04001930 }
Greg Danielc5167c02019-06-05 17:36:53 +00001931 srcContext = std::move(nextRTC);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001932 srcX = srcY = 0;
1933 srcW = nextW;
1934 srcH = nextH;
1935 constraint = SkCanvas::kFast_SrcRectConstraint;
1936 }
Greg Danielc5167c02019-06-05 17:36:53 +00001937 auto result = sk_ref_sp(srcContext->asRenderTargetContext());
1938 SkASSERT(result);
1939 return result;
Brian Salomon031b0ba2019-05-23 11:05:26 -04001940}
1941
1942void GrRenderTargetContext::asyncRescaleAndReadPixels(
1943 const SkImageInfo& info, const SkIRect& srcRect, SkSurface::RescaleGamma rescaleGamma,
1944 SkFilterQuality rescaleQuality, ReadPixelsCallback callback, ReadPixelsContext context) {
1945 auto direct = fContext->priv().asDirectContext();
1946 if (!direct) {
1947 callback(context, nullptr, 0);
1948 return;
1949 }
1950 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
1951 callback(context, nullptr, 0);
1952 return;
Brian Salomonab32f652019-05-10 14:24:50 -04001953 }
1954 // We currently don't know our own alpha type, we assume it's premul if we have an alpha channel
1955 // and opaque otherwise.
Brian Salomon201700f2019-05-17 12:05:44 -04001956 if (!GrPixelConfigIsAlphaOnly(fRenderTargetProxy->config()) &&
1957 info.alphaType() != kPremul_SkAlphaType) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001958 callback(context, nullptr, 0);
1959 return;
1960 }
1961 auto dstCT = SkColorTypeToGrColorType(info.colorType());
1962 bool needsRescale = srcRect.width() != info.width() || srcRect.height() != info.height();
1963 GrPixelConfig configOfFinalContext = fRenderTargetProxy->config();
1964 if (needsRescale) {
1965 auto backendFormat = this->caps()->getBackendFormatFromColorType(info.colorType());
1966 configOfFinalContext =
1967 this->caps()->getConfigFromBackendFormat(backendFormat, info.colorType());
1968 }
1969 auto readCT = this->caps()->supportedReadPixelsColorType(configOfFinalContext, dstCT);
1970 // Fail if we can't do a CPU conversion from readCT to dstCT.
1971 if (GrColorTypeToSkColorType(readCT) == kUnknown_SkColorType) {
1972 callback(context, nullptr, 0);
1973 return;
1974 }
1975 // Fail if readCT does not have all of readCT's color channels.
1976 if (GrColorTypeComponentFlags(dstCT) & ~GrColorTypeComponentFlags(readCT)) {
1977 callback(context, nullptr, 0);
1978 return;
1979 }
1980
1981 sk_sp<GrRenderTargetContext> rtc;
1982 int x = srcRect.fLeft;
1983 int y = srcRect.fTop;
1984 if (needsRescale) {
1985 rtc = this->rescale(info, srcRect, rescaleGamma, rescaleQuality);
1986 if (!rtc) {
1987 callback(context, nullptr, 0);
1988 return;
1989 }
1990 SkASSERT(SkColorSpace::Equals(rtc->colorSpaceInfo().colorSpace(), info.colorSpace()));
1991 SkASSERT(rtc->origin() == kTopLeft_GrSurfaceOrigin);
1992 x = y = 0;
1993 } else {
1994 sk_sp<GrColorSpaceXform> xform =
1995 GrColorSpaceXform::Make(this->colorSpaceInfo().colorSpace(), kPremul_SkAlphaType,
1996 info.colorSpace(), info.alphaType());
1997 // Insert a draw to a temporary surface if we need to do a y-flip or color space conversion.
1998 if (this->origin() == kBottomLeft_GrSurfaceOrigin || xform) {
1999 sk_sp<GrTextureProxy> texProxy = sk_ref_sp(fRenderTargetProxy->asTextureProxy());
2000 const auto backendFormat = fRenderTargetProxy->backendFormat().makeTexture2D();
2001 SkRect srcRectToDraw = SkRect::Make(srcRect);
2002 // If the src is not texturable first try to make a copy to a texture.
2003 if (!texProxy) {
Greg Danielc5167c02019-06-05 17:36:53 +00002004 GrSurfaceDesc desc;
2005 desc.fWidth = srcRect.width();
2006 desc.fHeight = srcRect.height();
2007 desc.fConfig = fRenderTargetProxy->config();
2008 auto sContext = direct->priv().makeDeferredSurfaceContext(
2009 backendFormat, desc, this->origin(), GrMipMapped::kNo,
2010 SkBackingFit::kApprox, SkBudgeted::kNo,
2011 this->colorSpaceInfo().refColorSpace());
2012 if (!sContext) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04002013 callback(context, nullptr, 0);
2014 return;
2015 }
Greg Danielc5167c02019-06-05 17:36:53 +00002016 if (!sContext->copy(fRenderTargetProxy.get(), srcRect, {0, 0})) {
2017 callback(context, nullptr, 0);
2018 return;
2019 }
2020 texProxy = sk_ref_sp(sContext->asTextureProxy());
2021 SkASSERT(texProxy);
Brian Salomon031b0ba2019-05-23 11:05:26 -04002022 srcRectToDraw = SkRect::MakeWH(srcRect.width(), srcRect.height());
2023 }
2024 rtc = direct->priv().makeDeferredRenderTargetContext(
2025 backendFormat, SkBackingFit::kApprox, srcRect.width(), srcRect.height(),
2026 fRenderTargetProxy->config(), info.refColorSpace(), 1, GrMipMapped::kNo,
2027 kTopLeft_GrSurfaceOrigin);
2028 if (!rtc) {
2029 callback(context, nullptr, 0);
2030 return;
2031 }
2032 rtc->drawTexture(GrNoClip(), std::move(texProxy), GrSamplerState::Filter::kNearest,
2033 SkBlendMode::kSrc, SK_PMColor4fWHITE, srcRectToDraw,
2034 SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
2035 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
2036 std::move(xform));
2037 x = y = 0;
2038 } else {
2039 rtc = sk_ref_sp(this);
2040 }
2041 }
2042 return rtc->asyncReadPixels(info, x, y, callback, context);
2043}
2044
2045void GrRenderTargetContext::asyncReadPixels(const SkImageInfo& info, int x, int y,
2046 ReadPixelsCallback callback,
2047 ReadPixelsContext context) {
2048 SkASSERT(info.width() + x <= this->width());
2049 SkASSERT(info.height() + y <= this->height());
2050 auto direct = fContext->priv().asDirectContext();
2051 if (!direct) {
2052 callback(context, nullptr, 0);
2053 return;
2054 }
2055 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
2056 callback(context, nullptr, 0);
2057 return;
2058 }
2059 // We currently don't know our own alpha type, we assume it's premul if we have an alpha channel
2060 // and opaque otherwise.
2061 if (!GrPixelConfigIsAlphaOnly(fRenderTargetProxy->config()) &&
2062 info.alphaType() != kPremul_SkAlphaType) {
2063 callback(context, nullptr, 0);
2064 return;
Brian Salomonab32f652019-05-10 14:24:50 -04002065 }
Brian Salomon201700f2019-05-17 12:05:44 -04002066 auto dstCT = SkColorTypeToGrColorType(info.colorType());
Brian Salomonab32f652019-05-10 14:24:50 -04002067 auto readCT = this->caps()->supportedReadPixelsColorType(fRenderTargetProxy->config(), dstCT);
Brian Salomoncd734f62019-05-10 16:32:54 -04002068 // Fail if we can't do a CPU conversion from readCT to dstCT.
2069 if (GrColorTypeToSkColorType(readCT) == kUnknown_SkColorType) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04002070 callback(context, nullptr, 0);
2071 return;
Brian Salomonab32f652019-05-10 14:24:50 -04002072 }
Brian Salomoncd734f62019-05-10 16:32:54 -04002073 // Fail if readCT does not have all of readCT's color channels.
2074 if (GrColorTypeComponentFlags(dstCT) & ~GrColorTypeComponentFlags(readCT)) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04002075 callback(context, nullptr, 0);
2076 return;
Brian Salomonab32f652019-05-10 14:24:50 -04002077 }
2078
Brian Salomon031b0ba2019-05-23 11:05:26 -04002079 if (!this->caps()->transferBufferSupport() ||
2080 !this->caps()->transferFromOffsetAlignment(readCT)) {
2081 SkAutoPixmapStorage pm;
2082 pm.alloc(info);
2083 if (!this->readPixels(info, pm.writable_addr(), pm.rowBytes(), x, y)) {
2084 callback(context, nullptr, 0);
Brian Salomonab32f652019-05-10 14:24:50 -04002085 }
Brian Salomon031b0ba2019-05-23 11:05:26 -04002086 callback(context, pm.addr(), pm.rowBytes());
2087 return;
Brian Salomonab32f652019-05-10 14:24:50 -04002088 }
Brian Salomoncd734f62019-05-10 16:32:54 -04002089
Brian Salomon031b0ba2019-05-23 11:05:26 -04002090 size_t rowBytes = GrColorTypeBytesPerPixel(readCT) * info.width();
2091 size_t size = rowBytes * info.height();
Brian Salomonab32f652019-05-10 14:24:50 -04002092 auto buffer = direct->priv().resourceProvider()->createBuffer(
2093 size, GrGpuBufferType::kXferGpuToCpu, GrAccessPattern::kStream_GrAccessPattern);
2094 if (!buffer) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04002095 callback(context, nullptr, 0);
2096 return;
Brian Salomonab32f652019-05-10 14:24:50 -04002097 }
Brian Salomon031b0ba2019-05-23 11:05:26 -04002098 this->getRTOpList()->addOp(
2099 GrTransferFromOp::Make(fContext, SkIRect::MakeXYWH(x, y, info.width(), info.height()),
2100 readCT, buffer, 0),
2101 *this->caps());
Brian Salomonab32f652019-05-10 14:24:50 -04002102 struct FinishContext {
Brian Salomoncd734f62019-05-10 16:32:54 -04002103 SkImageInfo fReadInfo;
2104 SkImageInfo fDstInfo;
Brian Salomonab32f652019-05-10 14:24:50 -04002105 ReadPixelsCallback* fClientCallback;
2106 ReadPixelsContext fClientContext;
2107 sk_sp<GrGpuBuffer> fBuffer;
2108 size_t fRowBytes;
2109 };
Brian Salomon201700f2019-05-17 12:05:44 -04002110 const auto readInfo = info.makeColorType(GrColorTypeToSkColorType(readCT));
Brian Salomonab32f652019-05-10 14:24:50 -04002111 // Assumption is that the caller would like to flush. We could take a parameter or require an
2112 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
2113 // callback to GrGpu until after the next flush that flushes our op list, though.
Brian Salomon201700f2019-05-17 12:05:44 -04002114 auto* finishContext = new FinishContext{readInfo, info, callback, context, buffer, rowBytes};
Brian Salomonab32f652019-05-10 14:24:50 -04002115 auto finishCallback = [](GrGpuFinishedContext c) {
2116 auto context = reinterpret_cast<const FinishContext*>(c);
2117 void* data = context->fBuffer->map();
Brian Salomoncd734f62019-05-10 16:32:54 -04002118 if (!data) {
2119 (*context->fClientCallback)(context->fClientContext, nullptr, 0);
2120 delete context;
2121 return;
2122 }
2123 SkAutoPixmapStorage pm;
2124 const void* callbackData = data;
2125 size_t callbackRowBytes = context->fRowBytes;
2126 if (context->fDstInfo != context->fReadInfo) {
2127 pm.alloc(context->fDstInfo);
2128 SkConvertPixels(context->fDstInfo, pm.writable_addr(), pm.rowBytes(),
2129 context->fReadInfo, data, context->fRowBytes);
2130 callbackData = pm.addr();
2131 callbackRowBytes = pm.rowBytes();
2132 }
2133 (*context->fClientCallback)(context->fClientContext, callbackData, callbackRowBytes);
Brian Salomonab32f652019-05-10 14:24:50 -04002134 if (data) {
2135 context->fBuffer->unmap();
2136 }
2137 delete context;
2138 };
2139 GrFlushInfo flushInfo;
2140 flushInfo.fFinishedContext = finishContext;
2141 flushInfo.fFinishedProc = finishCallback;
2142 this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
Brian Salomonab32f652019-05-10 14:24:50 -04002143}
2144
Greg Daniele6bfb7d2019-04-17 15:26:11 -04002145GrSemaphoresSubmitted GrRenderTargetContext::flush(SkSurface::BackendSurfaceAccess access,
2146 const GrFlushInfo& info) {
robertphillips8c523e02016-07-26 07:41:00 -07002147 ASSERT_SINGLE_OWNER
Robert Phillips6a6de562019-02-15 15:19:15 -05002148 if (fContext->priv().abandoned()) {
Robert Phillipsa9162df2019-02-11 14:12:03 -05002149 return GrSemaphoresSubmitted::kNo;
2150 }
robertphillips8c523e02016-07-26 07:41:00 -07002151 SkDEBUGCODE(this->validate();)
Robert Phillips15c91422019-05-07 16:54:48 -04002152 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "flush", fContext);
robertphillips8c523e02016-07-26 07:41:00 -07002153
Greg Daniele6bfb7d2019-04-17 15:26:11 -04002154 return this->drawingManager()->flushSurface(fRenderTargetProxy.get(), access, info);
Greg Daniela5cb7812017-06-16 09:45:32 -04002155}
2156
Greg Danielc64ee462017-06-15 16:59:49 -04002157bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
Robert Phillipsbc4994a2019-02-14 08:36:56 -05002158 const GrBackendSemaphore waitSemaphores[]) {
Greg Daniela5cb7812017-06-16 09:45:32 -04002159 ASSERT_SINGLE_OWNER
Greg Danielc64ee462017-06-15 16:59:49 -04002160 RETURN_FALSE_IF_ABANDONED
Greg Daniela5cb7812017-06-16 09:45:32 -04002161 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04002162 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "waitOnSemaphores", fContext);
Greg Daniela5cb7812017-06-16 09:45:32 -04002163
2164 AutoCheckFlush acf(this->drawingManager());
2165
Brian Salomon9ff5acb2019-05-08 09:04:47 -04002166 if (numSemaphores && !this->caps()->semaphoreSupport()) {
Greg Danielc64ee462017-06-15 16:59:49 -04002167 return false;
2168 }
2169
Robert Phillipsbc4994a2019-02-14 08:36:56 -05002170 auto direct = fContext->priv().asDirectContext();
2171 if (!direct) {
2172 return false;
2173 }
2174
2175 auto resourceProvider = direct->priv().resourceProvider();
Robert Phillips6be756b2018-01-16 15:07:54 -05002176
Greg Daniela5cb7812017-06-16 09:45:32 -04002177 for (int i = 0; i < numSemaphores; ++i) {
Robert Phillips6be756b2018-01-16 15:07:54 -05002178 sk_sp<GrSemaphore> sema = resourceProvider->wrapBackendSemaphore(
Greg Daniel17b7c052018-01-09 13:55:33 -05002179 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
2180 kAdopt_GrWrapOwnership);
Robert Phillipsbc4994a2019-02-14 08:36:56 -05002181 std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(fContext, std::move(sema),
Robert Phillips7c525e62018-06-12 10:11:12 -04002182 fRenderTargetProxy.get()));
Greg Danielcb324152019-02-25 11:36:53 -05002183 this->getRTOpList()->addWaitOp(std::move(waitOp), *this->caps());
Greg Daniela5cb7812017-06-16 09:45:32 -04002184 }
Greg Danielc64ee462017-06-15 16:59:49 -04002185 return true;
robertphillips8c523e02016-07-26 07:41:00 -07002186}
joshualitt33a5fce2015-11-18 13:28:51 -08002187
Robert Phillips65a88fa2017-08-08 08:36:22 -04002188void GrRenderTargetContext::insertEventMarker(const SkString& str) {
Robert Phillips88a32ef2018-06-07 11:05:56 -04002189 std::unique_ptr<GrOp> op(GrDebugMarkerOp::Make(fContext, fRenderTargetProxy.get(), str));
Robert Phillips65a88fa2017-08-08 08:36:22 -04002190 this->getRTOpList()->addOp(std::move(op), *this->caps());
2191}
2192
Robert Phillipsbe9aff22019-02-15 11:33:22 -05002193const GrCaps* GrRenderTargetContext::caps() const {
2194 return fContext->priv().caps();
2195}
2196
Brian Osman11052242016-10-27 14:47:55 -04002197void GrRenderTargetContext::drawPath(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05002198 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002199 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04002200 const SkMatrix& viewMatrix,
Brian Salomon40b77a62017-12-22 11:25:52 -05002201 const SkPath& path,
Brian Osman11052242016-10-27 14:47:55 -04002202 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08002203 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07002204 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07002205 SkDEBUGCODE(this->validate();)
Robert Phillips20390c32018-08-17 11:01:03 -04002206 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPath", fContext);
2207
Brian Salomon40b77a62017-12-22 11:25:52 -05002208 GrShape shape(path, style);
Robert Phillips20390c32018-08-17 11:01:03 -04002209
Robert Phillips27927a52018-08-20 13:18:12 -04002210 this->drawShape(clip, std::move(paint), aa, viewMatrix, shape);
Robert Phillips20390c32018-08-17 11:01:03 -04002211}
2212
2213void GrRenderTargetContext::drawShape(const GrClip& clip,
2214 GrPaint&& paint,
2215 GrAA aa,
2216 const SkMatrix& viewMatrix,
2217 const GrShape& shape) {
2218 ASSERT_SINGLE_OWNER
2219 RETURN_IF_ABANDONED
2220 SkDEBUGCODE(this->validate();)
2221 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawShape", fContext);
2222
Brian Salomon2fad74a2017-12-20 13:28:55 -05002223 if (shape.isEmpty()) {
2224 if (shape.inverseFilled()) {
2225 this->drawPaint(clip, std::move(paint), viewMatrix);
2226 }
2227 return;
robertphillipsea461502015-05-26 11:38:03 -07002228 }
2229
Robert Phillips72152832017-01-25 17:31:35 -05002230 AutoCheckFlush acf(this->drawingManager());
robertphillipsea461502015-05-26 11:38:03 -07002231
Brian Salomon2fad74a2017-12-20 13:28:55 -05002232 if (!shape.style().hasPathEffect()) {
Chris Dalton7d6748e2019-03-13 00:34:52 -06002233 GrAAType aaType = this->chooseAAType(aa);
Brian Salomon2fad74a2017-12-20 13:28:55 -05002234 SkRRect rrect;
2235 // We can ignore the starting point and direction since there is no path effect.
2236 bool inverted;
2237 if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
2238 if (rrect.isRect()) {
2239 this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(),
2240 &shape.style());
2241 return;
2242 } else if (rrect.isOval()) {
2243 this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style());
robertphillipsea461502015-05-26 11:38:03 -07002244 return;
2245 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002246 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style());
2247 return;
Robert Phillips73653b42018-08-22 12:42:42 -04002248 } else if (GrAAType::kCoverage == aaType && shape.style().isSimpleFill() &&
2249 viewMatrix.rectStaysRect()) {
2250 // TODO: the rectStaysRect restriction could be lifted if we were willing to apply
2251 // the matrix to all the points individually rather than just to the rect
2252 SkRect rects[2];
2253 if (shape.asNestedRects(rects)) {
2254 // Concave AA paths are expensive - try to avoid them for special cases
Michael Ludwig72ab3462018-12-10 12:43:36 -05002255 std::unique_ptr<GrDrawOp> op = GrStrokeRectOp::MakeNested(
Robert Phillips73653b42018-08-22 12:42:42 -04002256 fContext, std::move(paint), viewMatrix, rects);
2257 if (op) {
2258 this->addDrawOp(clip, std::move(op));
2259 }
2260 // Returning here indicates that there is nothing to draw in this case.
2261 return;
2262 }
robertphillipsea461502015-05-26 11:38:03 -07002263 }
2264 }
robertphillips4bc31812016-03-01 12:22:49 -08002265
Brian Salomon2fad74a2017-12-20 13:28:55 -05002266 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape);
robertphillipsea461502015-05-26 11:38:03 -07002267}
2268
Chris Daltonbbfd5162017-11-07 13:35:22 -07002269bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
Brian Osman11052242016-10-27 14:47:55 -04002270 const GrUserStencilSettings* ss,
2271 SkRegion::Op op,
2272 bool invert,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002273 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04002274 const SkMatrix& viewMatrix,
2275 const SkPath& path) {
robertphillips391395d2016-03-02 09:26:36 -08002276 ASSERT_SINGLE_OWNER_PRIV
2277 RETURN_FALSE_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -04002278 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04002279 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilPath",
2280 fRenderTargetContext->fContext);
robertphillips391395d2016-03-02 09:26:36 -08002281
2282 if (path.isEmpty() && path.isInverseFillType()) {
Michael Ludwigaa1b6b32019-05-29 14:43:13 -04002283 GrPaint paint;
2284 paint.setCoverageSetOpXPFactory(op, invert);
2285 this->stencilRect(clip, ss, std::move(paint), GrAA::kNo, SkMatrix::I(),
2286 SkRect::MakeIWH(fRenderTargetContext->width(),
2287 fRenderTargetContext->height()));
robertphillips391395d2016-03-02 09:26:36 -08002288 return true;
2289 }
2290
Robert Phillips72152832017-01-25 17:31:35 -05002291 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
robertphillips391395d2016-03-02 09:26:36 -08002292
2293 // An Assumption here is that path renderer would use some form of tweaking
2294 // the src color (either the input alpha or in the frag shader) to implement
2295 // aa. If we have some future driver-mojo path AA that can do the right
2296 // thing WRT to the blend then we'll need some query on the PR.
Chris Dalton09e56892019-03-13 00:22:01 -06002297 auto aaTypeFlags = choose_path_aa_type_flags(
2298 aa, fRenderTargetContext->fsaaType(), *fRenderTargetContext->caps());
robertphillips976f5f02016-06-03 10:59:20 -07002299 bool hasUserStencilSettings = !ss->isUnused();
robertphillips391395d2016-03-02 09:26:36 -08002300
Chris Daltondb91c6e2017-09-08 16:25:08 -06002301 SkIRect clipConservativeBounds;
2302 clip.getConservativeBounds(fRenderTargetContext->width(), fRenderTargetContext->height(),
2303 &clipConservativeBounds, nullptr);
2304
bsalomon8acedde2016-06-24 10:42:16 -07002305 GrShape shape(path, GrStyle::SimpleFill());
robertphillips391395d2016-03-02 09:26:36 -08002306 GrPathRenderer::CanDrawPathArgs canDrawArgs;
Brian Salomonc7fe0f72018-05-11 10:14:21 -04002307 canDrawArgs.fCaps = fRenderTargetContext->caps();
robertphillips391395d2016-03-02 09:26:36 -08002308 canDrawArgs.fViewMatrix = &viewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -07002309 canDrawArgs.fShape = &shape;
Chris Daltondb91c6e2017-09-08 16:25:08 -06002310 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
Chris Dalton09e56892019-03-13 00:22:01 -06002311 canDrawArgs.fAATypeFlags = aaTypeFlags;
Greg Danielbe7fc462019-01-03 16:40:42 -05002312 SkASSERT(!fRenderTargetContext->wrapsVkSecondaryCB());
2313 canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
cdalton93a379b2016-05-11 13:58:08 -07002314 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
robertphillips391395d2016-03-02 09:26:36 -08002315
2316 // Don't allow the SW renderer
Robert Phillips72152832017-01-25 17:31:35 -05002317 GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer(
Brian Salomon36aa1762016-12-10 13:24:02 -05002318 canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor);
robertphillips391395d2016-03-02 09:26:36 -08002319 if (!pr) {
2320 return false;
2321 }
2322
2323 GrPaint paint;
2324 paint.setCoverageSetOpXPFactory(op, invert);
2325
Brian Salomonf3569f02017-10-24 12:52:33 -04002326 GrPathRenderer::DrawPathArgs args{fRenderTargetContext->drawingManager()->getContext(),
2327 std::move(paint),
2328 ss,
2329 fRenderTargetContext,
2330 &clip,
2331 &clipConservativeBounds,
2332 &viewMatrix,
2333 &shape,
Chris Dalton09e56892019-03-13 00:22:01 -06002334 aaTypeFlags,
Brian Osman34ec3742018-07-03 10:40:57 -04002335 fRenderTargetContext->colorSpaceInfo().isLinearlyBlended()};
robertphillips391395d2016-03-02 09:26:36 -08002336 pr->drawPath(args);
2337 return true;
2338}
2339
Brian Osman11052242016-10-27 14:47:55 -04002340SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
robertphillips714712b2016-08-04 06:20:45 -07002341 ASSERT_SINGLE_OWNER_PRIV
2342
Robert Phillips6a6de562019-02-15 15:19:15 -05002343 if (fRenderTargetContext->fContext->priv().abandoned()) {
robertphillips714712b2016-08-04 06:20:45 -07002344 return SkBudgeted::kNo;
2345 }
2346
Brian Osman11052242016-10-27 14:47:55 -04002347 SkDEBUGCODE(fRenderTargetContext->validate();)
robertphillips714712b2016-08-04 06:20:45 -07002348
Robert Phillipsc7635fa2016-10-28 13:25:24 -04002349 return fRenderTargetContext->fRenderTargetProxy->isBudgeted();
robertphillips714712b2016-08-04 06:20:45 -07002350}
2351
Brian Salomon2fad74a2017-12-20 13:28:55 -05002352void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
2353 GrPaint&& paint,
2354 GrAA aa,
2355 const SkMatrix& viewMatrix,
2356 const GrShape& originalShape) {
joshualitt1de610a2016-01-06 08:26:09 -08002357 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07002358 RETURN_IF_ABANDONED
Brian Salomondcbb9d92017-07-19 10:53:20 -04002359 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext);
2360
Jim Van Verthf86073a2018-10-02 13:05:38 -04002361 if (!viewMatrix.isFinite() || !originalShape.bounds().isFinite()) {
2362 return;
2363 }
2364
Chris Daltondb91c6e2017-09-08 16:25:08 -06002365 SkIRect clipConservativeBounds;
2366 clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
2367
Brian Salomon2fad74a2017-12-20 13:28:55 -05002368 GrShape tempShape;
Chris Dalton09e56892019-03-13 00:22:01 -06002369 auto aaTypeFlags = choose_path_aa_type_flags(aa, this->fsaaType(), *this->caps());
2370
robertphillips68737822015-10-29 12:12:21 -07002371 GrPathRenderer::CanDrawPathArgs canDrawArgs;
Brian Salomonc7fe0f72018-05-11 10:14:21 -04002372 canDrawArgs.fCaps = this->caps();
robertphillips68737822015-10-29 12:12:21 -07002373 canDrawArgs.fViewMatrix = &viewMatrix;
Brian Salomon2fad74a2017-12-20 13:28:55 -05002374 canDrawArgs.fShape = &originalShape;
Chris Daltondb91c6e2017-09-08 16:25:08 -06002375 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
Greg Danielbe7fc462019-01-03 16:40:42 -05002376 canDrawArgs.fTargetIsWrappedVkSecondaryCB = this->wrapsVkSecondaryCB();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002377 canDrawArgs.fHasUserStencilSettings = false;
robertphillips68737822015-10-29 12:12:21 -07002378
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002379 GrPathRenderer* pr;
Brian Salomon82125e92016-12-10 09:35:48 -05002380 static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
Brian Salomon2fad74a2017-12-20 13:28:55 -05002381 if (originalShape.isEmpty() && !originalShape.inverseFilled()) {
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002382 return;
2383 }
2384
Chris Dalton09e56892019-03-13 00:22:01 -06002385 canDrawArgs.fAATypeFlags = aaTypeFlags;
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002386
2387 // Try a 1st time without applying any of the style to the geometry (and barring sw)
2388 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
2389 SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
2390
Brian Salomon2fad74a2017-12-20 13:28:55 -05002391 if (!pr && originalShape.style().pathEffect()) {
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002392 // It didn't work above, so try again with the path effect applied.
Brian Salomon2fad74a2017-12-20 13:28:55 -05002393 tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
2394 if (tempShape.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07002395 return;
2396 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002397 canDrawArgs.fShape = &tempShape;
Robert Phillips72152832017-01-25 17:31:35 -05002398 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002399 }
2400 if (!pr) {
Brian Salomon2fad74a2017-12-20 13:28:55 -05002401 if (canDrawArgs.fShape->style().applies()) {
2402 tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec,
2403 styleScale);
2404 if (tempShape.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07002405 return;
2406 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002407 canDrawArgs.fShape = &tempShape;
Brian Salomone7df0bb2018-05-07 14:44:57 -04002408 // This time, allow SW renderer
2409 pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
2410 } else {
2411 pr = this->drawingManager()->getSoftwarePathRenderer();
bsalomon6663acf2016-05-10 09:14:17 -07002412 }
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002413 }
robertphillipsea461502015-05-26 11:38:03 -07002414
bsalomon8acedde2016-06-24 10:42:16 -07002415 if (!pr) {
robertphillipsea461502015-05-26 11:38:03 -07002416#ifdef SK_DEBUG
2417 SkDebugf("Unable to find path renderer compatible with path.\n");
2418#endif
2419 return;
2420 }
2421
Robert Phillips256c37b2017-03-01 14:32:46 -05002422 GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
Brian Salomon82f44312017-01-11 13:42:54 -05002423 std::move(paint),
2424 &GrUserStencilSettings::kUnused,
2425 this,
2426 &clip,
Chris Daltondb91c6e2017-09-08 16:25:08 -06002427 &clipConservativeBounds,
Brian Salomon82f44312017-01-11 13:42:54 -05002428 &viewMatrix,
Brian Salomon2fad74a2017-12-20 13:28:55 -05002429 canDrawArgs.fShape,
Chris Dalton09e56892019-03-13 00:22:01 -06002430 aaTypeFlags,
Brian Osman34ec3742018-07-03 10:40:57 -04002431 this->colorSpaceInfo().isLinearlyBlended()};
bsalomon0aff2fa2015-07-31 06:48:27 -07002432 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -07002433}
2434
Brian Salomon467921e2017-03-06 16:17:12 -05002435static void op_bounds(SkRect* bounds, const GrOp* op) {
2436 *bounds = op->bounds();
2437 if (op->hasZeroArea()) {
2438 if (op->hasAABloat()) {
2439 bounds->outset(0.5f, 0.5f);
2440 } else {
2441 // We don't know which way the particular GPU will snap lines or points at integer
2442 // coords. So we ensure that the bounds is large enough for either snap.
2443 SkRect before = *bounds;
2444 bounds->roundOut(bounds);
2445 if (bounds->fLeft == before.fLeft) {
2446 bounds->fLeft -= 1;
2447 }
2448 if (bounds->fTop == before.fTop) {
2449 bounds->fTop -= 1;
2450 }
2451 if (bounds->fRight == before.fRight) {
2452 bounds->fRight += 1;
2453 }
2454 if (bounds->fBottom == before.fBottom) {
2455 bounds->fBottom += 1;
2456 }
2457 }
2458 }
2459}
2460
Brian Salomon348a0372018-10-31 10:42:18 -04002461void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op,
2462 const std::function<WillAddOpFn>& willAddFn) {
joshualitt1de610a2016-01-06 08:26:09 -08002463 ASSERT_SINGLE_OWNER
Robert Phillips69893702019-02-22 11:16:30 -05002464 if (fContext->priv().abandoned()) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002465 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002466 return;
Robert Phillipsc0138922017-03-08 11:50:55 -05002467 }
robertphillips2e1e51f2015-10-15 08:01:48 -07002468 SkDEBUGCODE(this->validate();)
Ethan Nicholas029b22c2018-10-18 16:49:56 -04002469 SkDEBUGCODE(op->fAddDrawOpCalled = true;)
Brian Salomondcbb9d92017-07-19 10:53:20 -04002470 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "addDrawOp", fContext);
robertphillips2d70dcb2015-10-06 07:38:23 -07002471
Brian Salomon467921e2017-03-06 16:17:12 -05002472 // Setup clip
2473 SkRect bounds;
2474 op_bounds(&bounds, op.get());
Brian Salomon97180af2017-03-14 13:42:58 -04002475 GrAppliedClip appliedClip;
Brian Salomon54d212e2017-03-21 14:22:38 -04002476 GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags();
2477 if (!clip.apply(fContext, this, fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA,
2478 fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil, &appliedClip,
2479 &bounds)) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002480 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002481 return;
Brian Salomon54d212e2017-03-21 14:22:38 -04002482 }
2483
Michael Ludwig6e17f1d2019-05-15 14:00:20 +00002484 if (fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil ||
2485 appliedClip.hasStencilClip()) {
2486 if (this->caps()->performStencilClearsAsDraws()) {
2487 // Must use an op to perform the clear of the stencil buffer before this op, but only
2488 // have to clear the first time any draw needs it (this also ensures we don't loop
2489 // forever when the internal stencil clear adds a draw op that has stencil settings).
2490 if (!fRenderTargetProxy->needsStencil()) {
2491 // Send false so that the stencil buffer is fully cleared to 0
Michael Ludwigc39d0c82019-01-15 10:03:43 -05002492 this->internalStencilClear(GrFixedClip::Disabled(), /* inside mask */ false);
2493 }
Michael Ludwig6e17f1d2019-05-15 14:00:20 +00002494 } else {
2495 // Just make sure the stencil buffer is cleared before the draw op, easy to do it as
2496 // a load at the start
2497 this->getRTOpList()->setStencilLoadOp(GrLoadOp::kClear);
Michael Ludwigc39d0c82019-01-15 10:03:43 -05002498 }
Robert Phillips95214472017-08-08 18:00:03 -04002499
Robert Phillips65048132017-08-10 08:44:49 -04002500 this->setNeedsStencil();
Brian Salomon54d212e2017-03-21 14:22:38 -04002501 }
2502
Brian Osman5ced0bf2019-03-15 10:15:29 -04002503 GrClampType clampType = GrPixelConfigClampType(this->colorSpaceInfo().config());
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002504 GrXferProcessor::DstProxy dstProxy;
Brian Osman5ced0bf2019-03-15 10:15:29 -04002505 GrProcessorSet::Analysis analysis = op->finalize(
2506 *this->caps(), &appliedClip, this->fsaaType(), clampType);
Chris Dalton945ee652019-01-23 09:10:36 -07002507 if (analysis.requiresDstTexture()) {
Brian Salomon09181ef2018-11-14 13:39:51 -05002508 if (!this->setupDstProxy(this->asRenderTargetProxy(), clip, *op, &dstProxy)) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002509 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002510 return;
Brian Salomon54d212e2017-03-21 14:22:38 -04002511 }
2512 }
2513
2514 op->setClippedBounds(bounds);
Brian Salomon348a0372018-10-31 10:42:18 -04002515 auto opList = this->getRTOpList();
2516 if (willAddFn) {
2517 willAddFn(op.get(), opList->uniqueID());
2518 }
Chris Dalton945ee652019-01-23 09:10:36 -07002519 opList->addDrawOp(std::move(op), analysis, std::move(appliedClip), dstProxy, *this->caps());
Brian Salomon54d212e2017-03-21 14:22:38 -04002520}
2521
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002522bool GrRenderTargetContext::setupDstProxy(GrRenderTargetProxy* rtProxy, const GrClip& clip,
Brian Salomon09181ef2018-11-14 13:39:51 -05002523 const GrOp& op,
Robert Phillips16d8ec62017-07-27 16:16:25 -04002524 GrXferProcessor::DstProxy* dstProxy) {
Greg Danielbe7fc462019-01-03 16:40:42 -05002525 // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
2526 // don't actually have a VkImage to make a copy of. Additionally we don't have the power to
2527 // start and stop the render pass in order to make the copy.
2528 if (rtProxy->wrapsVkSecondaryCB()) {
2529 return false;
2530 }
2531
Brian Salomon467921e2017-03-06 16:17:12 -05002532 if (this->caps()->textureBarrierSupport()) {
Robert Phillipsbf25d432017-04-07 10:08:53 -04002533 if (GrTextureProxy* texProxy = rtProxy->asTextureProxy()) {
Brian Salomon467921e2017-03-06 16:17:12 -05002534 // The render target is a texture, so we can read from it directly in the shader. The XP
2535 // will be responsible to detect this situation and request a texture barrier.
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002536 dstProxy->setProxy(sk_ref_sp(texProxy));
2537 dstProxy->setOffset(0, 0);
Robert Phillipsbf25d432017-04-07 10:08:53 -04002538 return true;
Brian Salomon467921e2017-03-06 16:17:12 -05002539 }
2540 }
2541
Robert Phillipsbf25d432017-04-07 10:08:53 -04002542 SkIRect copyRect = SkIRect::MakeWH(rtProxy->width(), rtProxy->height());
Brian Salomon467921e2017-03-06 16:17:12 -05002543
Eric Karl74480882017-04-03 14:49:05 -07002544 SkIRect clippedRect;
Robert Phillipsbf25d432017-04-07 10:08:53 -04002545 clip.getConservativeBounds(rtProxy->width(), rtProxy->height(), &clippedRect);
Brian Salomon09181ef2018-11-14 13:39:51 -05002546 SkRect opBounds = op.bounds();
2547 // If the op has aa bloating or is a infinitely thin geometry (hairline) outset the bounds by
2548 // 0.5 pixels.
2549 if (op.hasAABloat() || op.hasZeroArea()) {
2550 opBounds.outset(0.5f, 0.5f);
2551 // An antialiased/hairline draw can sometimes bleed outside of the clips bounds. For
2552 // performance we may ignore the clip when the draw is entirely inside the clip is float
2553 // space but will hit pixels just outside the clip when actually rasterizing.
2554 clippedRect.outset(1, 1);
2555 clippedRect.intersect(SkIRect::MakeWH(rtProxy->width(), rtProxy->height()));
2556 }
2557 SkIRect opIBounds;
2558 opBounds.roundOut(&opIBounds);
2559 if (!clippedRect.intersect(opIBounds)) {
Brian Salomon467921e2017-03-06 16:17:12 -05002560#ifdef SK_DEBUG
Robert Phillipsbf25d432017-04-07 10:08:53 -04002561 GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw.");
Brian Salomon467921e2017-03-06 16:17:12 -05002562#endif
Robert Phillipsbf25d432017-04-07 10:08:53 -04002563 return false;
Brian Salomon467921e2017-03-06 16:17:12 -05002564 }
2565
2566 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
2567 // have per-sample dst values by making the copy multisampled.
2568 GrSurfaceDesc desc;
Eric Karl74480882017-04-03 14:49:05 -07002569 bool rectsMustMatch = false;
2570 bool disallowSubrect = false;
Greg Danielc5167c02019-06-05 17:36:53 +00002571 GrSurfaceOrigin origin;
2572 if (!this->caps()->initDescForDstCopy(rtProxy, &desc, &origin, &rectsMustMatch,
Brian Salomon2a4f9832018-03-03 22:43:43 -05002573 &disallowSubrect)) {
Brian Salomon467921e2017-03-06 16:17:12 -05002574 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillipsbf25d432017-04-07 10:08:53 -04002575 desc.fConfig = rtProxy->config();
Greg Danielc5167c02019-06-05 17:36:53 +00002576 origin = rtProxy->origin();
Brian Salomon467921e2017-03-06 16:17:12 -05002577 }
2578
Eric Karl74480882017-04-03 14:49:05 -07002579 if (!disallowSubrect) {
2580 copyRect = clippedRect;
2581 }
Brian Salomon467921e2017-03-06 16:17:12 -05002582
Robert Phillipsbf25d432017-04-07 10:08:53 -04002583 SkIPoint dstPoint, dstOffset;
2584 SkBackingFit fit;
Eric Karl74480882017-04-03 14:49:05 -07002585 if (rectsMustMatch) {
Robert Phillipsbf25d432017-04-07 10:08:53 -04002586 desc.fWidth = rtProxy->width();
2587 desc.fHeight = rtProxy->height();
Eric Karl74480882017-04-03 14:49:05 -07002588 dstPoint = {copyRect.fLeft, copyRect.fTop};
2589 dstOffset = {0, 0};
Robert Phillipsbf25d432017-04-07 10:08:53 -04002590 fit = SkBackingFit::kExact;
Eric Karl74480882017-04-03 14:49:05 -07002591 } else {
2592 desc.fWidth = copyRect.width();
2593 desc.fHeight = copyRect.height();
2594 dstPoint = {0, 0};
2595 dstOffset = {copyRect.fLeft, copyRect.fTop};
Robert Phillipsbf25d432017-04-07 10:08:53 -04002596 fit = SkBackingFit::kApprox;
Eric Karl74480882017-04-03 14:49:05 -07002597 }
Brian Salomon467921e2017-03-06 16:17:12 -05002598
Greg Danielc5167c02019-06-05 17:36:53 +00002599 SkASSERT(rtProxy->backendFormat().textureType() == GrTextureType::k2D);
2600 const GrBackendFormat& format = rtProxy->backendFormat();
2601 sk_sp<GrSurfaceContext> sContext = fContext->priv().makeDeferredSurfaceContext(
2602 format, desc, origin, GrMipMapped::kNo, fit, SkBudgeted::kYes,
2603 sk_ref_sp(this->colorSpaceInfo().colorSpace()));
2604 if (!sContext) {
2605 SkDebugf("setupDstTexture: surfaceContext creation failed.\n");
2606 return false;
2607 }
Robert Phillipsbf25d432017-04-07 10:08:53 -04002608
Greg Danielc5167c02019-06-05 17:36:53 +00002609 if (!sContext->copy(rtProxy, copyRect, dstPoint)) {
2610 SkDebugf("setupDstTexture: copy failed.\n");
2611 return false;
2612 }
2613
2614 dstProxy->setProxy(sContext->asTextureProxyRef());
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002615 dstProxy->setOffset(dstOffset);
Robert Phillipsbf25d432017-04-07 10:08:53 -04002616 return true;
robertphillips2334fb62015-06-17 05:43:33 -07002617}