blob: a6fb9a47b64e48e9c822175f32490f9f65adb57e [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 Salomonf30b1c12019-06-20 12:25:02 -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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/private/GrRecordingContext.h"
13#include "include/private/SkShadowFlags.h"
14#include "include/utils/SkShadowUtils.h"
Brian Salomoncd734f62019-05-10 16:32:54 -040015#include "src/core/SkAutoPixmapStorage.h"
16#include "src/core/SkConvertPixels.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/core/SkDrawShadowInfo.h"
18#include "src/core/SkGlyphRunPainter.h"
19#include "src/core/SkLatticeIter.h"
20#include "src/core/SkMatrixPriv.h"
21#include "src/core/SkRRectPriv.h"
22#include "src/core/SkSurfacePriv.h"
23#include "src/gpu/GrAppliedClip.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040024#include "src/gpu/GrAuditTrail.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050025#include "src/gpu/GrBlurUtils.h"
26#include "src/gpu/GrCaps.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040027#include "src/gpu/GrColor.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050028#include "src/gpu/GrContextPriv.h"
Brian Salomonf30b1c12019-06-20 12:25:02 -040029#include "src/gpu/GrDataUtils.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050030#include "src/gpu/GrDrawingManager.h"
31#include "src/gpu/GrFixedClip.h"
32#include "src/gpu/GrGpuResourcePriv.h"
33#include "src/gpu/GrMemoryPool.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040034#include "src/gpu/GrOpList.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050035#include "src/gpu/GrPathRenderer.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050036#include "src/gpu/GrRecordingContextPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050037#include "src/gpu/GrRenderTargetContextPriv.h"
Chris Dalton6b982802019-06-27 13:53:46 -060038#include "src/gpu/GrRenderTargetProxyPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050039#include "src/gpu/GrResourceProvider.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050040#include "src/gpu/GrStencilAttachment.h"
41#include "src/gpu/GrStyle.h"
42#include "src/gpu/GrTracing.h"
43#include "src/gpu/SkGr.h"
Brian Salomon031b0ba2019-05-23 11:05:26 -040044#include "src/gpu/effects/GrBicubicEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050045#include "src/gpu/effects/GrRRectEffect.h"
46#include "src/gpu/effects/GrTextureDomain.h"
Brian Salomon024bd002019-06-11 11:38:16 -040047#include "src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h"
Michael Ludwigfd4f4df2019-05-29 09:51:09 -040048#include "src/gpu/geometry/GrQuad.h"
Michael Ludwig61328202019-06-19 14:48:58 +000049#include "src/gpu/geometry/GrQuadUtils.h"
Michael Ludwig663afe52019-06-03 16:46:19 -040050#include "src/gpu/geometry/GrShape.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050051#include "src/gpu/ops/GrAtlasTextOp.h"
52#include "src/gpu/ops/GrClearOp.h"
53#include "src/gpu/ops/GrClearStencilClipOp.h"
54#include "src/gpu/ops/GrDebugMarkerOp.h"
55#include "src/gpu/ops/GrDrawAtlasOp.h"
56#include "src/gpu/ops/GrDrawOp.h"
57#include "src/gpu/ops/GrDrawVerticesOp.h"
58#include "src/gpu/ops/GrDrawableOp.h"
59#include "src/gpu/ops/GrFillRRectOp.h"
60#include "src/gpu/ops/GrFillRectOp.h"
61#include "src/gpu/ops/GrLatticeOp.h"
62#include "src/gpu/ops/GrOp.h"
63#include "src/gpu/ops/GrOvalOpFactory.h"
64#include "src/gpu/ops/GrRegionOp.h"
65#include "src/gpu/ops/GrSemaphoreOp.h"
66#include "src/gpu/ops/GrShadowRRectOp.h"
67#include "src/gpu/ops/GrStencilPathOp.h"
68#include "src/gpu/ops/GrStrokeRectOp.h"
69#include "src/gpu/ops/GrTextureOp.h"
Brian Salomonab32f652019-05-10 14:24:50 -040070#include "src/gpu/ops/GrTransferFromOp.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050071#include "src/gpu/text/GrTextContext.h"
72#include "src/gpu/text/GrTextTarget.h"
Brian Salomonf18b1d82017-10-27 11:30:49 -040073
Herb Derbyc1b482c2018-08-09 15:02:27 -040074class GrRenderTargetContext::TextTarget : public GrTextTarget {
Brian Salomonf18b1d82017-10-27 11:30:49 -040075public:
76 TextTarget(GrRenderTargetContext* renderTargetContext)
Herb Derbyc1b482c2018-08-09 15:02:27 -040077 : GrTextTarget(renderTargetContext->width(), renderTargetContext->height(),
Robert Phillips7e90be92019-02-15 12:22:59 -050078 renderTargetContext->colorSpaceInfo())
Herb Derby74c6ed32018-07-28 18:07:54 -040079 , fRenderTargetContext(renderTargetContext)
Herb Derby65956872018-08-21 16:55:04 -040080 , fGlyphPainter{*renderTargetContext}{}
Brian Salomonf18b1d82017-10-27 11:30:49 -040081
Robert Phillips7c525e62018-06-12 10:11:12 -040082 void addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) override {
Brian Salomonf18b1d82017-10-27 11:30:49 -040083 fRenderTargetContext->addDrawOp(clip, std::move(op));
84 }
85
Robert Phillips46a13382018-08-23 13:53:01 -040086 void drawShape(const GrClip& clip, const SkPaint& paint,
87 const SkMatrix& viewMatrix, const GrShape& shape) override {
Robert Phillips27927a52018-08-20 13:18:12 -040088 GrBlurUtils::drawShapeWithMaskFilter(fRenderTargetContext->fContext, fRenderTargetContext,
89 clip, paint, viewMatrix, shape);
Brian Salomonf18b1d82017-10-27 11:30:49 -040090 }
91
92 void makeGrPaint(GrMaskFormat maskFormat, const SkPaint& skPaint, const SkMatrix& viewMatrix,
Robert Phillips7c525e62018-06-12 10:11:12 -040093 GrPaint* grPaint) override {
Robert Phillips69893702019-02-22 11:16:30 -050094 auto context = fRenderTargetContext->fContext;
Brian Salomonf18b1d82017-10-27 11:30:49 -040095 const GrColorSpaceInfo& colorSpaceInfo = fRenderTargetContext->colorSpaceInfo();
96 if (kARGB_GrMaskFormat == maskFormat) {
97 SkPaintToGrPaintWithPrimitiveColor(context, colorSpaceInfo, skPaint, grPaint);
98 } else {
99 SkPaintToGrPaint(context, colorSpaceInfo, skPaint, viewMatrix, grPaint);
100 }
101 }
102
Robert Phillips69893702019-02-22 11:16:30 -0500103 GrRecordingContext* getContext() override {
Robert Phillips7c525e62018-06-12 10:11:12 -0400104 return fRenderTargetContext->fContext;
105 }
106
Herb Derby65956872018-08-21 16:55:04 -0400107 SkGlyphRunListPainter* glyphPainter() override {
108 return &fGlyphPainter;
Herb Derby74c6ed32018-07-28 18:07:54 -0400109 }
110
Brian Salomonf18b1d82017-10-27 11:30:49 -0400111private:
112 GrRenderTargetContext* fRenderTargetContext;
Herb Derby65956872018-08-21 16:55:04 -0400113 SkGlyphRunListPainter fGlyphPainter;
Herb Derby74c6ed32018-07-28 18:07:54 -0400114
Brian Salomonf18b1d82017-10-27 11:30:49 -0400115};
joshualittbc907352016-01-13 06:45:40 -0800116
Robert Phillips72152832017-01-25 17:31:35 -0500117#define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext())
joshualitt1de610a2016-01-06 08:26:09 -0800118#define ASSERT_SINGLE_OWNER \
Robert Phillipsa90aa2b2017-04-10 08:19:26 -0400119 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());)
robertphillips391395d2016-03-02 09:26:36 -0800120#define ASSERT_SINGLE_OWNER_PRIV \
Robert Phillipsa90aa2b2017-04-10 08:19:26 -0400121 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());)
Robert Phillips69893702019-02-22 11:16:30 -0500122#define RETURN_IF_ABANDONED if (fContext->priv().abandoned()) { return; }
123#define RETURN_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return; }
124#define RETURN_FALSE_IF_ABANDONED if (fContext->priv().abandoned()) { return false; }
125#define RETURN_FALSE_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return false; }
126#define RETURN_NULL_IF_ABANDONED if (fContext->priv().abandoned()) { return nullptr; }
robertphillipsea461502015-05-26 11:38:03 -0700127
Brian Salomone225b562017-06-14 13:00:03 -0400128//////////////////////////////////////////////////////////////////////////////
129
robertphillipsea461502015-05-26 11:38:03 -0700130class AutoCheckFlush {
131public:
halcanary9d524f22016-03-29 09:03:52 -0700132 AutoCheckFlush(GrDrawingManager* drawingManager) : fDrawingManager(drawingManager) {
robertphillips77a2e522015-10-17 07:43:27 -0700133 SkASSERT(fDrawingManager);
134 }
bsalomonb77a9072016-09-07 10:02:04 -0700135 ~AutoCheckFlush() { fDrawingManager->flushIfNecessary(); }
robertphillipsea461502015-05-26 11:38:03 -0700136
137private:
robertphillips77a2e522015-10-17 07:43:27 -0700138 GrDrawingManager* fDrawingManager;
robertphillipsea461502015-05-26 11:38:03 -0700139};
140
Robert Phillipsf2361d22016-10-25 14:20:06 -0400141// In MDB mode the reffing of the 'getLastOpList' call's result allows in-progress
Brian Osman11052242016-10-27 14:47:55 -0400142// GrOpLists to be picked up and added to by renderTargetContexts lower in the call
Robert Phillipsf2361d22016-10-25 14:20:06 -0400143// stack. When this occurs with a closed GrOpList, a new one will be allocated
Brian Osman11052242016-10-27 14:47:55 -0400144// when the renderTargetContext attempts to use it (via getOpList).
Robert Phillips69893702019-02-22 11:16:30 -0500145GrRenderTargetContext::GrRenderTargetContext(GrRecordingContext* context,
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400146 sk_sp<GrRenderTargetProxy> rtp,
Brian Salomond6287472019-06-24 15:50:07 -0400147 GrColorType colorType,
Brian Osman11052242016-10-27 14:47:55 -0400148 sk_sp<SkColorSpace> colorSpace,
149 const SkSurfaceProps* surfaceProps,
Robert Phillips941d1442017-06-14 16:37:02 -0400150 bool managedOpList)
Brian Salomond6287472019-06-24 15:50:07 -0400151 : GrSurfaceContext(context, colorType, kPremul_SkAlphaType, std::move(colorSpace),
152 rtp->config())
Brian Salomonf3569f02017-10-24 12:52:33 -0400153 , fRenderTargetProxy(std::move(rtp))
154 , fOpList(sk_ref_sp(fRenderTargetProxy->getLastRenderTargetOpList()))
Brian Salomonf3569f02017-10-24 12:52:33 -0400155 , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
156 , fManagedOpList(managedOpList) {
Brian Salomonf18b1d82017-10-27 11:30:49 -0400157 fTextTarget.reset(new TextTarget(this));
robertphillips2e1e51f2015-10-15 08:01:48 -0700158 SkDEBUGCODE(this->validate();)
robertphillipsea461502015-05-26 11:38:03 -0700159}
160
robertphillips2e1e51f2015-10-15 08:01:48 -0700161#ifdef SK_DEBUG
Brian Osman11052242016-10-27 14:47:55 -0400162void GrRenderTargetContext::validate() const {
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400163 SkASSERT(fRenderTargetProxy);
164 fRenderTargetProxy->validate(fContext);
robertphillipsa106c622015-10-16 09:07:06 -0700165
Robert Phillipsf2361d22016-10-25 14:20:06 -0400166 if (fOpList && !fOpList->isClosed()) {
Robert Phillipsdc83b892017-04-13 12:23:54 -0400167 SkASSERT(fRenderTargetProxy->getLastOpList() == fOpList.get());
robertphillipsa106c622015-10-16 09:07:06 -0700168 }
robertphillips2e1e51f2015-10-15 08:01:48 -0700169}
170#endif
171
Brian Osman11052242016-10-27 14:47:55 -0400172GrRenderTargetContext::~GrRenderTargetContext() {
joshualitt1de610a2016-01-06 08:26:09 -0800173 ASSERT_SINGLE_OWNER
robertphillipsa106c622015-10-16 09:07:06 -0700174}
175
Chris Dalton7d6748e2019-03-13 00:34:52 -0600176inline GrAAType GrRenderTargetContext::chooseAAType(GrAA aa) {
Chris Dalton7d6748e2019-03-13 00:34:52 -0600177 if (GrAA::kNo == aa) {
178 // On some devices we cannot disable MSAA if it is enabled so we make the AA type reflect
179 // that.
Chris Dalton6ce447a2019-06-23 18:07:38 -0600180 if (this->numSamples() > 1 && !this->caps()->multisampleDisableSupport()) {
Chris Dalton7d6748e2019-03-13 00:34:52 -0600181 return GrAAType::kMSAA;
182 }
183 return GrAAType::kNone;
184 }
Chris Dalton6ce447a2019-06-23 18:07:38 -0600185 return (this->numSamples() > 1) ? GrAAType::kMSAA : GrAAType::kCoverage;
Chris Dalton7d6748e2019-03-13 00:34:52 -0600186}
187
Robert Phillipsf200a902017-01-30 13:27:37 -0500188GrTextureProxy* GrRenderTargetContext::asTextureProxy() {
Robert Phillipseaa86252016-11-08 13:49:39 +0000189 return fRenderTargetProxy->asTextureProxy();
190}
191
Greg Daniele252f082017-10-23 16:05:23 -0400192const GrTextureProxy* GrRenderTargetContext::asTextureProxy() const {
193 return fRenderTargetProxy->asTextureProxy();
194}
195
Robert Phillipsf200a902017-01-30 13:27:37 -0500196sk_sp<GrTextureProxy> GrRenderTargetContext::asTextureProxyRef() {
197 return sk_ref_sp(fRenderTargetProxy->asTextureProxy());
198}
199
Greg Daniele252f082017-10-23 16:05:23 -0400200GrMipMapped GrRenderTargetContext::mipMapped() const {
201 if (const GrTextureProxy* proxy = this->asTextureProxy()) {
202 return proxy->mipMapped();
203 }
204 return GrMipMapped::kNo;
205}
206
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400207GrRenderTargetOpList* GrRenderTargetContext::getRTOpList() {
joshualitt1de610a2016-01-06 08:26:09 -0800208 ASSERT_SINGLE_OWNER
robertphillipsa106c622015-10-16 09:07:06 -0700209 SkDEBUGCODE(this->validate();)
210
Robert Phillipsf2361d22016-10-25 14:20:06 -0400211 if (!fOpList || fOpList->isClosed()) {
Michael Ludwig6e17f1d2019-05-15 14:00:20 +0000212 fOpList = this->drawingManager()->newRTOpList(fRenderTargetProxy, fManagedOpList);
robertphillipsa106c622015-10-16 09:07:06 -0700213 }
214
Robert Phillipsdc83b892017-04-13 12:23:54 -0400215 return fOpList.get();
robertphillipsa106c622015-10-16 09:07:06 -0700216}
217
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400218GrOpList* GrRenderTargetContext::getOpList() {
219 return this->getRTOpList();
robertphillipsea461502015-05-26 11:38:03 -0700220}
221
Herb Derbycddab252018-07-16 11:19:04 -0400222void GrRenderTargetContext::drawGlyphRunList(
223 const GrClip& clip, const SkMatrix& viewMatrix,
Robert Phillipse4643cc2018-08-14 13:01:29 -0400224 const SkGlyphRunList& blob) {
joshualitt1de610a2016-01-06 08:26:09 -0800225 ASSERT_SINGLE_OWNER
robertphillips2d70dcb2015-10-06 07:38:23 -0700226 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700227 SkDEBUGCODE(this->validate();)
Herb Derbycddab252018-07-16 11:19:04 -0400228 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawGlyphRunList", fContext);
robertphillips2d70dcb2015-10-06 07:38:23 -0700229
Greg Danielbe7fc462019-01-03 16:40:42 -0500230 // Drawing text can cause us to do inline uploads. This is not supported for wrapped vulkan
231 // secondary command buffers because it would require stopping and starting a render pass which
232 // we don't have access to.
233 if (this->wrapsVkSecondaryCB()) {
234 return;
235 }
236
Herb Derby26cbe512018-05-24 14:39:01 -0400237 GrTextContext* atlasTextContext = this->drawingManager()->getTextContext();
Herb Derbycddab252018-07-16 11:19:04 -0400238 atlasTextContext->drawGlyphRunList(fContext, fTextTarget.get(), clip, viewMatrix,
Robert Phillipse4643cc2018-08-14 13:01:29 -0400239 fSurfaceProps, blob);
robertphillipsea461502015-05-26 11:38:03 -0700240}
241
Brian Osman11052242016-10-27 14:47:55 -0400242void GrRenderTargetContext::discard() {
joshualitt1de610a2016-01-06 08:26:09 -0800243 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700244 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700245 SkDEBUGCODE(this->validate();)
Robert Phillips6b47c7d2017-08-29 07:24:09 -0400246 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -0700247
Robert Phillips72152832017-01-25 17:31:35 -0500248 AutoCheckFlush acf(this->drawingManager());
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400249
Robert Phillips380b90c2017-08-30 07:41:07 -0400250 this->getRTOpList()->discard();
robertphillipsea461502015-05-26 11:38:03 -0700251}
252
Brian Osman11052242016-10-27 14:47:55 -0400253void GrRenderTargetContext::clear(const SkIRect* rect,
Brian Osman9a9baae2018-11-05 15:06:26 -0500254 const SkPMColor4f& color,
Chris Dalton344e9032017-12-11 15:42:09 -0700255 CanClearFullscreen canClearFullscreen) {
joshualitt1de610a2016-01-06 08:26:09 -0800256 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700257 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700258 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400259 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext);
robertphillipsea461502015-05-26 11:38:03 -0700260
Robert Phillips72152832017-01-25 17:31:35 -0500261 AutoCheckFlush acf(this->drawingManager());
Chris Dalton344e9032017-12-11 15:42:09 -0700262 this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color,
263 canClearFullscreen);
csmartdalton29df7602016-08-31 11:55:52 -0700264}
robertphillips9199a9f2016-07-13 07:48:43 -0700265
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500266void GrRenderTargetContextPriv::clear(const GrFixedClip& clip,
267 const SkPMColor4f& color,
268 CanClearFullscreen canClearFullscreen) {
269 ASSERT_SINGLE_OWNER_PRIV
270 RETURN_IF_ABANDONED_PRIV
271 SkDEBUGCODE(fRenderTargetContext->validate();)
272 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clear",
273 fRenderTargetContext->fContext);
274
275 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
276 fRenderTargetContext->internalClear(clip, color, canClearFullscreen);
277}
278
279static void clear_to_grpaint(const SkPMColor4f& color, GrPaint* paint) {
280 paint->setColor4f(color);
281 if (color.isOpaque()) {
282 // Can just rely on the src-over blend mode to do the right thing
283 paint->setPorterDuffXPFactory(SkBlendMode::kSrcOver);
284 } else {
285 // A clear overwrites the prior color, so even if it's transparent, it behaves as if it
286 // were src blended
287 paint->setPorterDuffXPFactory(SkBlendMode::kSrc);
288 }
289}
290
291void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
292 const SkPMColor4f& color,
293 CanClearFullscreen canClearFullscreen) {
294 bool isFull = false;
295 if (!clip.hasWindowRectangles()) {
Robert Phillips0e35ce22019-04-05 10:57:28 -0400296 // TODO: wrt the shouldInitializeTextures path, it would be more performant to
297 // only clear the entire target if we knew it had not been cleared before. As
298 // is this could end up doing a lot of redundant clears.
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500299 isFull = !clip.scissorEnabled() ||
300 (CanClearFullscreen::kYes == canClearFullscreen &&
Robert Phillips0e35ce22019-04-05 10:57:28 -0400301 (this->caps()->preferFullscreenClears() || this->caps()->shouldInitializeTextures())) ||
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500302 clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height()));
303 }
304
305 if (isFull) {
Chris Dalton6b982802019-06-27 13:53:46 -0600306 GrRenderTargetOpList* opList = this->getRTOpList();
307 if (opList->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) &&
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500308 !this->caps()->performColorClearsAsDraws()) {
309 // The op list was emptied and native clears are allowed, so just use the load op
Chris Dalton6b982802019-06-27 13:53:46 -0600310 opList->setColorLoadOp(GrLoadOp::kClear, color);
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500311 return;
312 } else {
313 // Will use an op for the clear, reset the load op to discard since the op will
314 // blow away the color buffer contents
Chris Dalton6b982802019-06-27 13:53:46 -0600315 opList->setColorLoadOp(GrLoadOp::kDiscard);
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500316 }
317
318 // Must add an op to the list (either because we couldn't use a load op, or because the
319 // clear load op isn't supported)
320 if (this->caps()->performColorClearsAsDraws()) {
321 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
322 GrPaint paint;
323 clear_to_grpaint(color, &paint);
324 this->addDrawOp(GrFixedClip::Disabled(),
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400325 GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
326 rtRect));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500327 } else {
Chris Dalton6b982802019-06-27 13:53:46 -0600328 opList->addOp(GrClearOp::Make(fContext, SkIRect::MakeEmpty(), color,
329 /* fullscreen */ true), *this->caps());
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500330 }
331 } else {
332 if (this->caps()->performPartialClearsAsDraws()) {
333 // performPartialClearsAsDraws() also returns true if any clear has to be a draw.
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500334 GrPaint paint;
335 clear_to_grpaint(color, &paint);
336
Michael Ludwig64b28a72019-05-28 12:02:00 -0400337 this->addDrawOp(clip,
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400338 GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
339 SkRect::Make(clip.scissorRect())));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500340 } else {
341 std::unique_ptr<GrOp> op(GrClearOp::Make(fContext, clip, color,
342 this->asSurfaceProxy()));
343 // This version of the clear op factory can return null if the clip doesn't intersect
344 // with the surface proxy's boundary
345 if (!op) {
346 return;
347 }
348 this->getRTOpList()->addOp(std::move(op), *this->caps());
349 }
350 }
351}
352
Brian Osman9a9baae2018-11-05 15:06:26 -0500353void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const SkPMColor4f& color) {
Robert Phillips784b7bf2016-12-09 13:35:02 -0500354 ASSERT_SINGLE_OWNER_PRIV
355 RETURN_IF_ABANDONED_PRIV
356 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400357 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "absClear",
358 fRenderTargetContext->fContext);
Robert Phillips784b7bf2016-12-09 13:35:02 -0500359
Robert Phillips72152832017-01-25 17:31:35 -0500360 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
Robert Phillips784b7bf2016-12-09 13:35:02 -0500361
Brian Salomonbb5711a2017-05-17 13:49:59 -0400362 SkIRect rtRect = SkIRect::MakeWH(fRenderTargetContext->fRenderTargetProxy->worstCaseWidth(),
363 fRenderTargetContext->fRenderTargetProxy->worstCaseHeight());
Robert Phillips784b7bf2016-12-09 13:35:02 -0500364
365 if (clearRect) {
366 if (clearRect->contains(rtRect)) {
367 clearRect = nullptr; // full screen
368 } else {
369 if (!rtRect.intersect(*clearRect)) {
370 return;
371 }
372 }
373 }
374
375 // TODO: in a post-MDB world this should be handled at the OpList level.
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500376 // This makes sure to always add an op to the list, instead of marking the clear as a load op.
377 // This code follows very similar logic to internalClear() below, but critical differences are
378 // highlighted in line related to absClear()'s unique behavior.
379 if (clearRect) {
380 if (fRenderTargetContext->caps()->performPartialClearsAsDraws()) {
Ethan Nicholas56d19a52018-10-15 11:26:20 -0400381 GrPaint paint;
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500382 clear_to_grpaint(color, &paint);
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400383
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500384 // Use the disabled clip; the rect geometry already matches the clear rectangle and
385 // if it were added to a scissor, that would be intersected with the logical surface
386 // bounds and not the worst case dimensions required here.
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400387 fRenderTargetContext->addDrawOp(
388 GrFixedClip::Disabled(),
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400389 GrFillRectOp::MakeNonAARect(fRenderTargetContext->fContext, std::move(paint),
390 SkMatrix::I(), SkRect::Make(rtRect)));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500391 } else {
392 // Must use the ClearOp factory that takes a boolean (false) instead of a surface
393 // proxy. The surface proxy variant would intersect the clip rect with its logical
394 // bounds, which is not desired in this special case.
395 fRenderTargetContext->getRTOpList()->addOp(
396 GrClearOp::Make(fRenderTargetContext->fContext, rtRect, color,
397 /* fullscreen */ false),
398 *fRenderTargetContext->caps());
csmartdalton29df7602016-08-31 11:55:52 -0700399 }
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500400 } else {
401 // Reset the oplist like in internalClear(), but do not rely on a load op for the clear
Chris Dalton6b982802019-06-27 13:53:46 -0600402 fRenderTargetContext->getRTOpList()->resetForFullscreenClear(
403 fRenderTargetContext->canDiscardPreviousOpsOnFullClear());
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500404 fRenderTargetContext->getRTOpList()->setColorLoadOp(GrLoadOp::kDiscard);
405
406 if (fRenderTargetContext->caps()->performColorClearsAsDraws()) {
407 // This draws a quad covering the worst case dimensions instead of just the logical
408 // width and height like in internalClear().
409 GrPaint paint;
410 clear_to_grpaint(color, &paint);
Michael Ludwig4a0cf502019-05-30 12:54:09 -0400411 fRenderTargetContext->addDrawOp(
412 GrFixedClip::Disabled(),
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400413 GrFillRectOp::MakeNonAARect(fRenderTargetContext->fContext, std::move(paint),
414 SkMatrix::I(), SkRect::Make(rtRect)));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500415 } else {
416 // Nothing special about this path in absClear compared to internalClear()
417 fRenderTargetContext->getRTOpList()->addOp(
418 GrClearOp::Make(fRenderTargetContext->fContext, SkIRect::MakeEmpty(), color,
419 /* fullscreen */ true),
420 *fRenderTargetContext->caps());
Ethan Nicholas56d19a52018-10-15 11:26:20 -0400421 }
robertphillips9199a9f2016-07-13 07:48:43 -0700422 }
robertphillipsea461502015-05-26 11:38:03 -0700423}
424
Brian Osman11052242016-10-27 14:47:55 -0400425void GrRenderTargetContext::drawPaint(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500426 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -0400427 const SkMatrix& viewMatrix) {
Michael Ludwig61328202019-06-19 14:48:58 +0000428 // Start with the render target, since that is the maximum content we could possibly fill.
429 // drawFilledQuad() will automatically restrict it to clip bounds for us if possible.
Robert Phillipsc7635fa2016-10-28 13:25:24 -0400430 SkRect r = fRenderTargetProxy->getBoundsRect();
Michael Ludwig3d6390e2018-10-09 11:45:16 -0400431 if (!paint.numTotalFragmentProcessors()) {
Michael Ludwig61328202019-06-19 14:48:58 +0000432 // The paint is trivial so we won't need to use local coordinates, so skip calculating the
433 // inverse view matrix.
434 this->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), r, r);
435 } else {
436 // Use the inverse view matrix to arrive at appropriate local coordinates for the paint.
437 SkMatrix localMatrix;
438 if (!viewMatrix.invert(&localMatrix)) {
439 return;
Michael Ludwig3d6390e2018-10-09 11:45:16 -0400440 }
Michael Ludwig61328202019-06-19 14:48:58 +0000441 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), r,
442 localMatrix);
bsalomoncb31e512016-08-26 10:48:19 -0700443 }
robertphillipsea461502015-05-26 11:38:03 -0700444}
445
csmartdalton97f6cd52016-07-13 13:37:08 -0700446// Attempts to crop a rect and optional local rect to the clip boundaries.
447// Returns false if the draw can be skipped entirely.
Michael Ludwig61328202019-06-19 14:48:58 +0000448// FIXME to be removed once drawTexture et al are updated to use attemptQuadOptimization instead
robertphillips13a7eee2016-08-31 15:06:24 -0700449static bool crop_filled_rect(int width, int height, const GrClip& clip,
csmartdalton97f6cd52016-07-13 13:37:08 -0700450 const SkMatrix& viewMatrix, SkRect* rect,
451 SkRect* localRect = nullptr) {
452 if (!viewMatrix.rectStaysRect()) {
453 return true;
454 }
455
csmartdalton97f6cd52016-07-13 13:37:08 -0700456 SkIRect clipDevBounds;
457 SkRect clipBounds;
csmartdalton97f6cd52016-07-13 13:37:08 -0700458
robertphillips13a7eee2016-08-31 15:06:24 -0700459 clip.getConservativeBounds(width, height, &clipDevBounds);
reeda39667c2016-08-22 06:39:49 -0700460 if (!SkMatrixPriv::InverseMapRect(viewMatrix, &clipBounds, SkRect::Make(clipDevBounds))) {
461 return false;
462 }
csmartdalton97f6cd52016-07-13 13:37:08 -0700463
464 if (localRect) {
465 if (!rect->intersects(clipBounds)) {
466 return false;
467 }
Michael Ludwig904657d2019-04-12 10:57:24 -0400468 // localRect is force-sorted after clipping, so this is a sanity check to make sure callers
469 // aren't intentionally using inverted local rectangles.
470 SkASSERT(localRect->isSorted());
csmartdalton97f6cd52016-07-13 13:37:08 -0700471 const SkScalar dx = localRect->width() / rect->width();
472 const SkScalar dy = localRect->height() / rect->height();
473 if (clipBounds.fLeft > rect->fLeft) {
474 localRect->fLeft += (clipBounds.fLeft - rect->fLeft) * dx;
475 rect->fLeft = clipBounds.fLeft;
476 }
477 if (clipBounds.fTop > rect->fTop) {
478 localRect->fTop += (clipBounds.fTop - rect->fTop) * dy;
479 rect->fTop = clipBounds.fTop;
480 }
481 if (clipBounds.fRight < rect->fRight) {
482 localRect->fRight -= (rect->fRight - clipBounds.fRight) * dx;
483 rect->fRight = clipBounds.fRight;
484 }
485 if (clipBounds.fBottom < rect->fBottom) {
486 localRect->fBottom -= (rect->fBottom - clipBounds.fBottom) * dy;
487 rect->fBottom = clipBounds.fBottom;
488 }
Michael Ludwig904657d2019-04-12 10:57:24 -0400489 // Ensure local coordinates remain sorted after clipping. If the original dstRect was very
490 // large, numeric precision can invert the localRect
491 localRect->sort();
csmartdalton97f6cd52016-07-13 13:37:08 -0700492 return true;
493 }
494
495 return rect->intersect(clipBounds);
496}
497
Michael Ludwig61328202019-06-19 14:48:58 +0000498enum class GrRenderTargetContext::QuadOptimization {
499 // The rect to draw doesn't intersect clip or render target, so no draw op should be added
500 kDiscarded,
501 // The rect to draw was converted to some other op and appended to the oplist, so no additional
502 // op is necessary. Currently this can convert it to a clear op or a rrect op. Only valid if
503 // a constColor is provided.
504 kSubmitted,
505 // The clip was folded into the device quad, with updated edge flags and local coords, and
506 // caller is responsible for adding an appropriate op.
507 kClipApplied,
508 // No change to clip, but quad updated to better fit clip/render target, and caller is
509 // responsible for adding an appropriate op.
510 kCropped
511};
Michael Ludwig61a16512019-01-15 11:15:13 -0500512
Michael Ludwiged71b7e2019-06-21 13:47:02 -0400513static bool make_vertex_finite(float* value) {
514 if (SkScalarIsNaN(*value)) {
515 return false;
516 }
517
518 if (!SkScalarIsFinite(*value)) {
519 // +/- infinity at this point. Don't use exactly SK_ScalarMax so that we have some precision
520 // left when calculating crops.
521 static constexpr float kNearInfinity = SK_ScalarMax / 4.f;
522 *value = *value < 0.f ? -kNearInfinity : kNearInfinity;
523 }
524
525 return true;
526}
527
Michael Ludwig61328202019-06-19 14:48:58 +0000528GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimization(
Michael Ludwige08b4432019-06-19 18:00:48 -0400529 const GrClip& clip, const SkPMColor4f* constColor,
530 const GrUserStencilSettings* stencilSettings, GrAA* aa, GrQuadAAFlags* edgeFlags,
531 GrQuad* deviceQuad, GrQuad* localQuad) {
Michael Ludwig61328202019-06-19 14:48:58 +0000532 // Optimization requirements:
533 // 1. kDiscard applies when clip bounds and quad bounds do not intersect
534 // 2. kClear applies when constColor and final geom is pixel aligned rect;
535 // pixel aligned rect requires rect clip and (rect quad or quad covers clip)
536 // 3. kRRect applies when constColor and rrect clip and quad covers clip
537 // 4. kExplicitClip applies when rect clip and (rect quad or quad covers clip)
538 // 5. kCropped applies when rect quad (currently)
539 // 6. kNone always applies
540 GrQuadAAFlags newFlags = *edgeFlags;
Brian Salomon7694b902019-06-18 21:00:21 +0000541
Michael Ludwige08b4432019-06-19 18:00:48 -0400542 SkRect rtRect;
543 if (stencilSettings) {
544 // Must use worst case bounds so that stencil buffer updates on approximately sized render
545 // targets don't get corrupted.
546 rtRect = SkRect::MakeWH(fRenderTargetProxy->worstCaseWidth(),
547 fRenderTargetProxy->worstCaseHeight());
548 } else {
549 // Use the logical size of the render target, which allows for "fullscreen" clears even if
550 // the render target has an approximate backing fit
551 rtRect = SkRect::MakeWH(this->width(), this->height());
552 }
553
Michael Ludwig61328202019-06-19 14:48:58 +0000554 SkRect drawBounds = deviceQuad->bounds();
555 if (constColor) {
556 // Don't bother updating local coordinates when the paint will ignore them anyways
557 localQuad = nullptr;
Michael Ludwiged71b7e2019-06-21 13:47:02 -0400558 // If the device quad is not finite, coerce into a finite quad. This is acceptable since it
559 // will be cropped to the finite 'clip' or render target and there is no local space mapping
560 if (!deviceQuad->isFinite()) {
561 for (int i = 0; i < 4; ++i) {
562 if (!make_vertex_finite(deviceQuad->xs() + i) ||
563 !make_vertex_finite(deviceQuad->ys() + i) ||
564 !make_vertex_finite(deviceQuad->ws() + i)) {
565 // Discard if we see a nan
566 return QuadOptimization::kDiscarded;
567 }
568 }
569 SkASSERT(deviceQuad->isFinite());
570 }
571 } else {
572 // CropToRect requires the quads to be finite. If they are not finite and we have local
573 // coordinates, the mapping from local space to device space is poorly defined so drop it
574 if (!deviceQuad->isFinite()) {
575 return QuadOptimization::kDiscarded;
576 }
Brian Salomon7694b902019-06-18 21:00:21 +0000577 }
578
Michael Ludwig61328202019-06-19 14:48:58 +0000579 // If the quad is entirely off screen, it doesn't matter what the clip does
580 if (!rtRect.intersects(drawBounds)) {
581 return QuadOptimization::kDiscarded;
582 }
Brian Salomon7694b902019-06-18 21:00:21 +0000583
Michael Ludwig61328202019-06-19 14:48:58 +0000584 // Check if clip can be represented as a rounded rect (initialize as if clip fully contained
585 // the render target).
586 SkRRect clipRRect = SkRRect::MakeRect(rtRect);
Michael Ludwige08b4432019-06-19 18:00:48 -0400587 // We initialize clipAA to *aa when there are stencil settings so that we don't artificially
588 // encounter mixed-aa edges (not allowed for stencil), but we want to start as non-AA for
589 // regular draws so that if we fully cover the render target, that can stop being anti-aliased.
590 GrAA clipAA = stencilSettings ? *aa : GrAA::kNo;
Michael Ludwig61328202019-06-19 14:48:58 +0000591 bool axisAlignedClip = true;
Brian Salomon7694b902019-06-18 21:00:21 +0000592 if (!clip.quickContains(rtRect)) {
Michael Ludwig61328202019-06-19 14:48:58 +0000593 if (!clip.isRRect(rtRect, &clipRRect, &clipAA)) {
594 axisAlignedClip = false;
Brian Salomon7694b902019-06-18 21:00:21 +0000595 }
Brian Salomon7694b902019-06-18 21:00:21 +0000596 }
597
Michael Ludwig61328202019-06-19 14:48:58 +0000598 // If the clip rrect is valid (i.e. axis-aligned), we can potentially combine it with the
599 // draw geometry so that no clip is needed when drawing.
Michael Ludwige08b4432019-06-19 18:00:48 -0400600 if (axisAlignedClip && (!stencilSettings || clipAA == *aa)) {
Michael Ludwig61328202019-06-19 14:48:58 +0000601 // Tighten clip bounds (if clipRRect.isRect() is true, clipBounds now holds the intersection
602 // of the render target and the clip rect)
603 SkRect clipBounds = rtRect;
604 if (!clipBounds.intersect(clipRRect.rect()) || !clipBounds.intersects(drawBounds)) {
605 return QuadOptimization::kDiscarded;
Brian Salomon7694b902019-06-18 21:00:21 +0000606 }
607
Michael Ludwig61328202019-06-19 14:48:58 +0000608 if (clipRRect.isRect()) {
609 // No rounded corners, so the kClear and kExplicitClip optimizations are possible
610 if (GrQuadUtils::CropToRect(clipBounds, clipAA, &newFlags, deviceQuad, localQuad)) {
611 if (constColor && deviceQuad->quadType() == GrQuad::Type::kAxisAligned) {
612 // Clear optimization is possible
613 drawBounds = deviceQuad->bounds();
614 if (drawBounds.contains(rtRect)) {
615 // Fullscreen clear
616 this->clear(nullptr, *constColor, CanClearFullscreen::kYes);
617 return QuadOptimization::kSubmitted;
618 } else if (GrClip::IsPixelAligned(drawBounds) &&
619 drawBounds.width() > 256 && drawBounds.height() > 256) {
620 // Scissor + clear (round shouldn't do anything since we are pixel aligned)
621 SkIRect scissorRect;
622 drawBounds.round(&scissorRect);
623 this->clear(&scissorRect, *constColor, CanClearFullscreen::kNo);
624 return QuadOptimization::kSubmitted;
625 }
626 }
627
628 // Update overall AA setting.
629 *edgeFlags = newFlags;
630 if (*aa == GrAA::kNo && clipAA == GrAA::kYes &&
631 newFlags != GrQuadAAFlags::kNone) {
632 // The clip was anti-aliased and now the draw needs to be upgraded to AA to
633 // properly reflect the smooth edge of the clip.
634 *aa = GrAA::kYes;
635 }
636 // We intentionally do not downgrade AA here because we don't know if we need to
637 // preserve MSAA (see GrQuadAAFlags docs). But later in the pipeline, the ops can
638 // use GrResolveAATypeForQuad() to turn off coverage AA when all flags are off.
639
640 // deviceQuad is exactly the intersection of original quad and clip, so it can be
641 // drawn with no clip (submitted by caller)
642 return QuadOptimization::kClipApplied;
643 } else {
644 // The quads have been updated to better fit the clip bounds, but can't get rid of
645 // the clip entirely
646 return QuadOptimization::kCropped;
647 }
648 } else if (constColor) {
649 // Rounded corners and constant filled color (limit ourselves to solid colors because
650 // there is no way to use custom local coordinates with drawRRect).
651 if (GrQuadUtils::CropToRect(clipBounds, clipAA, &newFlags, deviceQuad, localQuad) &&
652 deviceQuad->quadType() == GrQuad::Type::kAxisAligned &&
653 deviceQuad->bounds().contains(clipBounds)) {
654 // Since the cropped quad became a rectangle which covered the bounds of the rrect,
655 // we can draw the rrect directly and ignore the edge flags
656 GrPaint paint;
657 clear_to_grpaint(*constColor, &paint);
658 this->drawRRect(GrFixedClip::Disabled(), std::move(paint), clipAA, SkMatrix::I(),
659 clipRRect, GrStyle::SimpleFill());
660 return QuadOptimization::kSubmitted;
661 } else {
662 // The quad has been updated to better fit clip bounds, but can't remove the clip
663 return QuadOptimization::kCropped;
664 }
Brian Salomon7694b902019-06-18 21:00:21 +0000665 }
Brian Salomon7694b902019-06-18 21:00:21 +0000666 }
667
Michael Ludwig61328202019-06-19 14:48:58 +0000668 // Crop the quad to the conservative bounds of the clip.
669 SkIRect clipDevBounds;
670 clip.getConservativeBounds(rtRect.width(), rtRect.height(), &clipDevBounds);
671 SkRect clipBounds = SkRect::Make(clipDevBounds);
672
673 // One final check for discarding, since we may have gone here directly due to a complex clip
674 if (!clipBounds.intersects(drawBounds)) {
675 return QuadOptimization::kDiscarded;
Brian Salomon7694b902019-06-18 21:00:21 +0000676 }
677
Michael Ludwig61328202019-06-19 14:48:58 +0000678 // Even if this were to return true, the crop rect does not exactly match the clip, so can not
679 // report explicit-clip. Since these edges aren't visible, don't update the final edge flags.
680 GrQuadUtils::CropToRect(clipBounds, clipAA, &newFlags, deviceQuad, localQuad);
681
682 return QuadOptimization::kCropped;
Brian Salomon7694b902019-06-18 21:00:21 +0000683}
684
Michael Ludwig61328202019-06-19 14:48:58 +0000685void GrRenderTargetContext::drawFilledQuad(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500686 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500687 GrAA aa,
Michael Ludwig61328202019-06-19 14:48:58 +0000688 GrQuadAAFlags edgeFlags,
689 const GrQuad& deviceQuad,
690 const GrQuad& localQuad,
Brian Osman11052242016-10-27 14:47:55 -0400691 const GrUserStencilSettings* ss) {
Michael Ludwig61328202019-06-19 14:48:58 +0000692 ASSERT_SINGLE_OWNER
693 RETURN_IF_ABANDONED
694 SkDEBUGCODE(this->validate();)
695 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFilledQuad", fContext);
Michael Ludwig61a16512019-01-15 11:15:13 -0500696
Michael Ludwig61328202019-06-19 14:48:58 +0000697 AutoCheckFlush acf(this->drawingManager());
698
699 SkPMColor4f* constColor = nullptr;
700 SkPMColor4f paintColor;
701 if (!ss && !paint.numCoverageFragmentProcessors() &&
702 paint.isConstantBlendedColor(&paintColor)) {
703 // Only consider clears/rrects when it's easy to guarantee 100% fill with single color
704 constColor = &paintColor;
Michael Ludwig61a16512019-01-15 11:15:13 -0500705 }
706
Michael Ludwig61328202019-06-19 14:48:58 +0000707 GrQuad croppedDeviceQuad = deviceQuad;
708 GrQuad croppedLocalQuad = localQuad;
Michael Ludwige08b4432019-06-19 18:00:48 -0400709 QuadOptimization opt = this->attemptQuadOptimization(clip, constColor, ss, &aa, &edgeFlags,
710 &croppedDeviceQuad, &croppedLocalQuad);
Michael Ludwig61328202019-06-19 14:48:58 +0000711 if (opt >= QuadOptimization::kClipApplied) {
712 // These optimizations require caller to add an op themselves
713 const GrClip& finalClip = opt == QuadOptimization::kClipApplied ? GrFixedClip::Disabled()
714 : clip;
715 GrAAType aaType = ss ? (aa == GrAA::kYes ? GrAAType::kMSAA : GrAAType::kNone)
716 : this->chooseAAType(aa);
717 this->addDrawOp(finalClip, GrFillRectOp::Make(fContext, std::move(paint), aaType, edgeFlags,
718 croppedDeviceQuad, croppedLocalQuad, ss));
csmartdalton97f6cd52016-07-13 13:37:08 -0700719 }
Michael Ludwig61328202019-06-19 14:48:58 +0000720 // All other optimization levels were completely handled inside attempt(), so no extra op needed
robertphillips391395d2016-03-02 09:26:36 -0800721}
722
Brian Osman11052242016-10-27 14:47:55 -0400723void GrRenderTargetContext::drawRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -0500724 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -0500725 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -0400726 const SkMatrix& viewMatrix,
727 const SkRect& rect,
728 const GrStyle* style) {
bsalomon6663acf2016-05-10 09:14:17 -0700729 if (!style) {
730 style = &GrStyle::SimpleFill();
731 }
joshualitt1de610a2016-01-06 08:26:09 -0800732 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -0700733 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -0700734 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400735 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRect", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -0700736
bsalomon6663acf2016-05-10 09:14:17 -0700737 // Path effects should've been devolved to a path in SkGpuDevice
738 SkASSERT(!style->pathEffect());
robertphillipsea461502015-05-26 11:38:03 -0700739
Robert Phillips72152832017-01-25 17:31:35 -0500740 AutoCheckFlush acf(this->drawingManager());
robertphillipsea461502015-05-26 11:38:03 -0700741
bsalomon6663acf2016-05-10 09:14:17 -0700742 const SkStrokeRec& stroke = style->strokeRec();
Robert Phillips8c8b0462018-08-24 16:18:03 -0400743 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
Michael Ludwig61328202019-06-19 14:48:58 +0000744 // Fills the rect, using rect as its own local coordinates
745 this->fillRectToRect(clip, std::move(paint), aa, viewMatrix, rect, rect);
Michael Ludwig61a16512019-01-15 11:15:13 -0500746 return;
bsalomona7d85ba2016-07-06 11:54:59 -0700747 } else if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
748 stroke.getStyle() == SkStrokeRec::kHairline_Style) {
749 if ((!rect.width() || !rect.height()) &&
750 SkStrokeRec::kHairline_Style != stroke.getStyle()) {
751 SkScalar r = stroke.getWidth() / 2;
752 // TODO: Move these stroke->fill fallbacks to GrShape?
753 switch (stroke.getJoin()) {
754 case SkPaint::kMiter_Join:
Brian Salomon82f44312017-01-11 13:42:54 -0500755 this->drawRect(
756 clip, std::move(paint), aa, viewMatrix,
757 {rect.fLeft - r, rect.fTop - r, rect.fRight + r, rect.fBottom + r},
758 &GrStyle::SimpleFill());
bsalomona7d85ba2016-07-06 11:54:59 -0700759 return;
760 case SkPaint::kRound_Join:
761 // Raster draws nothing when both dimensions are empty.
762 if (rect.width() || rect.height()){
763 SkRRect rrect = SkRRect::MakeRectXY(rect.makeOutset(r, r), r, r);
Brian Salomon82f44312017-01-11 13:42:54 -0500764 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect,
765 GrStyle::SimpleFill());
bsalomona7d85ba2016-07-06 11:54:59 -0700766 return;
767 }
768 case SkPaint::kBevel_Join:
769 if (!rect.width()) {
Brian Salomon82f44312017-01-11 13:42:54 -0500770 this->drawRect(clip, std::move(paint), aa, viewMatrix,
bsalomona7d85ba2016-07-06 11:54:59 -0700771 {rect.fLeft - r, rect.fTop, rect.fRight + r, rect.fBottom},
772 &GrStyle::SimpleFill());
773 } else {
Brian Salomon82f44312017-01-11 13:42:54 -0500774 this->drawRect(clip, std::move(paint), aa, viewMatrix,
bsalomona7d85ba2016-07-06 11:54:59 -0700775 {rect.fLeft, rect.fTop - r, rect.fRight, rect.fBottom + r},
776 &GrStyle::SimpleFill());
777 }
778 return;
779 }
780 }
robertphillips44302392016-07-08 14:43:03 -0700781
Brian Salomonbaaf4392017-06-15 09:59:23 -0400782 std::unique_ptr<GrDrawOp> op;
robertphillips44302392016-07-08 14:43:03 -0700783
Chris Dalton7d6748e2019-03-13 00:34:52 -0600784 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig72ab3462018-12-10 12:43:36 -0500785 op = GrStrokeRectOp::Make(fContext, std::move(paint), aaType, viewMatrix, rect, stroke);
786 // op may be null if the stroke is not supported or if using coverage aa and the view matrix
787 // does not preserve rectangles.
Brian Salomon42521e82016-12-07 16:44:58 -0500788 if (op) {
Brian Salomonbaaf4392017-06-15 09:59:23 -0400789 this->addDrawOp(clip, std::move(op));
robertphillips44302392016-07-08 14:43:03 -0700790 return;
robertphillips4bc31812016-03-01 12:22:49 -0800791 }
robertphillips4bc31812016-03-01 12:22:49 -0800792 }
Mike Klein16885072018-12-11 09:54:31 -0500793 assert_alive(paint);
Brian Salomon2fad74a2017-12-20 13:28:55 -0500794 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(rect, *style));
robertphillipsea461502015-05-26 11:38:03 -0700795}
796
Michael Ludwig69858532018-11-28 15:34:34 -0500797void GrRenderTargetContext::drawQuadSet(const GrClip& clip, GrPaint&& paint, GrAA aa,
798 const SkMatrix& viewMatrix, const QuadSetEntry quads[],
799 int cnt) {
Chris Dalton7d6748e2019-03-13 00:34:52 -0600800 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig69858532018-11-28 15:34:34 -0500801 this->addDrawOp(clip, GrFillRectOp::MakeSet(fContext, std::move(paint), aaType, viewMatrix,
802 quads, cnt));
803}
804
Robert Phillipsec2249f2016-11-09 08:54:35 -0500805int GrRenderTargetContextPriv::maxWindowRectangles() const {
806 return fRenderTargetContext->fRenderTargetProxy->maxWindowRectangles(
Brian Salomonc7fe0f72018-05-11 10:14:21 -0400807 *fRenderTargetContext->caps());
Robert Phillipsec2249f2016-11-09 08:54:35 -0500808}
809
Chris Dalton6b982802019-06-27 13:53:46 -0600810GrRenderTargetOpList::CanDiscardPreviousOps GrRenderTargetContext::canDiscardPreviousOpsOnFullClear(
811 ) const {
812#if GR_TEST_UTILS
813 if (fPreserveOpsOnFullClear_TestingOnly) {
814 return GrRenderTargetOpList::CanDiscardPreviousOps::kNo;
815 }
816#endif
817 // Regardless of how the clear is implemented (native clear or a fullscreen quad), all prior ops
818 // would normally be overwritten. The one exception is if the render target context is marked as
819 // needing a stencil buffer then there may be a prior op that writes to the stencil buffer.
820 // Although the clear will ignore the stencil buffer, following draw ops may not so we can't get
821 // rid of all the preceding ops. Beware! If we ever add any ops that have a side effect beyond
822 // modifying the stencil buffer we will need a more elaborate tracking system (skbug.com/7002).
823 return GrRenderTargetOpList::CanDiscardPreviousOps(!fNeedsStencil);
824}
825
826void GrRenderTargetContext::setNeedsStencil() {
827 // Don't clear stencil until after we've changed fNeedsStencil. This ensures we don't loop
828 // forever in the event that there are driver bugs and we need to clear as a draw.
829 bool needsStencilClear = !fNeedsStencil;
830
831 fNeedsStencil = true;
832 fRenderTargetProxy->setNeedsStencil();
833
834 if (needsStencilClear) {
835 if (this->caps()->performStencilClearsAsDraws()) {
836 // There is a driver bug with clearing stencil. We must use an op to manually clear the
837 // stencil buffer before the op that required 'setNeedsStencil'.
838 this->internalStencilClear(GrFixedClip::Disabled(), /* inside mask */ false);
839 } else {
840 // Setting the clear stencil load op is preferable. On non-tilers, this lets the flush
841 // code note when the instantiated stencil buffer is already clear and skip the clear
842 // altogether. And on tilers, loading the stencil buffer cleared is even faster than
843 // preserving the previous contents.
844 this->getRTOpList()->setStencilLoadOp(GrLoadOp::kClear);
845 }
846 }
847}
848
Jim Van Verth6a40abc2017-11-02 16:56:09 +0000849void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) {
robertphillips976f5f02016-06-03 10:59:20 -0700850 ASSERT_SINGLE_OWNER_PRIV
851 RETURN_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -0400852 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400853 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clearStencilClip",
854 fRenderTargetContext->fContext);
robertphillips976f5f02016-06-03 10:59:20 -0700855
Robert Phillips72152832017-01-25 17:31:35 -0500856 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
Robert Phillipsb9a02a12017-04-06 11:08:40 -0400857
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500858 fRenderTargetContext->internalStencilClear(clip, insideStencilMask);
859}
860
861void GrRenderTargetContext::internalStencilClear(const GrFixedClip& clip, bool insideStencilMask) {
862 if (this->caps()->performStencilClearsAsDraws()) {
863 const GrUserStencilSettings* ss = GrStencilSettings::SetClipBitSettings(insideStencilMask);
864 SkRect rtRect = SkRect::MakeWH(this->width(), this->height());
865
866 // Configure the paint to have no impact on the color buffer
867 GrPaint paint;
Michael Ludwig0cb2fde2019-05-28 13:14:41 -0400868 paint.setXPFactory(GrDisableColorXPFactory::Get());
Michael Ludwigaa1b6b32019-05-29 14:43:13 -0400869 this->addDrawOp(clip, GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
870 rtRect, ss));
Michael Ludwigc39d0c82019-01-15 10:03:43 -0500871 } else {
872 std::unique_ptr<GrOp> op(GrClearStencilClipOp::Make(fContext, clip, insideStencilMask,
873 fRenderTargetProxy.get()));
874 if (!op) {
875 return;
876 }
877 this->getRTOpList()->addOp(std::move(op), *this->caps());
Robert Phillipse60ad622016-11-17 10:22:48 -0500878 }
robertphillips976f5f02016-06-03 10:59:20 -0700879}
880
Chris Daltonbbfd5162017-11-07 13:35:22 -0700881void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip,
Chris Dalton09e56892019-03-13 00:22:01 -0600882 GrAA doStencilMSAA,
Brian Osman11052242016-10-27 14:47:55 -0400883 const SkMatrix& viewMatrix,
884 const GrPath* path) {
Brian Salomon467921e2017-03-06 16:17:12 -0500885 ASSERT_SINGLE_OWNER_PRIV
886 RETURN_IF_ABANDONED_PRIV
887 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -0400888 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "stencilPath",
889 fRenderTargetContext->fContext);
Brian Salomon467921e2017-03-06 16:17:12 -0500890
Brian Salomon467921e2017-03-06 16:17:12 -0500891 // TODO: extract portions of checkDraw that are relevant to path stenciling.
892 SkASSERT(path);
893 SkASSERT(fRenderTargetContext->caps()->shaderCaps()->pathRenderingSupport());
894
895 // FIXME: Use path bounds instead of this WAR once
896 // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved.
897 SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height());
898
899 // Setup clip
Chris Daltonbbfd5162017-11-07 13:35:22 -0700900 GrAppliedHardClip appliedClip;
901 if (!clip.apply(fRenderTargetContext->width(), fRenderTargetContext->height(), &appliedClip,
902 &bounds)) {
Brian Salomon467921e2017-03-06 16:17:12 -0500903 return;
904 }
905
Michael Ludwig6e17f1d2019-05-15 14:00:20 +0000906
Robert Phillips7c525e62018-06-12 10:11:12 -0400907 std::unique_ptr<GrOp> op = GrStencilPathOp::Make(fRenderTargetContext->fContext,
908 viewMatrix,
Chris Dalton09e56892019-03-13 00:22:01 -0600909 GrAA::kYes == doStencilMSAA,
Brian Salomon467921e2017-03-06 16:17:12 -0500910 path->getFillType(),
911 appliedClip.hasStencilClip(),
Brian Salomon467921e2017-03-06 16:17:12 -0500912 appliedClip.scissorState(),
Brian Salomon467921e2017-03-06 16:17:12 -0500913 path);
Robert Phillipsb9a02a12017-04-06 11:08:40 -0400914 if (!op) {
915 return;
916 }
Brian Salomon97180af2017-03-14 13:42:58 -0400917 op->setClippedBounds(bounds);
Chris Dalton6b982802019-06-27 13:53:46 -0600918
919 fRenderTargetContext->setNeedsStencil();
Robert Phillips2de8cfa2017-06-28 10:33:41 -0400920 fRenderTargetContext->getRTOpList()->addOp(std::move(op), *fRenderTargetContext->caps());
robertphillips976f5f02016-06-03 10:59:20 -0700921}
922
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400923void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
Michael Ludwigd54ca8f2019-02-13 13:25:21 -0500924 GrSamplerState::Filter filter, SkBlendMode mode,
925 const SkPMColor4f& color, const SkRect& srcRect,
Michael Ludwig136f45a2019-02-19 11:44:41 -0500926 const SkRect& dstRect, GrAA aa, GrQuadAAFlags aaFlags,
Brian Salomonb80ffee2018-05-23 16:39:39 -0400927 SkCanvas::SrcRectConstraint constraint,
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400928 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -0500929 sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
Brian Salomon34169692017-08-28 15:32:01 -0400930 ASSERT_SINGLE_OWNER
931 RETURN_IF_ABANDONED
932 SkDEBUGCODE(this->validate();)
Brian Salomonbe3c1d22018-05-21 12:54:39 -0400933 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTexture", fContext);
Brian Salomonf1709042018-10-03 11:57:00 -0400934 if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
935 srcRect.contains(proxy->getWorstCaseBoundsRect())) {
936 constraint = SkCanvas::kFast_SrcRectConstraint;
Brian Salomon34169692017-08-28 15:32:01 -0400937 }
Michael Ludwigd54ca8f2019-02-13 13:25:21 -0500938
Chris Dalton7d6748e2019-03-13 00:34:52 -0600939 GrAAType aaType = this->chooseAAType(aa);
Brian Salomonff9d6d32017-08-30 10:27:49 -0400940 SkRect clippedDstRect = dstRect;
941 SkRect clippedSrcRect = srcRect;
942 if (!crop_filled_rect(this->width(), this->height(), clip, viewMatrix, &clippedDstRect,
943 &clippedSrcRect)) {
944 return;
945 }
Michael Ludwigd54ca8f2019-02-13 13:25:21 -0500946
947 AutoCheckFlush acf(this->drawingManager());
Michael Ludwig22429f92019-06-27 10:44:48 -0400948 auto op = GrTextureOp::Make(fContext, std::move(proxy), filter, color, clippedSrcRect,
949 clippedDstRect, aaType, aaFlags, constraint, viewMatrix,
950 std::move(textureColorSpaceXform), mode);
Brian Salomon2213ee92018-10-02 10:44:21 -0400951 this->addDrawOp(clip, std::move(op));
Brian Salomon34169692017-08-28 15:32:01 -0400952}
953
Michael Ludwigce62dec2019-02-19 11:48:46 -0500954void GrRenderTargetContext::drawTextureQuad(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
955 GrSamplerState::Filter filter, SkBlendMode mode,
956 const SkPMColor4f& color, const SkPoint srcQuad[4],
957 const SkPoint dstQuad[4], GrAA aa,
958 GrQuadAAFlags aaFlags, const SkRect* domain,
959 const SkMatrix& viewMatrix,
960 sk_sp<GrColorSpaceXform> texXform) {
961 ASSERT_SINGLE_OWNER
962 RETURN_IF_ABANDONED
963 SkDEBUGCODE(this->validate();)
964 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureQuad", fContext);
965 if (domain && domain->contains(proxy->getWorstCaseBoundsRect())) {
966 domain = nullptr;
967 }
968
Chris Dalton7d6748e2019-03-13 00:34:52 -0600969 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwigce62dec2019-02-19 11:48:46 -0500970
971 // Unlike drawTexture(), don't bother cropping or optimizing the filter type since we're
972 // sampling an arbitrary quad of the texture.
973 AutoCheckFlush acf(this->drawingManager());
Michael Ludwig22429f92019-06-27 10:44:48 -0400974 auto op = GrTextureOp::MakeQuad(fContext, std::move(proxy), filter, color, srcQuad, dstQuad,
975 aaType, aaFlags, domain, viewMatrix, std::move(texXform), mode);
Michael Ludwigce62dec2019-02-19 11:48:46 -0500976 this->addDrawOp(clip, std::move(op));
977}
978
Brian Salomond7065e72018-10-12 11:42:02 -0400979void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetEntry set[], int cnt,
Michael Ludwiga3c45c72019-01-17 17:26:48 -0500980 GrSamplerState::Filter filter, SkBlendMode mode,
Michael Ludwig31ba7182019-04-03 10:38:06 -0400981 GrAA aa, SkCanvas::SrcRectConstraint constraint,
982 const SkMatrix& viewMatrix,
Brian Osman3d139a42018-11-19 10:42:10 -0500983 sk_sp<GrColorSpaceXform> texXform) {
Brian Salomond7065e72018-10-12 11:42:02 -0400984 ASSERT_SINGLE_OWNER
985 RETURN_IF_ABANDONED
986 SkDEBUGCODE(this->validate();)
987 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTextureSet", fContext);
Michael Ludwiga3c45c72019-01-17 17:26:48 -0500988
Michael Ludwiga3c45c72019-01-17 17:26:48 -0500989 if (mode != SkBlendMode::kSrcOver ||
Robert Phillips9da87e02019-02-04 13:26:26 -0500990 !fContext->priv().caps()->dynamicStateArrayGeometryProcessorTextureSupport()) {
Michael Ludwig22429f92019-06-27 10:44:48 -0400991 // Draw one at a time since the bulk API doesn't support non src-over blending, or the
992 // backend can't support the bulk geometry processor yet.
Michael Ludwig7ae2ab52019-03-05 16:00:20 -0500993 SkMatrix ctm;
Michael Ludwiga3c45c72019-01-17 17:26:48 -0500994 for (int i = 0; i < cnt; ++i) {
Michael Ludwigd54ca8f2019-02-13 13:25:21 -0500995 float alpha = set[i].fAlpha;
Michael Ludwig7ae2ab52019-03-05 16:00:20 -0500996 ctm = viewMatrix;
997 if (set[i].fPreViewMatrix) {
998 ctm.preConcat(*set[i].fPreViewMatrix);
999 }
1000
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001001 if (set[i].fDstClipQuad == nullptr) {
Michael Ludwigce62dec2019-02-19 11:48:46 -05001002 // Stick with original rectangles, which allows the ops to know more about what's
1003 // being drawn.
1004 this->drawTexture(clip, set[i].fProxy, filter, mode, {alpha, alpha, alpha, alpha},
1005 set[i].fSrcRect, set[i].fDstRect, aa, set[i].fAAFlags,
Michael Ludwig31ba7182019-04-03 10:38:06 -04001006 constraint, ctm, texXform);
Michael Ludwigce62dec2019-02-19 11:48:46 -05001007 } else {
1008 // Generate interpolated texture coordinates to match the dst clip
1009 SkPoint srcQuad[4];
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001010 GrMapRectPoints(set[i].fDstRect, set[i].fSrcRect, set[i].fDstClipQuad, srcQuad, 4);
Michael Ludwig31ba7182019-04-03 10:38:06 -04001011 const SkRect* domain = constraint == SkCanvas::kStrict_SrcRectConstraint
1012 ? &set[i].fSrcRect : nullptr;
Michael Ludwigce62dec2019-02-19 11:48:46 -05001013 this->drawTextureQuad(clip, set[i].fProxy, filter, mode,
Michael Ludwig1433cfd2019-02-27 17:12:30 -05001014 {alpha, alpha, alpha, alpha}, srcQuad, set[i].fDstClipQuad,
Michael Ludwig31ba7182019-04-03 10:38:06 -04001015 aa, set[i].fAAFlags, domain, ctm, texXform);
Michael Ludwigce62dec2019-02-19 11:48:46 -05001016 }
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001017 }
1018 } else {
1019 // Can use a single op, avoiding GrPaint creation, and can batch across proxies
Michael Ludwigd54ca8f2019-02-13 13:25:21 -05001020 AutoCheckFlush acf(this->drawingManager());
Chris Dalton7d6748e2019-03-13 00:34:52 -06001021 GrAAType aaType = this->chooseAAType(aa);
Michael Ludwig31ba7182019-04-03 10:38:06 -04001022 auto op = GrTextureOp::MakeSet(fContext, set, cnt, filter, aaType, constraint, viewMatrix,
Michael Ludwig009b92e2019-02-15 16:03:53 -05001023 std::move(texXform));
Michael Ludwiga3c45c72019-01-17 17:26:48 -05001024 this->addDrawOp(clip, std::move(op));
1025 }
Brian Salomond7065e72018-10-12 11:42:02 -04001026}
1027
Brian Osman11052242016-10-27 14:47:55 -04001028void GrRenderTargetContext::drawVertices(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001029 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -04001030 const SkMatrix& viewMatrix,
Brian Osmanae0c50c2017-05-25 16:56:34 -04001031 sk_sp<SkVertices> vertices,
Ruiqi Maoc97a3392018-08-15 10:44:19 -04001032 const SkVertices::Bone bones[],
Ruiqi Mao4ec72f72018-07-10 17:21:07 -04001033 int boneCount,
Brian Osmanae0c50c2017-05-25 16:56:34 -04001034 GrPrimitiveType* overridePrimType) {
Brian Salomon199fb872017-02-06 09:41:10 -05001035 ASSERT_SINGLE_OWNER
1036 RETURN_IF_ABANDONED
1037 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001038 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawVertices", fContext);
Brian Salomon199fb872017-02-06 09:41:10 -05001039
1040 AutoCheckFlush acf(this->drawingManager());
1041
1042 SkASSERT(vertices);
Chris Dalton7d6748e2019-03-13 00:34:52 -06001043 GrAAType aaType = this->chooseAAType(GrAA::kNo);
Brian Salomonf3569f02017-10-24 12:52:33 -04001044 std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
Ruiqi Mao4ec72f72018-07-10 17:21:07 -04001045 fContext, std::move(paint), std::move(vertices), bones, boneCount, viewMatrix, aaType,
Brian Salomonf3569f02017-10-24 12:52:33 -04001046 this->colorSpaceInfo().refColorSpaceXformFromSRGB(), overridePrimType);
Brian Salomonc2f42542017-07-12 14:11:22 -04001047 this->addDrawOp(clip, std::move(op));
robertphillipsea461502015-05-26 11:38:03 -07001048}
1049
1050///////////////////////////////////////////////////////////////////////////////
1051
Brian Osman4d92b892019-03-24 00:53:23 +00001052void GrRenderTargetContext::drawAtlas(const GrClip& clip,
1053 GrPaint&& paint,
1054 const SkMatrix& viewMatrix,
1055 int spriteCount,
1056 const SkRSXform xform[],
1057 const SkRect texRect[],
1058 const SkColor colors[]) {
1059 ASSERT_SINGLE_OWNER
1060 RETURN_IF_ABANDONED
1061 SkDEBUGCODE(this->validate();)
1062 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawAtlas", fContext);
1063
1064 AutoCheckFlush acf(this->drawingManager());
1065
1066 GrAAType aaType = this->chooseAAType(GrAA::kNo);
1067 std::unique_ptr<GrDrawOp> op = GrDrawAtlasOp::Make(fContext, std::move(paint), viewMatrix,
1068 aaType, spriteCount, xform, texRect, colors);
1069 this->addDrawOp(clip, std::move(op));
1070}
1071
1072///////////////////////////////////////////////////////////////////////////////
1073
Brian Osman11052242016-10-27 14:47:55 -04001074void GrRenderTargetContext::drawRRect(const GrClip& origClip,
Brian Salomon82f44312017-01-11 13:42:54 -05001075 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001076 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001077 const SkMatrix& viewMatrix,
1078 const SkRRect& rrect,
1079 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08001080 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07001081 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001082 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001083 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRRect", fContext);
Robert Phillips85290802018-07-02 13:14:28 -04001084
1085 const SkStrokeRec& stroke = style.strokeRec();
1086 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07001087 return;
1088 }
1089
bsalomon7f0d9f32016-08-15 14:49:10 -07001090 GrNoClip noclip;
1091 const GrClip* clip = &origClip;
1092#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
1093 // The Android framework frequently clips rrects to themselves where the clip is non-aa and the
Brian Salomon42521e82016-12-07 16:44:58 -05001094 // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it
bsalomon7f0d9f32016-08-15 14:49:10 -07001095 // doesn't detect that the clip can be ignored (modulo antialiasing). The following test
1096 // attempts to mitigate the stencil clip cost but will only help when the entire clip stack
Michael Ludwig28398842019-03-25 10:24:24 -04001097 // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. This
1098 // only works for filled rrects since the stroke width outsets beyond the rrect itself.
bsalomon7f0d9f32016-08-15 14:49:10 -07001099 SkRRect devRRect;
Michael Ludwig28398842019-03-25 10:24:24 -04001100 if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.transform(viewMatrix, &devRRect) &&
1101 clip->quickContains(devRRect)) {
bsalomon7f0d9f32016-08-15 14:49:10 -07001102 clip = &noclip;
1103 }
1104#endif
bsalomon6663acf2016-05-10 09:14:17 -07001105 SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice
ksakamotoec7f2ac2016-07-05 03:54:53 -07001106
Robert Phillips72152832017-01-25 17:31:35 -05001107 AutoCheckFlush acf(this->drawingManager());
csmartdaltona7f29642016-07-07 08:49:11 -07001108
Chris Dalton7d6748e2019-03-13 00:34:52 -06001109 GrAAType aaType = this->chooseAAType(aa);
Chris Dalton133944a2018-11-16 23:30:29 -05001110
Chris Dalton0dffbab2019-03-27 13:08:50 -06001111 std::unique_ptr<GrDrawOp> op;
Jim Van Verth64b85892019-06-17 12:01:46 -04001112 if (GrAAType::kCoverage == aaType && rrect.isSimple() &&
1113 rrect.getSimpleRadii().fX == rrect.getSimpleRadii().fY &&
1114 viewMatrix.rectStaysRect() && viewMatrix.isSimilarity()) {
1115 // In coverage mode, we draw axis-aligned circular roundrects with the GrOvalOpFactory
1116 // to avoid perf regressions on some platforms.
1117 assert_alive(paint);
1118 op = GrOvalOpFactory::MakeCircularRRectOp(
1119 fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
1120 }
1121 if (!op && style.isSimpleFill()) {
Chris Dalton0dffbab2019-03-27 13:08:50 -06001122 assert_alive(paint);
1123 op = GrFillRRectOp::Make(
1124 fContext, aaType, viewMatrix, rrect, *this->caps(), std::move(paint));
1125 }
Greg Daniel2655ede2019-04-10 00:49:28 +00001126 if (!op && GrAAType::kCoverage == aaType) {
Chris Dalton0dffbab2019-03-27 13:08:50 -06001127 assert_alive(paint);
1128 op = GrOvalOpFactory::MakeRRectOp(
Greg Daniel2655ede2019-04-10 00:49:28 +00001129 fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps());
Chris Dalton0dffbab2019-03-27 13:08:50 -06001130 }
1131 if (op) {
1132 this->addDrawOp(*clip, std::move(op));
1133 return;
robertphillipsea461502015-05-26 11:38:03 -07001134 }
robertphillipsb56f9272016-02-25 11:03:52 -08001135
Mike Klein16885072018-12-11 09:54:31 -05001136 assert_alive(paint);
Brian Salomon2fad74a2017-12-20 13:28:55 -05001137 this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix,
1138 GrShape(rrect, style));
robertphillipsea461502015-05-26 11:38:03 -07001139}
1140
Jim Van Verthc5903412016-11-17 15:27:09 -05001141///////////////////////////////////////////////////////////////////////////////
1142
Jim Van Verth3af1af92017-05-18 15:06:54 -04001143static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) {
1144 SkPoint3 result;
1145 m.mapXY(pt.fX, pt.fY, (SkPoint*)&result.fX);
1146 result.fZ = pt.fZ;
1147 return result;
1148}
1149
1150bool GrRenderTargetContext::drawFastShadow(const GrClip& clip,
Jim Van Verth3af1af92017-05-18 15:06:54 -04001151 const SkMatrix& viewMatrix,
1152 const SkPath& path,
1153 const SkDrawShadowRec& rec) {
Jim Van Verthc5903412016-11-17 15:27:09 -05001154 ASSERT_SINGLE_OWNER
Robert Phillips6a6de562019-02-15 15:19:15 -05001155 if (fContext->priv().abandoned()) {
Jim Van Verth3af1af92017-05-18 15:06:54 -04001156 return true;
1157 }
Jim Van Verthc5903412016-11-17 15:27:09 -05001158 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001159 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawFastShadow", fContext);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001160
1161 // check z plane
1162 bool tiltZPlane = SkToBool(!SkScalarNearlyZero(rec.fZPlaneParams.fX) ||
1163 !SkScalarNearlyZero(rec.fZPlaneParams.fY));
1164 bool skipAnalytic = SkToBool(rec.fFlags & SkShadowFlags::kGeometricOnly_ShadowFlag);
1165 if (tiltZPlane || skipAnalytic || !viewMatrix.rectStaysRect() || !viewMatrix.isSimilarity()) {
1166 return false;
1167 }
1168
1169 SkRRect rrect;
1170 SkRect rect;
1171 // we can only handle rects, circles, and rrects with circular corners
Mike Reed242135a2018-02-22 13:41:39 -05001172 bool isRRect = path.isRRect(&rrect) && SkRRectPriv::IsSimpleCircular(rrect) &&
Jim Van Verth3af1af92017-05-18 15:06:54 -04001173 rrect.radii(SkRRect::kUpperLeft_Corner).fX > SK_ScalarNearlyZero;
1174 if (!isRRect &&
1175 path.isOval(&rect) && SkScalarNearlyEqual(rect.width(), rect.height()) &&
1176 rect.width() > SK_ScalarNearlyZero) {
1177 rrect.setOval(rect);
1178 isRRect = true;
1179 }
1180 if (!isRRect && path.isRect(&rect)) {
1181 rrect.setRect(rect);
1182 isRRect = true;
1183 }
1184
1185 if (!isRRect) {
1186 return false;
1187 }
1188
Jim Van Verthc5903412016-11-17 15:27:09 -05001189 if (rrect.isEmpty()) {
Jim Van Verth3af1af92017-05-18 15:06:54 -04001190 return true;
Jim Van Verthc5903412016-11-17 15:27:09 -05001191 }
1192
Robert Phillips72152832017-01-25 17:31:35 -05001193 AutoCheckFlush acf(this->drawingManager());
Jim Van Verthc5903412016-11-17 15:27:09 -05001194
Jim Van Verth3af1af92017-05-18 15:06:54 -04001195 // transform light
1196 SkPoint3 devLightPos = map(viewMatrix, rec.fLightPos);
1197
1198 // 1/scale
1199 SkScalar devToSrcScale = viewMatrix.isScaleTranslate() ?
1200 SkScalarInvert(viewMatrix[SkMatrix::kMScaleX]) :
1201 sk_float_rsqrt(viewMatrix[SkMatrix::kMScaleX] * viewMatrix[SkMatrix::kMScaleX] +
1202 viewMatrix[SkMatrix::kMSkewX] * viewMatrix[SkMatrix::kMSkewX]);
1203
1204 SkScalar occluderHeight = rec.fZPlaneParams.fZ;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001205 bool transparent = SkToBool(rec.fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag);
1206
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001207 if (SkColorGetA(rec.fAmbientColor) > 0) {
Jim Van Verth1af03d42017-07-31 09:34:58 -04001208 SkScalar devSpaceInsetWidth = SkDrawShadowMetrics::AmbientBlurRadius(occluderHeight);
1209 const SkScalar umbraRecipAlpha = SkDrawShadowMetrics::AmbientRecipAlpha(occluderHeight);
1210 const SkScalar devSpaceAmbientBlur = devSpaceInsetWidth * umbraRecipAlpha;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001211
1212 // Outset the shadow rrect to the border of the penumbra
1213 SkScalar ambientPathOutset = devSpaceInsetWidth * devToSrcScale;
1214 SkRRect ambientRRect;
1215 SkRect outsetRect = rrect.rect().makeOutset(ambientPathOutset, ambientPathOutset);
1216 // If the rrect was an oval then its outset will also be one.
1217 // We set it explicitly to avoid errors.
1218 if (rrect.isOval()) {
1219 ambientRRect = SkRRect::MakeOval(outsetRect);
1220 } else {
Mike Reed242135a2018-02-22 13:41:39 -05001221 SkScalar outsetRad = SkRRectPriv::GetSimpleRadii(rrect).fX + ambientPathOutset;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001222 ambientRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1223 }
1224
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001225 GrColor ambientColor = SkColorToPremulGrColor(rec.fAmbientColor);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001226 if (transparent) {
1227 // set a large inset to force a fill
1228 devSpaceInsetWidth = ambientRRect.width();
1229 }
Jim Van Verth39e71652018-04-23 18:08:45 +00001230
Robert Phillips7c525e62018-06-12 10:11:12 -04001231 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1232 ambientColor,
1233 viewMatrix,
Brian Salomon05969092017-07-13 11:20:51 -04001234 ambientRRect,
1235 devSpaceAmbientBlur,
Jim Van Verthfb186392018-09-11 11:37:46 -04001236 devSpaceInsetWidth);
Robert Phillipse5763782019-04-17 14:38:24 -04001237 if (op) {
1238 this->addDrawOp(clip, std::move(op));
1239 }
Jim Van Verthc5903412016-11-17 15:27:09 -05001240 }
Jim Van Verth3af1af92017-05-18 15:06:54 -04001241
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001242 if (SkColorGetA(rec.fSpotColor) > 0) {
Jim Van Verth1af03d42017-07-31 09:34:58 -04001243 SkScalar devSpaceSpotBlur;
1244 SkScalar spotScale;
1245 SkVector spotOffset;
1246 SkDrawShadowMetrics::GetSpotParams(occluderHeight, devLightPos.fX, devLightPos.fY,
1247 devLightPos.fZ, rec.fLightRadius,
1248 &devSpaceSpotBlur, &spotScale, &spotOffset);
1249 // handle scale of radius due to CTM
Jim Van Verth3af1af92017-05-18 15:06:54 -04001250 const SkScalar srcSpaceSpotBlur = devSpaceSpotBlur * devToSrcScale;
1251
Jim Van Verth3af1af92017-05-18 15:06:54 -04001252 // Adjust translate for the effect of the scale.
1253 spotOffset.fX += spotScale*viewMatrix[SkMatrix::kMTransX];
1254 spotOffset.fY += spotScale*viewMatrix[SkMatrix::kMTransY];
1255 // This offset is in dev space, need to transform it into source space.
1256 SkMatrix ctmInverse;
1257 if (viewMatrix.invert(&ctmInverse)) {
1258 ctmInverse.mapPoints(&spotOffset, 1);
1259 } else {
1260 // Since the matrix is a similarity, this should never happen, but just in case...
1261 SkDebugf("Matrix is degenerate. Will not render spot shadow correctly!\n");
1262 SkASSERT(false);
1263 }
1264
1265 // Compute the transformed shadow rrect
1266 SkRRect spotShadowRRect;
1267 SkMatrix shadowTransform;
1268 shadowTransform.setScaleTranslate(spotScale, spotScale, spotOffset.fX, spotOffset.fY);
1269 rrect.transform(shadowTransform, &spotShadowRRect);
Mike Reed242135a2018-02-22 13:41:39 -05001270 SkScalar spotRadius = SkRRectPriv::GetSimpleRadii(spotShadowRRect).fX;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001271
1272 // Compute the insetWidth
Jim Van Verth1af03d42017-07-31 09:34:58 -04001273 SkScalar blurOutset = srcSpaceSpotBlur;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001274 SkScalar insetWidth = blurOutset;
1275 if (transparent) {
1276 // If transparent, just do a fill
1277 insetWidth += spotShadowRRect.width();
1278 } else {
1279 // For shadows, instead of using a stroke we specify an inset from the penumbra
1280 // border. We want to extend this inset area so that it meets up with the caster
1281 // geometry. The inset geometry will by default already be inset by the blur width.
1282 //
1283 // We compare the min and max corners inset by the radius between the original
1284 // rrect and the shadow rrect. The distance between the two plus the difference
1285 // between the scaled radius and the original radius gives the distance from the
1286 // transformed shadow shape to the original shape in that corner. The max
1287 // of these gives the maximum distance we need to cover.
1288 //
1289 // Since we are outsetting by 1/2 the blur distance, we just add the maxOffset to
1290 // that to get the full insetWidth.
1291 SkScalar maxOffset;
1292 if (rrect.isRect()) {
1293 // Manhattan distance works better for rects
1294 maxOffset = SkTMax(SkTMax(SkTAbs(spotShadowRRect.rect().fLeft -
1295 rrect.rect().fLeft),
1296 SkTAbs(spotShadowRRect.rect().fTop -
1297 rrect.rect().fTop)),
1298 SkTMax(SkTAbs(spotShadowRRect.rect().fRight -
1299 rrect.rect().fRight),
1300 SkTAbs(spotShadowRRect.rect().fBottom -
1301 rrect.rect().fBottom)));
1302 } else {
Mike Reed242135a2018-02-22 13:41:39 -05001303 SkScalar dr = spotRadius - SkRRectPriv::GetSimpleRadii(rrect).fX;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001304 SkPoint upperLeftOffset = SkPoint::Make(spotShadowRRect.rect().fLeft -
1305 rrect.rect().fLeft + dr,
1306 spotShadowRRect.rect().fTop -
1307 rrect.rect().fTop + dr);
1308 SkPoint lowerRightOffset = SkPoint::Make(spotShadowRRect.rect().fRight -
1309 rrect.rect().fRight - dr,
1310 spotShadowRRect.rect().fBottom -
1311 rrect.rect().fBottom - dr);
Cary Clarkdf429f32017-11-08 11:44:31 -05001312 maxOffset = SkScalarSqrt(SkTMax(SkPointPriv::LengthSqd(upperLeftOffset),
1313 SkPointPriv::LengthSqd(lowerRightOffset))) + dr;
Jim Van Verth3af1af92017-05-18 15:06:54 -04001314 }
Jim Van Verth4c8c1e82018-04-23 17:14:48 -04001315 insetWidth += SkTMax(blurOutset, maxOffset);
Jim Van Verth3af1af92017-05-18 15:06:54 -04001316 }
1317
1318 // Outset the shadow rrect to the border of the penumbra
1319 SkRect outsetRect = spotShadowRRect.rect().makeOutset(blurOutset, blurOutset);
1320 if (spotShadowRRect.isOval()) {
1321 spotShadowRRect = SkRRect::MakeOval(outsetRect);
1322 } else {
1323 SkScalar outsetRad = spotRadius + blurOutset;
1324 spotShadowRRect = SkRRect::MakeRectXY(outsetRect, outsetRad, outsetRad);
1325 }
1326
Jim Van Verthb1b80f72018-01-18 15:19:13 -05001327 GrColor spotColor = SkColorToPremulGrColor(rec.fSpotColor);
Jim Van Verth34d6e4b2017-06-09 11:09:03 -04001328
Robert Phillips7c525e62018-06-12 10:11:12 -04001329 std::unique_ptr<GrDrawOp> op = GrShadowRRectOp::Make(fContext,
1330 spotColor,
1331 viewMatrix,
Brian Salomon05969092017-07-13 11:20:51 -04001332 spotShadowRRect,
Jim Van Verth1af03d42017-07-31 09:34:58 -04001333 2.0f * devSpaceSpotBlur,
Brian Salomon05969092017-07-13 11:20:51 -04001334 insetWidth);
Robert Phillipse5763782019-04-17 14:38:24 -04001335 if (op) {
1336 this->addDrawOp(clip, std::move(op));
1337 }
Jim Van Verth3af1af92017-05-18 15:06:54 -04001338 }
1339
1340 return true;
Jim Van Verthc5903412016-11-17 15:27:09 -05001341}
1342
1343///////////////////////////////////////////////////////////////////////////////
1344
Brian Osman11052242016-10-27 14:47:55 -04001345bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001346 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001347 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001348 const SkMatrix& viewMatrix,
1349 const SkRRect& origOuter,
1350 const SkRRect& origInner) {
robertphillips00095892016-02-29 13:50:40 -08001351 SkASSERT(!origInner.isEmpty());
1352 SkASSERT(!origOuter.isEmpty());
1353
Brian Salomon65749212017-12-01 16:01:47 -05001354 SkTCopyOnFirstWrite<SkRRect> inner(origInner), outer(origOuter);
1355
Chris Dalton7d6748e2019-03-13 00:34:52 -06001356 GrAAType aaType = this->chooseAAType(aa);
Brian Salomon45839f92017-12-04 09:02:35 -05001357
1358 if (GrAAType::kMSAA == aaType) {
1359 return false;
1360 }
1361
Greg Daniel2655ede2019-04-10 00:49:28 +00001362 if (GrAAType::kCoverage == aaType && SkRRectPriv::IsCircle(*inner)
1363 && SkRRectPriv::IsCircle(*outer)) {
Brian Salomon65749212017-12-01 16:01:47 -05001364 auto outerR = outer->width() / 2.f;
1365 auto innerR = inner->width() / 2.f;
1366 auto cx = outer->getBounds().fLeft + outerR;
1367 auto cy = outer->getBounds().fTop + outerR;
1368 if (SkScalarNearlyEqual(cx, inner->getBounds().fLeft + innerR) &&
1369 SkScalarNearlyEqual(cy, inner->getBounds().fTop + innerR)) {
1370 auto avgR = (innerR + outerR) / 2.f;
1371 auto circleBounds = SkRect::MakeLTRB(cx - avgR, cy - avgR, cx + avgR, cy + avgR);
1372 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
1373 stroke.setStrokeStyle(outerR - innerR);
Greg Daniel2655ede2019-04-10 00:49:28 +00001374 auto op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix,
Robert Phillips7c525e62018-06-12 10:11:12 -04001375 circleBounds, GrStyle(stroke, nullptr),
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001376 this->caps()->shaderCaps());
Brian Salomon65749212017-12-01 16:01:47 -05001377 if (op) {
1378 this->addDrawOp(clip, std::move(op));
1379 return true;
1380 }
Mike Klein16885072018-12-11 09:54:31 -05001381 assert_alive(paint);
Brian Salomon65749212017-12-01 16:01:47 -05001382 }
1383 }
1384
Ethan Nicholas0f3c7322017-11-09 14:51:17 -05001385 GrClipEdgeType innerEdgeType, outerEdgeType;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001386 if (GrAAType::kCoverage == aaType) {
Ethan Nicholas1706f842017-11-10 11:58:19 -05001387 innerEdgeType = GrClipEdgeType::kInverseFillAA;
1388 outerEdgeType = GrClipEdgeType::kFillAA;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001389 } else {
Ethan Nicholas1706f842017-11-10 11:58:19 -05001390 innerEdgeType = GrClipEdgeType::kInverseFillBW;
1391 outerEdgeType = GrClipEdgeType::kFillBW;
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001392 }
robertphillips00095892016-02-29 13:50:40 -08001393
robertphillips00095892016-02-29 13:50:40 -08001394 SkMatrix inverseVM;
1395 if (!viewMatrix.isIdentity()) {
1396 if (!origInner.transform(viewMatrix, inner.writable())) {
1397 return false;
1398 }
1399 if (!origOuter.transform(viewMatrix, outer.writable())) {
1400 return false;
1401 }
1402 if (!viewMatrix.invert(&inverseVM)) {
1403 return false;
1404 }
1405 } else {
1406 inverseVM.reset();
halcanary9d524f22016-03-29 09:03:52 -07001407 }
robertphillips00095892016-02-29 13:50:40 -08001408
Ethan Nicholaseace9352018-10-15 20:09:54 +00001409 const auto& caps = *this->caps()->shaderCaps();
robertphillips00095892016-02-29 13:50:40 -08001410 // TODO these need to be a geometry processors
Ethan Nicholaseace9352018-10-15 20:09:54 +00001411 auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps);
robertphillips00095892016-02-29 13:50:40 -08001412 if (!innerEffect) {
1413 return false;
1414 }
1415
Ethan Nicholaseace9352018-10-15 20:09:54 +00001416 auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps);
robertphillips00095892016-02-29 13:50:40 -08001417 if (!outerEffect) {
1418 return false;
1419 }
1420
Brian Salomon82f44312017-01-11 13:42:54 -05001421 paint.addCoverageFragmentProcessor(std::move(innerEffect));
1422 paint.addCoverageFragmentProcessor(std::move(outerEffect));
robertphillips00095892016-02-29 13:50:40 -08001423
1424 SkRect bounds = outer->getBounds();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001425 if (GrAAType::kCoverage == aaType) {
robertphillips00095892016-02-29 13:50:40 -08001426 bounds.outset(SK_ScalarHalf, SK_ScalarHalf);
1427 }
halcanary9d524f22016-03-29 09:03:52 -07001428
Brian Salomon82f44312017-01-11 13:42:54 -05001429 this->fillRectWithLocalMatrix(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), bounds,
1430 inverseVM);
robertphillips00095892016-02-29 13:50:40 -08001431 return true;
1432}
1433
Brian Osman11052242016-10-27 14:47:55 -04001434void GrRenderTargetContext::drawDRRect(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001435 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001436 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001437 const SkMatrix& viewMatrix,
1438 const SkRRect& outer,
1439 const SkRRect& inner) {
robertphillips00095892016-02-29 13:50:40 -08001440 ASSERT_SINGLE_OWNER
1441 RETURN_IF_ABANDONED
1442 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001443 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawDRRect", fContext);
robertphillips00095892016-02-29 13:50:40 -08001444
1445 SkASSERT(!outer.isEmpty());
1446 SkASSERT(!inner.isEmpty());
1447
Robert Phillips72152832017-01-25 17:31:35 -05001448 AutoCheckFlush acf(this->drawingManager());
robertphillips00095892016-02-29 13:50:40 -08001449
Brian Salomon82f44312017-01-11 13:42:54 -05001450 if (this->drawFilledDRRect(clip, std::move(paint), aa, viewMatrix, outer, inner)) {
robertphillips00095892016-02-29 13:50:40 -08001451 return;
1452 }
Mike Klein16885072018-12-11 09:54:31 -05001453 assert_alive(paint);
robertphillips00095892016-02-29 13:50:40 -08001454
1455 SkPath path;
1456 path.setIsVolatile(true);
1457 path.addRRect(inner);
1458 path.addRRect(outer);
1459 path.setFillType(SkPath::kEvenOdd_FillType);
Brian Salomon2fad74a2017-12-20 13:28:55 -05001460 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrShape(path));
robertphillips00095892016-02-29 13:50:40 -08001461}
1462
robertphillipsea461502015-05-26 11:38:03 -07001463///////////////////////////////////////////////////////////////////////////////
1464
Brian Osman11052242016-10-27 14:47:55 -04001465void GrRenderTargetContext::drawRegion(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001466 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001467 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001468 const SkMatrix& viewMatrix,
1469 const SkRegion& region,
Stan Iliev73d8fd92017-08-02 15:36:24 -04001470 const GrStyle& style,
1471 const GrUserStencilSettings* ss) {
msarettcc319b92016-08-25 18:07:18 -07001472 ASSERT_SINGLE_OWNER
1473 RETURN_IF_ABANDONED
1474 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001475 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawRegion", fContext);
msarettcc319b92016-08-25 18:07:18 -07001476
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001477 if (GrAA::kYes == aa) {
Brian Salomonfc527d22016-12-14 21:07:01 -05001478 // GrRegionOp performs no antialiasing but is much faster, so here we check the matrix
Brian Salomonc57c7c92016-12-06 14:47:34 -05001479 // to see whether aa is really required.
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001480 if (!SkToBool(viewMatrix.getType() & ~(SkMatrix::kTranslate_Mask)) &&
Brian Salomon34169692017-08-28 15:32:01 -04001481 SkScalarIsInt(viewMatrix.getTranslateX()) &&
1482 SkScalarIsInt(viewMatrix.getTranslateY())) {
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001483 aa = GrAA::kNo;
1484 }
Brian Salomonc57c7c92016-12-06 14:47:34 -05001485 }
msarettcc319b92016-08-25 18:07:18 -07001486 bool complexStyle = !style.isSimpleFill();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001487 if (complexStyle || GrAA::kYes == aa) {
msarettcc319b92016-08-25 18:07:18 -07001488 SkPath path;
1489 region.getBoundaryPath(&path);
Robert Phillips46a13382018-08-23 13:53:01 -04001490 path.setIsVolatile(true);
1491
Brian Salomon82f44312017-01-11 13:42:54 -05001492 return this->drawPath(clip, std::move(paint), aa, viewMatrix, path, style);
msarettcc319b92016-08-25 18:07:18 -07001493 }
1494
Chris Dalton7d6748e2019-03-13 00:34:52 -06001495 GrAAType aaType = this->chooseAAType(GrAA::kNo);
Robert Phillips7c525e62018-06-12 10:11:12 -04001496 std::unique_ptr<GrDrawOp> op = GrRegionOp::Make(fContext, std::move(paint), viewMatrix, region,
1497 aaType, ss);
Brian Salomonf0366322017-07-11 15:53:05 -04001498 this->addDrawOp(clip, std::move(op));
msarettcc319b92016-08-25 18:07:18 -07001499}
1500
Brian Osman11052242016-10-27 14:47:55 -04001501void GrRenderTargetContext::drawOval(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001502 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001503 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001504 const SkMatrix& viewMatrix,
1505 const SkRect& oval,
1506 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08001507 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07001508 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07001509 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001510 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawOval", fContext);
robertphillips2e1e51f2015-10-15 08:01:48 -07001511
Robert Phillips7484d202018-07-03 09:09:08 -04001512 const SkStrokeRec& stroke = style.strokeRec();
1513
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001514 if (oval.isEmpty() && !style.pathEffect()) {
Robert Phillips7484d202018-07-03 09:09:08 -04001515 if (stroke.getStyle() == SkStrokeRec::kFill_Style) {
1516 return;
1517 }
1518
1519 this->drawRect(clip, std::move(paint), aa, viewMatrix, oval, &style);
Brian Salomon62e4f3d2018-04-20 13:54:11 -04001520 return;
robertphillipsea461502015-05-26 11:38:03 -07001521 }
1522
Robert Phillips72152832017-01-25 17:31:35 -05001523 AutoCheckFlush acf(this->drawingManager());
csmartdaltona7f29642016-07-07 08:49:11 -07001524
Chris Dalton7d6748e2019-03-13 00:34:52 -06001525 GrAAType aaType = this->chooseAAType(aa);
Chris Dalton0dffbab2019-03-27 13:08:50 -06001526
1527 std::unique_ptr<GrDrawOp> op;
Jim Van Verthd7871cc2019-06-27 13:08:04 -04001528 if (GrAAType::kCoverage == aaType && oval.width() > SK_ScalarNearlyZero &&
1529 oval.width() == oval.height() && viewMatrix.isSimilarity()) {
Jim Van Verth64b85892019-06-17 12:01:46 -04001530 // We don't draw true circles as round rects in coverage mode, because it can
1531 // cause perf regressions on some platforms as compared to the dedicated circle Op.
1532 assert_alive(paint);
1533 op = GrOvalOpFactory::MakeCircleOp(fContext, std::move(paint), viewMatrix, oval, style,
1534 this->caps()->shaderCaps());
1535 }
1536 if (!op && style.isSimpleFill()) {
Chris Dalton82eb9e72019-03-21 14:26:39 -06001537 // GrFillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate
1538 // the arc equation. This same special geometry and fragment branch also turn out to be a
1539 // substantial optimization for drawing ovals (namely, by not evaluating the arc equation
1540 // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw
1541 // ovals the exact same way we do round rects.
Jim Van Verth64b85892019-06-17 12:01:46 -04001542 assert_alive(paint);
1543 op = GrFillRRectOp::Make(fContext, aaType, viewMatrix, SkRRect::MakeOval(oval),
1544 *this->caps(), std::move(paint));
Chris Dalton0dffbab2019-03-27 13:08:50 -06001545 }
Greg Daniel2655ede2019-04-10 00:49:28 +00001546 if (!op && GrAAType::kCoverage == aaType) {
Chris Dalton0dffbab2019-03-27 13:08:50 -06001547 assert_alive(paint);
Greg Daniel2655ede2019-04-10 00:49:28 +00001548 op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style,
1549 this->caps()->shaderCaps());
Chris Dalton0dffbab2019-03-27 13:08:50 -06001550 }
1551 if (op) {
1552 this->addDrawOp(clip, std::move(op));
1553 return;
robertphillipsea461502015-05-26 11:38:03 -07001554 }
robertphillipsb56f9272016-02-25 11:03:52 -08001555
Mike Klein16885072018-12-11 09:54:31 -05001556 assert_alive(paint);
Brian Salomon5209d7f2018-04-20 16:52:42 -04001557 this->drawShapeUsingPathRenderer(
1558 clip, std::move(paint), aa, viewMatrix,
1559 GrShape(SkRRect::MakeOval(oval), SkPath::kCW_Direction, 2, false, style));
robertphillipsea461502015-05-26 11:38:03 -07001560}
1561
Brian Osman11052242016-10-27 14:47:55 -04001562void GrRenderTargetContext::drawArc(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001563 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05001564 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04001565 const SkMatrix& viewMatrix,
1566 const SkRect& oval,
1567 SkScalar startAngle,
1568 SkScalar sweepAngle,
1569 bool useCenter,
1570 const GrStyle& style) {
Robert Phillipsf1d0ced2017-02-10 09:31:01 -05001571 ASSERT_SINGLE_OWNER
1572 RETURN_IF_ABANDONED
1573 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001574 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawArc", fContext);
Robert Phillipsf1d0ced2017-02-10 09:31:01 -05001575
1576 AutoCheckFlush acf(this->drawingManager());
1577
Chris Dalton7d6748e2019-03-13 00:34:52 -06001578 GrAAType aaType = this->chooseAAType(aa);
Greg Daniel2655ede2019-04-10 00:49:28 +00001579 if (GrAAType::kCoverage == aaType) {
1580 const GrShaderCaps* shaderCaps = this->caps()->shaderCaps();
1581 std::unique_ptr<GrDrawOp> op = GrOvalOpFactory::MakeArcOp(fContext,
1582 std::move(paint),
1583 viewMatrix,
1584 oval,
1585 startAngle,
1586 sweepAngle,
1587 useCenter,
1588 style,
1589 shaderCaps);
1590 if (op) {
1591 this->addDrawOp(clip, std::move(op));
1592 return;
1593 }
1594 assert_alive(paint);
bsalomon4f3a0ca2016-08-22 13:14:26 -07001595 }
Brian Salomone4949402018-04-26 15:22:04 -04001596 this->drawShapeUsingPathRenderer(
1597 clip, std::move(paint), aa, viewMatrix,
1598 GrShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style));
bsalomon4f3a0ca2016-08-22 13:14:26 -07001599}
1600
Brian Osman11052242016-10-27 14:47:55 -04001601void GrRenderTargetContext::drawImageLattice(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05001602 GrPaint&& paint,
Brian Osman11052242016-10-27 14:47:55 -04001603 const SkMatrix& viewMatrix,
Brian Salomon2a943df2018-05-04 13:43:19 -04001604 sk_sp<GrTextureProxy> image,
1605 sk_sp<GrColorSpaceXform> csxf,
1606 GrSamplerState::Filter filter,
Brian Osman11052242016-10-27 14:47:55 -04001607 std::unique_ptr<SkLatticeIter> iter,
1608 const SkRect& dst) {
joshualitt1de610a2016-01-06 08:26:09 -08001609 ASSERT_SINGLE_OWNER
joshualitt33a5fce2015-11-18 13:28:51 -08001610 RETURN_IF_ABANDONED
1611 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04001612 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawImageLattice", fContext);
joshualitt33a5fce2015-11-18 13:28:51 -08001613
Robert Phillips72152832017-01-25 17:31:35 -05001614 AutoCheckFlush acf(this->drawingManager());
joshualitt33a5fce2015-11-18 13:28:51 -08001615
Brian Salomon2a943df2018-05-04 13:43:19 -04001616 std::unique_ptr<GrDrawOp> op =
Robert Phillips7c525e62018-06-12 10:11:12 -04001617 GrLatticeOp::MakeNonAA(fContext, std::move(paint), viewMatrix, std::move(image),
1618 std::move(csxf), filter, std::move(iter), dst);
Brian Salomon815486c2017-07-11 08:52:13 -04001619 this->addDrawOp(clip, std::move(op));
joshualitt33a5fce2015-11-18 13:28:51 -08001620}
1621
Greg Daniel64cc9aa2018-10-19 13:54:56 -04001622void GrRenderTargetContext::drawDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable,
1623 const SkRect& bounds) {
1624 std::unique_ptr<GrOp> op(GrDrawableOp::Make(fContext, std::move(drawable), bounds));
1625 SkASSERT(op);
1626 this->getRTOpList()->addOp(std::move(op), *this->caps());
1627}
1628
Brian Salomon031b0ba2019-05-23 11:05:26 -04001629sk_sp<GrRenderTargetContext> GrRenderTargetContext::rescale(const SkImageInfo& info,
1630 const SkIRect& srcRect,
1631 SkSurface::RescaleGamma rescaleGamma,
1632 SkFilterQuality rescaleQuality) {
Brian Salomonab32f652019-05-10 14:24:50 -04001633 auto direct = fContext->priv().asDirectContext();
1634 if (!direct) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001635 return nullptr;
Brian Salomonab32f652019-05-10 14:24:50 -04001636 }
1637 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001638 return nullptr;
1639 }
1640
1641 // We currently don't know our own alpha type, we assume it's premul if we have an alpha channel
1642 // and opaque otherwise.
1643 if (!GrPixelConfigIsAlphaOnly(fRenderTargetProxy->config()) &&
1644 info.alphaType() != kPremul_SkAlphaType) {
1645 return nullptr;
1646 }
1647
1648 int srcW = srcRect.width();
1649 int srcH = srcRect.height();
1650 int srcX = srcRect.fLeft;
1651 int srcY = srcRect.fTop;
Greg Daniel46cfbc62019-06-07 11:43:30 -04001652 sk_sp<GrTextureProxy> texProxy = sk_ref_sp(fRenderTargetProxy->asTextureProxy());
Brian Salomon031b0ba2019-05-23 11:05:26 -04001653 SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint;
Greg Daniel46cfbc62019-06-07 11:43:30 -04001654 if (!texProxy) {
1655 texProxy = GrSurfaceProxy::Copy(fContext, fRenderTargetProxy.get(), GrMipMapped::kNo,
1656 srcRect, SkBackingFit::kApprox, SkBudgeted::kNo);
1657 if (!texProxy) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001658 return nullptr;
1659 }
1660 srcX = 0;
1661 srcY = 0;
1662 constraint = SkCanvas::kFast_SrcRectConstraint;
Brian Salomon031b0ba2019-05-23 11:05:26 -04001663 }
1664
1665 float sx = (float)info.width() / srcW;
1666 float sy = (float)info.height() / srcH;
1667
1668 // How many bilerp/bicubic steps to do in X and Y. + means upscaling, - means downscaling.
1669 int stepsX;
1670 int stepsY;
1671 if (rescaleQuality > kNone_SkFilterQuality) {
1672 stepsX = static_cast<int>((sx > 1.f) ? std::ceil(std::log2f(sx))
1673 : std::floor(std::log2f(sx)));
1674 stepsY = static_cast<int>((sy > 1.f) ? std::ceil(std::log2f(sy))
1675 : std::floor(std::log2f(sy)));
1676 } else {
1677 stepsX = sx != 1.f;
1678 stepsY = sy != 1.f;
1679 }
1680 SkASSERT(stepsX || stepsY);
Brian Salomon024bd002019-06-11 11:38:16 -04001681 auto rescaleColorSapce = this->colorSpaceInfo().refColorSpace();
Brian Salomond6287472019-06-24 15:50:07 -04001682 auto currRTC = sk_ref_sp(this);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001683 // Assume we should ignore the rescale linear request if the surface has no color space since
1684 // it's unclear how we'd linearize from an unknown color space.
1685 if (rescaleGamma == SkSurface::RescaleGamma::kLinear &&
Brian Salomon024bd002019-06-11 11:38:16 -04001686 rescaleColorSapce.get() && !rescaleColorSapce->gammaIsLinear()) {
1687 auto cs = rescaleColorSapce->makeLinearGamma();
Brian Salomon031b0ba2019-05-23 11:05:26 -04001688 auto backendFormat = this->caps()->getBackendFormatFromGrColorType(GrColorType::kRGBA_F16,
1689 GrSRGBEncoded::kNo);
Brian Salomon024bd002019-06-11 11:38:16 -04001690 auto xform = GrColorSpaceXform::Make(rescaleColorSapce.get(), kPremul_SkAlphaType, cs.get(),
Greg Daniel46cfbc62019-06-07 11:43:30 -04001691 kPremul_SkAlphaType);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001692 // We'll fall back to kRGBA_8888 if half float not supported.
1693 auto linearRTC = fContext->priv().makeDeferredRenderTargetContextWithFallback(
Brian Salomond6287472019-06-24 15:50:07 -04001694 backendFormat, SkBackingFit::kExact, srcW, srcH, kRGBA_half_GrPixelConfig,
1695 GrColorType::kRGBA_F16, cs, 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001696 if (!linearRTC) {
1697 return nullptr;
1698 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001699 linearRTC->drawTexture(GrNoClip(), texProxy,
Brian Salomon031b0ba2019-05-23 11:05:26 -04001700 GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
1701 SK_PMColor4fWHITE, SkRect::Make(srcRect), SkRect::MakeWH(srcW, srcH),
1702 GrAA::kNo, GrQuadAAFlags::kNone, constraint, SkMatrix::I(),
1703 std::move(xform));
Greg Daniel46cfbc62019-06-07 11:43:30 -04001704 texProxy = linearRTC->asTextureProxyRef();
Brian Salomond6287472019-06-24 15:50:07 -04001705 currRTC = std::move(linearRTC);
Brian Salomon024bd002019-06-11 11:38:16 -04001706 rescaleColorSapce = std::move(cs);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001707 srcX = 0;
1708 srcY = 0;
1709 constraint = SkCanvas::kFast_SrcRectConstraint;
1710 }
1711 while (stepsX || stepsY) {
1712 int nextW = info.width();
1713 int nextH = info.height();
1714 if (stepsX < 0) {
1715 nextW = info.width() << (-stepsX - 1);
1716 stepsX++;
1717 } else if (stepsX != 0) {
1718 if (stepsX > 1) {
1719 nextW = srcW * 2;
1720 }
1721 --stepsX;
1722 }
1723 if (stepsY < 0) {
1724 nextH = info.height() << (-stepsY - 1);
1725 stepsY++;
1726 } else if (stepsY != 0) {
1727 if (stepsY > 1) {
1728 nextH = srcH * 2;
1729 }
1730 --stepsY;
1731 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001732 GrBackendFormat backendFormat = texProxy->backendFormat().makeTexture2D();
1733 GrPixelConfig config = texProxy->config();
Brian Salomond6287472019-06-24 15:50:07 -04001734 GrColorType colorType = currRTC->colorSpaceInfo().colorType();
Brian Salomon024bd002019-06-11 11:38:16 -04001735 auto cs = rescaleColorSapce;
Brian Salomon900dda82019-06-03 13:12:55 -04001736 sk_sp<GrColorSpaceXform> xform;
Brian Salomon031b0ba2019-05-23 11:05:26 -04001737 if (!stepsX && !stepsY) {
1738 // Might as well fold conversion to final info in the last step.
1739 backendFormat = this->caps()->getBackendFormatFromColorType(info.colorType());
1740 config = this->caps()->getConfigFromBackendFormat(backendFormat, info.colorType());
1741 cs = info.refColorSpace();
Brian Salomond6287472019-06-24 15:50:07 -04001742 colorType = SkColorTypeToGrColorType(info.colorType());
Brian Salomon024bd002019-06-11 11:38:16 -04001743 xform = GrColorSpaceXform::Make(rescaleColorSapce.get(),
Brian Salomon900dda82019-06-03 13:12:55 -04001744 kPremul_SkAlphaType, cs.get(), info.alphaType());
Brian Salomon031b0ba2019-05-23 11:05:26 -04001745 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001746 currRTC = fContext->priv().makeDeferredRenderTargetContextWithFallback(
Brian Salomond6287472019-06-24 15:50:07 -04001747 backendFormat, SkBackingFit::kExact, nextW, nextH, config, colorType, std::move(cs),
1748 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
Greg Daniel46cfbc62019-06-07 11:43:30 -04001749 if (!currRTC) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001750 return nullptr;
1751 }
1752 auto dstRect = SkRect::MakeWH(nextW, nextH);
1753 if (rescaleQuality == kHigh_SkFilterQuality) {
1754 SkMatrix matrix;
1755 matrix.setScaleTranslate((float)srcW / nextW, (float)srcH / nextH, srcX, srcY);
1756 std::unique_ptr<GrFragmentProcessor> fp;
Brian Salomona86fc7a2019-05-28 20:42:58 -04001757 auto dir = GrBicubicEffect::Direction::kXY;
1758 if (nextW == srcW) {
1759 dir = GrBicubicEffect::Direction::kY;
1760 } else if (nextH == srcH) {
1761 dir = GrBicubicEffect::Direction::kX;
1762 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001763 if (srcW != texProxy->width() || srcH != texProxy->height()) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001764 auto domain = GrTextureDomain::MakeTexelDomain(
1765 SkIRect::MakeXYWH(srcX, srcY, srcW, srcH), GrTextureDomain::kClamp_Mode);
Brian Salomon1127c0b2019-06-13 20:22:10 +00001766 fp = GrBicubicEffect::Make(texProxy, matrix, domain, dir, kPremul_SkAlphaType);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001767 } else {
Brian Salomon1127c0b2019-06-13 20:22:10 +00001768 fp = GrBicubicEffect::Make(texProxy, matrix, dir, kPremul_SkAlphaType);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001769 }
Brian Salomon900dda82019-06-03 13:12:55 -04001770 if (xform) {
1771 fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(xform));
1772 }
Brian Salomon031b0ba2019-05-23 11:05:26 -04001773 GrPaint paint;
1774 paint.addColorFragmentProcessor(std::move(fp));
1775 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Michael Ludwig61328202019-06-19 14:48:58 +00001776 currRTC->fillRectToRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
1777 dstRect, dstRect);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001778 } else {
1779 auto filter = rescaleQuality == kNone_SkFilterQuality ? GrSamplerState::Filter::kNearest
1780 : GrSamplerState::Filter::kBilerp;
1781 auto srcSubset = SkRect::MakeXYWH(srcX, srcY, srcW, srcH);
Greg Daniel46cfbc62019-06-07 11:43:30 -04001782 currRTC->drawTexture(GrNoClip(), texProxy, filter, SkBlendMode::kSrc, SK_PMColor4fWHITE,
1783 srcSubset, dstRect, GrAA::kNo, GrQuadAAFlags::kNone, constraint,
1784 SkMatrix::I(), std::move(xform));
Brian Salomon031b0ba2019-05-23 11:05:26 -04001785 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001786 texProxy = currRTC->asTextureProxyRef();
Brian Salomon031b0ba2019-05-23 11:05:26 -04001787 srcX = srcY = 0;
1788 srcW = nextW;
1789 srcH = nextH;
1790 constraint = SkCanvas::kFast_SrcRectConstraint;
1791 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04001792 SkASSERT(currRTC);
1793 return currRTC;
Brian Salomon031b0ba2019-05-23 11:05:26 -04001794}
1795
1796void GrRenderTargetContext::asyncRescaleAndReadPixels(
1797 const SkImageInfo& info, const SkIRect& srcRect, SkSurface::RescaleGamma rescaleGamma,
1798 SkFilterQuality rescaleQuality, ReadPixelsCallback callback, ReadPixelsContext context) {
1799 auto direct = fContext->priv().asDirectContext();
1800 if (!direct) {
1801 callback(context, nullptr, 0);
1802 return;
1803 }
1804 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
1805 callback(context, nullptr, 0);
1806 return;
Brian Salomonab32f652019-05-10 14:24:50 -04001807 }
1808 // We currently don't know our own alpha type, we assume it's premul if we have an alpha channel
1809 // and opaque otherwise.
Brian Salomon201700f2019-05-17 12:05:44 -04001810 if (!GrPixelConfigIsAlphaOnly(fRenderTargetProxy->config()) &&
1811 info.alphaType() != kPremul_SkAlphaType) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001812 callback(context, nullptr, 0);
1813 return;
1814 }
1815 auto dstCT = SkColorTypeToGrColorType(info.colorType());
1816 bool needsRescale = srcRect.width() != info.width() || srcRect.height() != info.height();
1817 GrPixelConfig configOfFinalContext = fRenderTargetProxy->config();
Brian Salomonf30b1c12019-06-20 12:25:02 -04001818 auto backendFormatOfFinalContext = fRenderTargetProxy->backendFormat();
Brian Salomon031b0ba2019-05-23 11:05:26 -04001819 if (needsRescale) {
Brian Salomonf30b1c12019-06-20 12:25:02 -04001820 backendFormatOfFinalContext = this->caps()->getBackendFormatFromColorType(info.colorType());
1821 configOfFinalContext = this->caps()->getConfigFromBackendFormat(backendFormatOfFinalContext,
1822 info.colorType());
Brian Salomon031b0ba2019-05-23 11:05:26 -04001823 }
Brian Salomonf30b1c12019-06-20 12:25:02 -04001824 auto readInfo = this->caps()->supportedReadPixelsColorType(configOfFinalContext,
1825 backendFormatOfFinalContext, dstCT);
1826 // Fail if we can't read from the source surface's color type.
1827 if (readInfo.fColorType == GrColorType::kUnknown) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001828 callback(context, nullptr, 0);
1829 return;
1830 }
1831 // Fail if readCT does not have all of readCT's color channels.
Brian Salomonf30b1c12019-06-20 12:25:02 -04001832 if (GrColorTypeComponentFlags(dstCT) & ~GrColorTypeComponentFlags(readInfo.fColorType)) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001833 callback(context, nullptr, 0);
1834 return;
1835 }
1836
1837 sk_sp<GrRenderTargetContext> rtc;
1838 int x = srcRect.fLeft;
1839 int y = srcRect.fTop;
1840 if (needsRescale) {
1841 rtc = this->rescale(info, srcRect, rescaleGamma, rescaleQuality);
1842 if (!rtc) {
1843 callback(context, nullptr, 0);
1844 return;
1845 }
1846 SkASSERT(SkColorSpace::Equals(rtc->colorSpaceInfo().colorSpace(), info.colorSpace()));
1847 SkASSERT(rtc->origin() == kTopLeft_GrSurfaceOrigin);
1848 x = y = 0;
1849 } else {
1850 sk_sp<GrColorSpaceXform> xform =
1851 GrColorSpaceXform::Make(this->colorSpaceInfo().colorSpace(), kPremul_SkAlphaType,
1852 info.colorSpace(), info.alphaType());
1853 // Insert a draw to a temporary surface if we need to do a y-flip or color space conversion.
1854 if (this->origin() == kBottomLeft_GrSurfaceOrigin || xform) {
1855 sk_sp<GrTextureProxy> texProxy = sk_ref_sp(fRenderTargetProxy->asTextureProxy());
1856 const auto backendFormat = fRenderTargetProxy->backendFormat().makeTexture2D();
1857 SkRect srcRectToDraw = SkRect::Make(srcRect);
1858 // If the src is not texturable first try to make a copy to a texture.
1859 if (!texProxy) {
Greg Daniel46cfbc62019-06-07 11:43:30 -04001860 texProxy = GrSurfaceProxy::Copy(fContext, fRenderTargetProxy.get(),
1861 GrMipMapped::kNo, srcRect, SkBackingFit::kApprox,
1862 SkBudgeted::kNo);
1863 if (!texProxy) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001864 callback(context, nullptr, 0);
1865 return;
1866 }
Brian Salomon031b0ba2019-05-23 11:05:26 -04001867 srcRectToDraw = SkRect::MakeWH(srcRect.width(), srcRect.height());
1868 }
1869 rtc = direct->priv().makeDeferredRenderTargetContext(
1870 backendFormat, SkBackingFit::kApprox, srcRect.width(), srcRect.height(),
Brian Salomond6287472019-06-24 15:50:07 -04001871 fRenderTargetProxy->config(), this->colorSpaceInfo().colorType(),
1872 info.refColorSpace(), 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001873 if (!rtc) {
1874 callback(context, nullptr, 0);
1875 return;
1876 }
1877 rtc->drawTexture(GrNoClip(), std::move(texProxy), GrSamplerState::Filter::kNearest,
1878 SkBlendMode::kSrc, SK_PMColor4fWHITE, srcRectToDraw,
1879 SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
1880 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
1881 std::move(xform));
1882 x = y = 0;
1883 } else {
1884 rtc = sk_ref_sp(this);
1885 }
1886 }
Brian Salomon024bd002019-06-11 11:38:16 -04001887 return rtc->asyncReadPixels(SkIRect::MakeXYWH(x, y, info.width(), info.height()),
1888 info.colorType(), callback, context);
Brian Salomon031b0ba2019-05-23 11:05:26 -04001889}
1890
Brian Salomon024bd002019-06-11 11:38:16 -04001891GrRenderTargetContext::PixelTransferResult GrRenderTargetContext::transferPixels(
1892 GrColorType dstCT, const SkIRect& rect) {
1893 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
1894 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
Brian Salomon031b0ba2019-05-23 11:05:26 -04001895 auto direct = fContext->priv().asDirectContext();
1896 if (!direct) {
Brian Salomon024bd002019-06-11 11:38:16 -04001897 return {};
Brian Salomon031b0ba2019-05-23 11:05:26 -04001898 }
1899 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
Brian Salomon024bd002019-06-11 11:38:16 -04001900 return {};
Brian Salomon031b0ba2019-05-23 11:05:26 -04001901 }
Brian Salomonf30b1c12019-06-20 12:25:02 -04001902 auto supportedRead = this->caps()->supportedReadPixelsColorType(
1903 fRenderTargetProxy->config(), fRenderTargetProxy->backendFormat(), dstCT);
Brian Salomoncd734f62019-05-10 16:32:54 -04001904 // Fail if readCT does not have all of readCT's color channels.
Brian Salomonf30b1c12019-06-20 12:25:02 -04001905 if (GrColorTypeComponentFlags(dstCT) & ~GrColorTypeComponentFlags(supportedRead.fColorType)) {
Brian Salomon024bd002019-06-11 11:38:16 -04001906 return {};
Brian Salomonab32f652019-05-10 14:24:50 -04001907 }
1908
Brian Salomon031b0ba2019-05-23 11:05:26 -04001909 if (!this->caps()->transferBufferSupport() ||
Brian Salomonf30b1c12019-06-20 12:25:02 -04001910 !this->caps()->transferFromOffsetAlignment(supportedRead.fColorType)) {
Brian Salomon024bd002019-06-11 11:38:16 -04001911 return {};
1912 }
1913
Brian Salomonf30b1c12019-06-20 12:25:02 -04001914 size_t rowBytes = GrColorTypeBytesPerPixel(supportedRead.fColorType) * rect.width();
Brian Salomon024bd002019-06-11 11:38:16 -04001915 size_t size = rowBytes * rect.height();
1916 auto buffer = direct->priv().resourceProvider()->createBuffer(
1917 size, GrGpuBufferType::kXferGpuToCpu, GrAccessPattern::kStream_GrAccessPattern);
1918 if (!buffer) {
1919 return {};
1920 }
Brian Salomonf30b1c12019-06-20 12:25:02 -04001921 auto srcRect = rect;
1922 bool flip = this->origin() == kBottomLeft_GrSurfaceOrigin;
1923 if (flip) {
1924 srcRect = SkIRect::MakeLTRB(rect.fLeft, this->height() - rect.fBottom, rect.fRight,
1925 this->height() - rect.fTop);
1926 }
1927 auto op = GrTransferFromOp::Make(fContext, srcRect, supportedRead.fColorType, buffer, 0);
1928 this->getRTOpList()->addOp(std::move(op), *this->caps());
Brian Salomon024bd002019-06-11 11:38:16 -04001929 PixelTransferResult result;
1930 result.fTransferBuffer = std::move(buffer);
Brian Salomonf30b1c12019-06-20 12:25:02 -04001931 if (supportedRead.fColorType != dstCT || supportedRead.fSwizzle != GrSwizzle("rgba") || flip) {
1932 result.fPixelConverter = [w = rect.width(), h = rect.height(), dstCT, supportedRead](
1933 void* dst, const void* src) {
1934 GrPixelInfo srcInfo;
1935 srcInfo.fColorInfo.fAlphaType = kPremul_SkAlphaType;
1936 srcInfo.fColorInfo.fColorType = supportedRead.fColorType;
1937 srcInfo.fColorInfo.fColorSpace = nullptr;
1938 srcInfo.fRowBytes = GrColorTypeBytesPerPixel(supportedRead.fColorType) * w;
1939
1940 GrPixelInfo dstInfo;
1941 dstInfo.fColorInfo.fAlphaType = kPremul_SkAlphaType;
1942 dstInfo.fColorInfo.fColorType = dstCT;
1943 dstInfo.fColorInfo.fColorSpace = nullptr;
1944 dstInfo.fRowBytes = GrColorTypeBytesPerPixel(dstCT) * w;
1945
1946 srcInfo.fWidth = dstInfo.fWidth = w;
1947 srcInfo.fHeight = dstInfo.fHeight = h;
1948
1949 GrConvertPixels(dstInfo, dst, srcInfo, src, supportedRead.fSwizzle);
1950 };
Brian Salomon024bd002019-06-11 11:38:16 -04001951 }
1952 return result;
1953}
1954
1955void GrRenderTargetContext::asyncReadPixels(const SkIRect& rect, SkColorType colorType,
1956 ReadPixelsCallback callback,
1957 ReadPixelsContext context) {
1958 SkASSERT(rect.fLeft >= 0 && rect.fRight <= this->width());
1959 SkASSERT(rect.fTop >= 0 && rect.fBottom <= this->height());
1960
1961 auto transferResult = this->transferPixels(SkColorTypeToGrColorType(colorType), rect);
1962
1963 if (!transferResult.fTransferBuffer) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001964 SkAutoPixmapStorage pm;
Brian Salomon024bd002019-06-11 11:38:16 -04001965 auto ii = SkImageInfo::Make(rect.width(), rect.height(), colorType, kPremul_SkAlphaType,
1966 this->colorSpaceInfo().refColorSpace());
1967 pm.alloc(ii);
1968 if (!this->readPixels(ii, pm.writable_addr(), pm.rowBytes(), rect.fLeft, rect.fTop)) {
Brian Salomon031b0ba2019-05-23 11:05:26 -04001969 callback(context, nullptr, 0);
Brian Salomonab32f652019-05-10 14:24:50 -04001970 }
Brian Salomon031b0ba2019-05-23 11:05:26 -04001971 callback(context, pm.addr(), pm.rowBytes());
1972 return;
Brian Salomonab32f652019-05-10 14:24:50 -04001973 }
Brian Salomoncd734f62019-05-10 16:32:54 -04001974
Brian Salomonab32f652019-05-10 14:24:50 -04001975 struct FinishContext {
1976 ReadPixelsCallback* fClientCallback;
1977 ReadPixelsContext fClientContext;
Brian Salomon024bd002019-06-11 11:38:16 -04001978 int fW, fH;
1979 SkColorType fColorType;
1980 PixelTransferResult fTransferResult;
Brian Salomonab32f652019-05-10 14:24:50 -04001981 };
1982 // Assumption is that the caller would like to flush. We could take a parameter or require an
1983 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
1984 // callback to GrGpu until after the next flush that flushes our op list, though.
Brian Salomon024bd002019-06-11 11:38:16 -04001985 auto* finishContext = new FinishContext{callback, context, rect.width(),
1986 rect.height(), colorType, std::move(transferResult)};
Brian Salomonab32f652019-05-10 14:24:50 -04001987 auto finishCallback = [](GrGpuFinishedContext c) {
Brian Salomon024bd002019-06-11 11:38:16 -04001988 const auto* context = reinterpret_cast<const FinishContext*>(c);
1989 const void* data = context->fTransferResult.fTransferBuffer->map();
Brian Salomoncd734f62019-05-10 16:32:54 -04001990 if (!data) {
1991 (*context->fClientCallback)(context->fClientContext, nullptr, 0);
1992 delete context;
1993 return;
1994 }
1995 SkAutoPixmapStorage pm;
Brian Salomon024bd002019-06-11 11:38:16 -04001996 if (context->fTransferResult.fPixelConverter) {
1997 pm.alloc(SkImageInfo::Make(context->fW, context->fH, context->fColorType,
1998 kPremul_SkAlphaType, nullptr));
1999 context->fTransferResult.fPixelConverter(pm.writable_addr(), data);
2000 data = pm.addr();
Brian Salomoncd734f62019-05-10 16:32:54 -04002001 }
Brian Salomon024bd002019-06-11 11:38:16 -04002002 (*context->fClientCallback)(context->fClientContext, data,
2003 context->fW * SkColorTypeBytesPerPixel(context->fColorType));
2004 delete context;
2005 };
2006 GrFlushInfo flushInfo;
2007 flushInfo.fFinishedContext = finishContext;
2008 flushInfo.fFinishedProc = finishCallback;
2009 this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
2010}
2011
2012void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(
2013 SkYUVColorSpace yuvColorSpace, sk_sp<SkColorSpace> dstColorSpace, const SkIRect& srcRect,
2014 int dstW, int dstH, RescaleGamma rescaleGamma, SkFilterQuality rescaleQuality,
2015 ReadPixelsCallbackYUV420 callback, ReadPixelsContext context) {
2016 SkASSERT(srcRect.fLeft >= 0 && srcRect.fRight <= this->width());
2017 SkASSERT(srcRect.fTop >= 0 && srcRect.fBottom <= this->height());
2018 SkASSERT((dstW % 2 == 0) && (dstH % 2 == 0));
2019 auto direct = fContext->priv().asDirectContext();
2020 if (!direct) {
2021 callback(context, nullptr, nullptr);
2022 return;
2023 }
2024 if (fRenderTargetProxy->wrapsVkSecondaryCB()) {
2025 callback(context, nullptr, nullptr);
2026 return;
2027 }
2028 if (dstW & 0x1) {
2029 return;
2030 }
2031 int x = srcRect.fLeft;
2032 int y = srcRect.fTop;
2033 auto rtc = sk_ref_sp(this);
2034 bool needsRescale = srcRect.width() != dstW || srcRect.height() != dstH;
2035 if (needsRescale) {
2036 auto info = SkImageInfo::Make(dstW, dstH, kRGBA_8888_SkColorType, kPremul_SkAlphaType,
2037 dstColorSpace);
2038 // TODO: Incorporate the YUV conversion into last pass of rescaling.
2039 rtc = this->rescale(info, srcRect, rescaleGamma, rescaleQuality);
2040 if (!rtc) {
2041 callback(context, nullptr, nullptr);
2042 return;
Brian Salomonab32f652019-05-10 14:24:50 -04002043 }
Brian Salomon024bd002019-06-11 11:38:16 -04002044 SkASSERT(SkColorSpace::Equals(rtc->colorSpaceInfo().colorSpace(), info.colorSpace()));
2045 SkASSERT(rtc->origin() == kTopLeft_GrSurfaceOrigin);
2046 x = y = 0;
2047 } else {
2048 sk_sp<GrColorSpaceXform> xform =
2049 GrColorSpaceXform::Make(this->colorSpaceInfo().colorSpace(), kPremul_SkAlphaType,
2050 dstColorSpace.get(), kPremul_SkAlphaType);
2051 if (xform) {
2052 sk_sp<GrTextureProxy> texProxy = this->asTextureProxyRef();
2053 // TODO: Do something if the input is not a texture already.
2054 if (!texProxy) {
2055 callback(context, nullptr, nullptr);
2056 return;
2057 }
2058 const auto backendFormat =
2059 this->caps()->getBackendFormatFromColorType(kRGBA_8888_SkColorType);
2060 SkRect srcRectToDraw = SkRect::Make(srcRect);
2061 rtc = direct->priv().makeDeferredRenderTargetContext(
2062 backendFormat, SkBackingFit::kApprox, dstW, dstH, fRenderTargetProxy->config(),
Brian Salomond6287472019-06-24 15:50:07 -04002063 this->colorSpaceInfo().colorType(), dstColorSpace, 1, GrMipMapped::kNo,
2064 kTopLeft_GrSurfaceOrigin);
Brian Salomon024bd002019-06-11 11:38:16 -04002065 if (!rtc) {
2066 callback(context, nullptr, nullptr);
2067 return;
2068 }
2069 rtc->drawTexture(GrNoClip(), std::move(texProxy), GrSamplerState::Filter::kNearest,
2070 SkBlendMode::kSrc, SK_PMColor4fWHITE, srcRectToDraw,
2071 SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
2072 GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
2073 std::move(xform));
2074 x = y = 0;
2075 }
2076 }
2077 auto srcProxy = rtc->asTextureProxyRef();
2078 // TODO: Do something if the input is not a texture already.
2079 if (!srcProxy) {
2080 callback(context, nullptr, nullptr);
2081 return;
2082 }
Brian Salomonf30b1c12019-06-20 12:25:02 -04002083 const auto backendFormat = this->caps()->getBackendFormatFromGrColorType(GrColorType::kAlpha_8,
2084 GrSRGBEncoded::kNo);
Brian Salomon024bd002019-06-11 11:38:16 -04002085 auto yRTC = direct->priv().makeDeferredRenderTargetContext(
Brian Salomond6287472019-06-24 15:50:07 -04002086 backendFormat, SkBackingFit::kApprox, dstW, dstH, kAlpha_8_GrPixelConfig,
2087 GrColorType::kAlpha_8, dstColorSpace, 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon024bd002019-06-11 11:38:16 -04002088 auto uRTC = direct->priv().makeDeferredRenderTargetContext(
Brian Salomonf30b1c12019-06-20 12:25:02 -04002089 backendFormat, SkBackingFit::kApprox, dstW / 2, dstH / 2, kAlpha_8_GrPixelConfig,
Brian Salomond6287472019-06-24 15:50:07 -04002090 GrColorType::kAlpha_8, dstColorSpace, 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon024bd002019-06-11 11:38:16 -04002091 auto vRTC = direct->priv().makeDeferredRenderTargetContext(
Brian Salomonf30b1c12019-06-20 12:25:02 -04002092 backendFormat, SkBackingFit::kApprox, dstW / 2, dstH / 2, kAlpha_8_GrPixelConfig,
Brian Salomond6287472019-06-24 15:50:07 -04002093 GrColorType::kAlpha_8, dstColorSpace, 1, GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin);
Brian Salomon024bd002019-06-11 11:38:16 -04002094 if (!yRTC || !uRTC || !vRTC) {
2095 callback(context, nullptr, nullptr);
2096 return;
2097 }
2098
2099 static constexpr float kRec601M[] {
2100 65.481f / 255, 128.553f / 255, 24.966f / 255, 16.f / 255, // y
2101 -37.797f / 255, -74.203f / 255, 112.0f / 255, 128.f / 255, // u
2102 112.f / 255, -93.786f / 255, -18.214f / 255, 128.f / 255, // v
2103 };
2104 static constexpr float kRec709M[] {
2105 45.5594f / 255, 156.6288f / 255, 15.8118f / 255, 16.f / 255, // y
2106 -25.6642f / 255, -86.3358f / 255, 112.f / 255, 128.f / 255, // u
2107 112.f / 255, -101.7303f / 255, -10.2697f / 255, 128.f / 255, // v
2108 };
2109 static constexpr float kJpegM[] {
2110 0.299f , 0.587f , 0.114f , 0.f / 255, // y
2111 -0.168736f, -0.331264f, 0.5f , 128.f / 255, // u
2112 0.5f , -0.418688f, -0.081312f, 128.f / 255, // v
2113 };
2114 static constexpr float kIM[] {
2115 1.f, 0.f, 0.f, 0.f,
2116 0.f, 1.f, 0.f, 0.f,
2117 0.f, 0.f, 1.f, 0.f,
2118 };
2119 const float* baseM = kIM;
2120 switch (yuvColorSpace) {
2121 case kRec601_SkYUVColorSpace:
2122 baseM = kRec601M;
2123 break;
2124 case kRec709_SkYUVColorSpace:
2125 baseM = kRec709M;
2126 break;
2127 case kJPEG_SkYUVColorSpace:
2128 baseM = kJpegM;
2129 break;
2130 case kIdentity_SkYUVColorSpace:
2131 baseM = kIM;
2132 break;
2133 }
2134 // TODO: Use one transfer buffer for all three planes to reduce map/unmap cost?
2135
2136 auto texMatrix = SkMatrix::MakeTrans(x, y);
2137
Michael Ludwig61328202019-06-19 14:48:58 +00002138 SkRect dstRectY = SkRect::MakeWH(dstW, dstH);
2139 SkRect dstRectUV = SkRect::MakeWH(dstW / 2, dstH / 2);
2140
Brian Salomon024bd002019-06-11 11:38:16 -04002141 // This matrix generates (r,g,b,a) = (0, 0, 0, y)
2142 float yM[20];
Brian Salomondf586b72019-06-11 13:26:37 -04002143 std::fill_n(yM, 15, 0.f);
Brian Salomon024bd002019-06-11 11:38:16 -04002144 yM[15] = baseM[0]; yM[16] = baseM[1]; yM[17] = baseM[2]; yM[18] = 0; yM[19] = baseM[3];
2145 GrPaint yPaint;
2146 yPaint.addColorTextureProcessor(srcProxy, texMatrix);
2147 auto yFP = GrColorMatrixFragmentProcessor::Make(yM, false, true, false);
2148 yPaint.addColorFragmentProcessor(std::move(yFP));
2149 yPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Michael Ludwig61328202019-06-19 14:48:58 +00002150 yRTC->fillRectToRect(GrNoClip(), std::move(yPaint), GrAA::kNo, SkMatrix::I(),
2151 dstRectY, dstRectY);
Brian Salomon024bd002019-06-11 11:38:16 -04002152 auto yTransfer = yRTC->transferPixels(GrColorType::kAlpha_8,
2153 SkIRect::MakeWH(yRTC->width(), yRTC->height()));
2154 if (!yTransfer.fTransferBuffer) {
2155 callback(context, nullptr, nullptr);
2156 return;
2157 }
2158
2159 texMatrix.preScale(2.f, 2.f);
2160 // This matrix generates (r,g,b,a) = (0, 0, 0, u)
2161 float uM[20];
Brian Salomondf586b72019-06-11 13:26:37 -04002162 std::fill_n(uM, 15, 0.f);
Brian Salomon024bd002019-06-11 11:38:16 -04002163 uM[15] = baseM[4]; uM[16] = baseM[5]; uM[17] = baseM[6]; uM[18] = 0; uM[19] = baseM[7];
2164 GrPaint uPaint;
2165 uPaint.addColorTextureProcessor(srcProxy, texMatrix, GrSamplerState::ClampBilerp());
2166 auto uFP = GrColorMatrixFragmentProcessor::Make(uM, false, true, false);
2167 uPaint.addColorFragmentProcessor(std::move(uFP));
2168 uPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Michael Ludwig61328202019-06-19 14:48:58 +00002169 uRTC->fillRectToRect(GrNoClip(), std::move(uPaint), GrAA::kNo, SkMatrix::I(),
2170 dstRectUV, dstRectUV);
Brian Salomon024bd002019-06-11 11:38:16 -04002171 auto uTransfer = uRTC->transferPixels(GrColorType::kAlpha_8,
2172 SkIRect::MakeWH(uRTC->width(), uRTC->height()));
2173 if (!uTransfer.fTransferBuffer) {
2174 callback(context, nullptr, nullptr);
2175 return;
2176 }
2177
2178 // This matrix generates (r,g,b,a) = (0, 0, 0, v)
2179 float vM[20];
Brian Salomondf586b72019-06-11 13:26:37 -04002180 std::fill_n(vM, 15, 0.f);
Brian Salomon024bd002019-06-11 11:38:16 -04002181 vM[15] = baseM[8]; vM[16] = baseM[9]; vM[17] = baseM[10]; vM[18] = 0; vM[19] = baseM[11];
2182 GrPaint vPaint;
2183 vPaint.addColorTextureProcessor(srcProxy, texMatrix, GrSamplerState::ClampBilerp());
2184 auto vFP = GrColorMatrixFragmentProcessor::Make(vM, false, true, false);
2185 vPaint.addColorFragmentProcessor(std::move(vFP));
2186 vPaint.setPorterDuffXPFactory(SkBlendMode::kSrc);
Michael Ludwig61328202019-06-19 14:48:58 +00002187 vRTC->fillRectToRect(GrNoClip(), std::move(vPaint), GrAA::kNo, SkMatrix::I(),
2188 dstRectUV, dstRectUV);
Brian Salomon024bd002019-06-11 11:38:16 -04002189 auto vTransfer = vRTC->transferPixels(GrColorType::kAlpha_8,
2190 SkIRect::MakeWH(vRTC->width(), vRTC->height()));
2191 if (!vTransfer.fTransferBuffer) {
2192 callback(context, nullptr, nullptr);
2193 return;
2194 }
2195
2196 struct FinishContext {
2197 ReadPixelsCallbackYUV420* fClientCallback;
2198 ReadPixelsContext fClientContext;
2199 int fW, fH;
2200 PixelTransferResult fYTransfer;
2201 PixelTransferResult fUTransfer;
2202 PixelTransferResult fVTransfer;
2203 };
2204 // Assumption is that the caller would like to flush. We could take a parameter or require an
2205 // explicit flush from the caller. We'd have to have a way to defer attaching the finish
2206 // callback to GrGpu until after the next flush that flushes our op list, though.
2207 auto* finishContext = new FinishContext{callback,
2208 context,
2209 dstW,
2210 dstH,
2211 std::move(yTransfer),
2212 std::move(uTransfer),
2213 std::move(vTransfer)};
2214 auto finishCallback = [](GrGpuFinishedContext c) {
2215 const auto* context = reinterpret_cast<const FinishContext*>(c);
2216 const void* y = context->fYTransfer.fTransferBuffer->map();
2217 const void* u = context->fUTransfer.fTransferBuffer->map();
2218 const void* v = context->fVTransfer.fTransferBuffer->map();
2219 if (!y || !u || !v) {
2220 if (y) {
2221 context->fYTransfer.fTransferBuffer->unmap();
2222 }
2223 if (u) {
2224 context->fUTransfer.fTransferBuffer->unmap();
2225 }
2226 if (v) {
2227 context->fVTransfer.fTransferBuffer->unmap();
2228 }
2229 (*context->fClientCallback)(context->fClientContext, nullptr, 0);
2230 delete context;
2231 return;
2232 }
2233 size_t w = SkToSizeT(context->fW);
2234 size_t h = SkToSizeT(context->fH);
2235 std::unique_ptr<uint8_t[]> yTemp;
2236 if (context->fYTransfer.fPixelConverter) {
2237 yTemp.reset(new uint8_t[w * h]);
2238 context->fYTransfer.fPixelConverter(yTemp.get(), y);
2239 y = yTemp.get();
2240 }
2241 std::unique_ptr<uint8_t[]> uTemp;
2242 if (context->fUTransfer.fPixelConverter) {
2243 uTemp.reset(new uint8_t[w / 2 * h / 2]);
2244 context->fUTransfer.fPixelConverter(uTemp.get(), u);
2245 u = uTemp.get();
2246 }
2247 std::unique_ptr<uint8_t[]> vTemp;
2248 if (context->fVTransfer.fPixelConverter) {
2249 vTemp.reset(new uint8_t[w / 2 * h / 2]);
2250 context->fVTransfer.fPixelConverter(vTemp.get(), v);
2251 v = vTemp.get();
2252 }
2253 const void* data[] = {y, u, v};
2254 size_t rowBytes[] = {w, w / 2, w / 2};
2255 (*context->fClientCallback)(context->fClientContext, data, rowBytes);
2256 context->fYTransfer.fTransferBuffer->unmap();
2257 context->fUTransfer.fTransferBuffer->unmap();
2258 context->fVTransfer.fTransferBuffer->unmap();
Brian Salomonab32f652019-05-10 14:24:50 -04002259 delete context;
2260 };
2261 GrFlushInfo flushInfo;
2262 flushInfo.fFinishedContext = finishContext;
2263 flushInfo.fFinishedProc = finishCallback;
2264 this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo);
Brian Salomonab32f652019-05-10 14:24:50 -04002265}
2266
Greg Daniele6bfb7d2019-04-17 15:26:11 -04002267GrSemaphoresSubmitted GrRenderTargetContext::flush(SkSurface::BackendSurfaceAccess access,
2268 const GrFlushInfo& info) {
robertphillips8c523e02016-07-26 07:41:00 -07002269 ASSERT_SINGLE_OWNER
Robert Phillips6a6de562019-02-15 15:19:15 -05002270 if (fContext->priv().abandoned()) {
Robert Phillipsa9162df2019-02-11 14:12:03 -05002271 return GrSemaphoresSubmitted::kNo;
2272 }
robertphillips8c523e02016-07-26 07:41:00 -07002273 SkDEBUGCODE(this->validate();)
Robert Phillips15c91422019-05-07 16:54:48 -04002274 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "flush", fContext);
robertphillips8c523e02016-07-26 07:41:00 -07002275
Greg Daniele6bfb7d2019-04-17 15:26:11 -04002276 return this->drawingManager()->flushSurface(fRenderTargetProxy.get(), access, info);
Greg Daniela5cb7812017-06-16 09:45:32 -04002277}
2278
Greg Danielc64ee462017-06-15 16:59:49 -04002279bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores,
Robert Phillipsbc4994a2019-02-14 08:36:56 -05002280 const GrBackendSemaphore waitSemaphores[]) {
Greg Daniela5cb7812017-06-16 09:45:32 -04002281 ASSERT_SINGLE_OWNER
Greg Danielc64ee462017-06-15 16:59:49 -04002282 RETURN_FALSE_IF_ABANDONED
Greg Daniela5cb7812017-06-16 09:45:32 -04002283 SkDEBUGCODE(this->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04002284 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "waitOnSemaphores", fContext);
Greg Daniela5cb7812017-06-16 09:45:32 -04002285
2286 AutoCheckFlush acf(this->drawingManager());
2287
Brian Salomon9ff5acb2019-05-08 09:04:47 -04002288 if (numSemaphores && !this->caps()->semaphoreSupport()) {
Greg Danielc64ee462017-06-15 16:59:49 -04002289 return false;
2290 }
2291
Robert Phillipsbc4994a2019-02-14 08:36:56 -05002292 auto direct = fContext->priv().asDirectContext();
2293 if (!direct) {
2294 return false;
2295 }
2296
2297 auto resourceProvider = direct->priv().resourceProvider();
Robert Phillips6be756b2018-01-16 15:07:54 -05002298
Greg Daniela5cb7812017-06-16 09:45:32 -04002299 for (int i = 0; i < numSemaphores; ++i) {
Robert Phillips6be756b2018-01-16 15:07:54 -05002300 sk_sp<GrSemaphore> sema = resourceProvider->wrapBackendSemaphore(
Greg Daniel17b7c052018-01-09 13:55:33 -05002301 waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait,
2302 kAdopt_GrWrapOwnership);
Robert Phillipsbc4994a2019-02-14 08:36:56 -05002303 std::unique_ptr<GrOp> waitOp(GrSemaphoreOp::MakeWait(fContext, std::move(sema),
Robert Phillips7c525e62018-06-12 10:11:12 -04002304 fRenderTargetProxy.get()));
Greg Danielcb324152019-02-25 11:36:53 -05002305 this->getRTOpList()->addWaitOp(std::move(waitOp), *this->caps());
Greg Daniela5cb7812017-06-16 09:45:32 -04002306 }
Greg Danielc64ee462017-06-15 16:59:49 -04002307 return true;
robertphillips8c523e02016-07-26 07:41:00 -07002308}
joshualitt33a5fce2015-11-18 13:28:51 -08002309
Robert Phillips65a88fa2017-08-08 08:36:22 -04002310void GrRenderTargetContext::insertEventMarker(const SkString& str) {
Robert Phillips88a32ef2018-06-07 11:05:56 -04002311 std::unique_ptr<GrOp> op(GrDebugMarkerOp::Make(fContext, fRenderTargetProxy.get(), str));
Robert Phillips65a88fa2017-08-08 08:36:22 -04002312 this->getRTOpList()->addOp(std::move(op), *this->caps());
2313}
2314
Robert Phillipsbe9aff22019-02-15 11:33:22 -05002315const GrCaps* GrRenderTargetContext::caps() const {
2316 return fContext->priv().caps();
2317}
2318
Brian Osman11052242016-10-27 14:47:55 -04002319void GrRenderTargetContext::drawPath(const GrClip& clip,
Brian Salomon82f44312017-01-11 13:42:54 -05002320 GrPaint&& paint,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002321 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04002322 const SkMatrix& viewMatrix,
Brian Salomon40b77a62017-12-22 11:25:52 -05002323 const SkPath& path,
Brian Osman11052242016-10-27 14:47:55 -04002324 const GrStyle& style) {
joshualitt1de610a2016-01-06 08:26:09 -08002325 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07002326 RETURN_IF_ABANDONED
robertphillips2e1e51f2015-10-15 08:01:48 -07002327 SkDEBUGCODE(this->validate();)
Robert Phillips20390c32018-08-17 11:01:03 -04002328 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawPath", fContext);
2329
Brian Salomon40b77a62017-12-22 11:25:52 -05002330 GrShape shape(path, style);
Robert Phillips20390c32018-08-17 11:01:03 -04002331
Robert Phillips27927a52018-08-20 13:18:12 -04002332 this->drawShape(clip, std::move(paint), aa, viewMatrix, shape);
Robert Phillips20390c32018-08-17 11:01:03 -04002333}
2334
2335void GrRenderTargetContext::drawShape(const GrClip& clip,
2336 GrPaint&& paint,
2337 GrAA aa,
2338 const SkMatrix& viewMatrix,
2339 const GrShape& shape) {
2340 ASSERT_SINGLE_OWNER
2341 RETURN_IF_ABANDONED
2342 SkDEBUGCODE(this->validate();)
2343 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawShape", fContext);
2344
Brian Salomon2fad74a2017-12-20 13:28:55 -05002345 if (shape.isEmpty()) {
2346 if (shape.inverseFilled()) {
2347 this->drawPaint(clip, std::move(paint), viewMatrix);
2348 }
2349 return;
robertphillipsea461502015-05-26 11:38:03 -07002350 }
2351
Robert Phillips72152832017-01-25 17:31:35 -05002352 AutoCheckFlush acf(this->drawingManager());
robertphillipsea461502015-05-26 11:38:03 -07002353
Brian Salomon2fad74a2017-12-20 13:28:55 -05002354 if (!shape.style().hasPathEffect()) {
Chris Dalton7d6748e2019-03-13 00:34:52 -06002355 GrAAType aaType = this->chooseAAType(aa);
Brian Salomon2fad74a2017-12-20 13:28:55 -05002356 SkRRect rrect;
2357 // We can ignore the starting point and direction since there is no path effect.
2358 bool inverted;
2359 if (shape.asRRect(&rrect, nullptr, nullptr, &inverted) && !inverted) {
2360 if (rrect.isRect()) {
2361 this->drawRect(clip, std::move(paint), aa, viewMatrix, rrect.rect(),
2362 &shape.style());
2363 return;
2364 } else if (rrect.isOval()) {
2365 this->drawOval(clip, std::move(paint), aa, viewMatrix, rrect.rect(), shape.style());
robertphillipsea461502015-05-26 11:38:03 -07002366 return;
2367 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002368 this->drawRRect(clip, std::move(paint), aa, viewMatrix, rrect, shape.style());
2369 return;
Robert Phillips73653b42018-08-22 12:42:42 -04002370 } else if (GrAAType::kCoverage == aaType && shape.style().isSimpleFill() &&
2371 viewMatrix.rectStaysRect()) {
2372 // TODO: the rectStaysRect restriction could be lifted if we were willing to apply
2373 // the matrix to all the points individually rather than just to the rect
2374 SkRect rects[2];
2375 if (shape.asNestedRects(rects)) {
2376 // Concave AA paths are expensive - try to avoid them for special cases
Michael Ludwig72ab3462018-12-10 12:43:36 -05002377 std::unique_ptr<GrDrawOp> op = GrStrokeRectOp::MakeNested(
Robert Phillips73653b42018-08-22 12:42:42 -04002378 fContext, std::move(paint), viewMatrix, rects);
2379 if (op) {
2380 this->addDrawOp(clip, std::move(op));
2381 }
2382 // Returning here indicates that there is nothing to draw in this case.
2383 return;
2384 }
robertphillipsea461502015-05-26 11:38:03 -07002385 }
2386 }
robertphillips4bc31812016-03-01 12:22:49 -08002387
Brian Salomon2fad74a2017-12-20 13:28:55 -05002388 this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, shape);
robertphillipsea461502015-05-26 11:38:03 -07002389}
2390
Chris Daltonbbfd5162017-11-07 13:35:22 -07002391bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip,
Brian Osman11052242016-10-27 14:47:55 -04002392 const GrUserStencilSettings* ss,
2393 SkRegion::Op op,
2394 bool invert,
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002395 GrAA aa,
Brian Osman11052242016-10-27 14:47:55 -04002396 const SkMatrix& viewMatrix,
2397 const SkPath& path) {
robertphillips391395d2016-03-02 09:26:36 -08002398 ASSERT_SINGLE_OWNER_PRIV
2399 RETURN_FALSE_IF_ABANDONED_PRIV
Brian Osman11052242016-10-27 14:47:55 -04002400 SkDEBUGCODE(fRenderTargetContext->validate();)
Brian Salomondcbb9d92017-07-19 10:53:20 -04002401 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "drawAndStencilPath",
2402 fRenderTargetContext->fContext);
robertphillips391395d2016-03-02 09:26:36 -08002403
2404 if (path.isEmpty() && path.isInverseFillType()) {
Michael Ludwigaa1b6b32019-05-29 14:43:13 -04002405 GrPaint paint;
2406 paint.setCoverageSetOpXPFactory(op, invert);
2407 this->stencilRect(clip, ss, std::move(paint), GrAA::kNo, SkMatrix::I(),
2408 SkRect::MakeIWH(fRenderTargetContext->width(),
2409 fRenderTargetContext->height()));
robertphillips391395d2016-03-02 09:26:36 -08002410 return true;
2411 }
2412
Robert Phillips72152832017-01-25 17:31:35 -05002413 AutoCheckFlush acf(fRenderTargetContext->drawingManager());
robertphillips391395d2016-03-02 09:26:36 -08002414
2415 // An Assumption here is that path renderer would use some form of tweaking
2416 // the src color (either the input alpha or in the frag shader) to implement
2417 // aa. If we have some future driver-mojo path AA that can do the right
2418 // thing WRT to the blend then we'll need some query on the PR.
Chris Dalton6ce447a2019-06-23 18:07:38 -06002419 GrAAType aaType = fRenderTargetContext->chooseAAType(aa);
robertphillips976f5f02016-06-03 10:59:20 -07002420 bool hasUserStencilSettings = !ss->isUnused();
robertphillips391395d2016-03-02 09:26:36 -08002421
Chris Daltondb91c6e2017-09-08 16:25:08 -06002422 SkIRect clipConservativeBounds;
2423 clip.getConservativeBounds(fRenderTargetContext->width(), fRenderTargetContext->height(),
2424 &clipConservativeBounds, nullptr);
2425
bsalomon8acedde2016-06-24 10:42:16 -07002426 GrShape shape(path, GrStyle::SimpleFill());
robertphillips391395d2016-03-02 09:26:36 -08002427 GrPathRenderer::CanDrawPathArgs canDrawArgs;
Brian Salomonc7fe0f72018-05-11 10:14:21 -04002428 canDrawArgs.fCaps = fRenderTargetContext->caps();
robertphillips391395d2016-03-02 09:26:36 -08002429 canDrawArgs.fViewMatrix = &viewMatrix;
bsalomon8acedde2016-06-24 10:42:16 -07002430 canDrawArgs.fShape = &shape;
Chris Daltondb91c6e2017-09-08 16:25:08 -06002431 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
Chris Dalton6ce447a2019-06-23 18:07:38 -06002432 canDrawArgs.fAAType = aaType;
Greg Danielbe7fc462019-01-03 16:40:42 -05002433 SkASSERT(!fRenderTargetContext->wrapsVkSecondaryCB());
2434 canDrawArgs.fTargetIsWrappedVkSecondaryCB = false;
cdalton93a379b2016-05-11 13:58:08 -07002435 canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
robertphillips391395d2016-03-02 09:26:36 -08002436
2437 // Don't allow the SW renderer
Robert Phillips72152832017-01-25 17:31:35 -05002438 GrPathRenderer* pr = fRenderTargetContext->drawingManager()->getPathRenderer(
Brian Salomon36aa1762016-12-10 13:24:02 -05002439 canDrawArgs, false, GrPathRendererChain::DrawType::kStencilAndColor);
robertphillips391395d2016-03-02 09:26:36 -08002440 if (!pr) {
2441 return false;
2442 }
2443
2444 GrPaint paint;
2445 paint.setCoverageSetOpXPFactory(op, invert);
2446
Brian Salomonf3569f02017-10-24 12:52:33 -04002447 GrPathRenderer::DrawPathArgs args{fRenderTargetContext->drawingManager()->getContext(),
2448 std::move(paint),
2449 ss,
2450 fRenderTargetContext,
2451 &clip,
2452 &clipConservativeBounds,
2453 &viewMatrix,
2454 &shape,
Chris Dalton6ce447a2019-06-23 18:07:38 -06002455 aaType,
Brian Osman34ec3742018-07-03 10:40:57 -04002456 fRenderTargetContext->colorSpaceInfo().isLinearlyBlended()};
robertphillips391395d2016-03-02 09:26:36 -08002457 pr->drawPath(args);
2458 return true;
2459}
2460
Brian Osman11052242016-10-27 14:47:55 -04002461SkBudgeted GrRenderTargetContextPriv::isBudgeted() const {
robertphillips714712b2016-08-04 06:20:45 -07002462 ASSERT_SINGLE_OWNER_PRIV
2463
Robert Phillips6a6de562019-02-15 15:19:15 -05002464 if (fRenderTargetContext->fContext->priv().abandoned()) {
robertphillips714712b2016-08-04 06:20:45 -07002465 return SkBudgeted::kNo;
2466 }
2467
Brian Osman11052242016-10-27 14:47:55 -04002468 SkDEBUGCODE(fRenderTargetContext->validate();)
robertphillips714712b2016-08-04 06:20:45 -07002469
Robert Phillipsc7635fa2016-10-28 13:25:24 -04002470 return fRenderTargetContext->fRenderTargetProxy->isBudgeted();
robertphillips714712b2016-08-04 06:20:45 -07002471}
2472
Brian Salomon2fad74a2017-12-20 13:28:55 -05002473void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip,
2474 GrPaint&& paint,
2475 GrAA aa,
2476 const SkMatrix& viewMatrix,
2477 const GrShape& originalShape) {
joshualitt1de610a2016-01-06 08:26:09 -08002478 ASSERT_SINGLE_OWNER
robertphillipsea461502015-05-26 11:38:03 -07002479 RETURN_IF_ABANDONED
Brian Salomondcbb9d92017-07-19 10:53:20 -04002480 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "internalDrawPath", fContext);
2481
Jim Van Verthf86073a2018-10-02 13:05:38 -04002482 if (!viewMatrix.isFinite() || !originalShape.bounds().isFinite()) {
2483 return;
2484 }
2485
Chris Daltondb91c6e2017-09-08 16:25:08 -06002486 SkIRect clipConservativeBounds;
2487 clip.getConservativeBounds(this->width(), this->height(), &clipConservativeBounds, nullptr);
2488
Brian Salomon2fad74a2017-12-20 13:28:55 -05002489 GrShape tempShape;
Chris Dalton6ce447a2019-06-23 18:07:38 -06002490 GrAAType aaType = this->chooseAAType(aa);
Chris Dalton09e56892019-03-13 00:22:01 -06002491
robertphillips68737822015-10-29 12:12:21 -07002492 GrPathRenderer::CanDrawPathArgs canDrawArgs;
Brian Salomonc7fe0f72018-05-11 10:14:21 -04002493 canDrawArgs.fCaps = this->caps();
robertphillips68737822015-10-29 12:12:21 -07002494 canDrawArgs.fViewMatrix = &viewMatrix;
Brian Salomon2fad74a2017-12-20 13:28:55 -05002495 canDrawArgs.fShape = &originalShape;
Chris Daltondb91c6e2017-09-08 16:25:08 -06002496 canDrawArgs.fClipConservativeBounds = &clipConservativeBounds;
Greg Danielbe7fc462019-01-03 16:40:42 -05002497 canDrawArgs.fTargetIsWrappedVkSecondaryCB = this->wrapsVkSecondaryCB();
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002498 canDrawArgs.fHasUserStencilSettings = false;
robertphillips68737822015-10-29 12:12:21 -07002499
Brian Salomon0e8fc8b2016-12-09 15:10:07 -05002500 GrPathRenderer* pr;
Brian Salomon82125e92016-12-10 09:35:48 -05002501 static constexpr GrPathRendererChain::DrawType kType = GrPathRendererChain::DrawType::kColor;
Brian Salomon2fad74a2017-12-20 13:28:55 -05002502 if (originalShape.isEmpty() && !originalShape.inverseFilled()) {
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002503 return;
2504 }
2505
Chris Dalton6ce447a2019-06-23 18:07:38 -06002506 canDrawArgs.fAAType = aaType;
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002507
2508 // Try a 1st time without applying any of the style to the geometry (and barring sw)
2509 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
2510 SkScalar styleScale = GrStyle::MatrixToScaleFactor(viewMatrix);
2511
Brian Salomon2fad74a2017-12-20 13:28:55 -05002512 if (!pr && originalShape.style().pathEffect()) {
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002513 // It didn't work above, so try again with the path effect applied.
Brian Salomon2fad74a2017-12-20 13:28:55 -05002514 tempShape = originalShape.applyStyle(GrStyle::Apply::kPathEffectOnly, styleScale);
2515 if (tempShape.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07002516 return;
2517 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002518 canDrawArgs.fShape = &tempShape;
Robert Phillips72152832017-01-25 17:31:35 -05002519 pr = this->drawingManager()->getPathRenderer(canDrawArgs, false, kType);
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002520 }
2521 if (!pr) {
Brian Salomon2fad74a2017-12-20 13:28:55 -05002522 if (canDrawArgs.fShape->style().applies()) {
2523 tempShape = canDrawArgs.fShape->applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec,
2524 styleScale);
2525 if (tempShape.isEmpty()) {
robertphillipsea461502015-05-26 11:38:03 -07002526 return;
2527 }
Brian Salomon2fad74a2017-12-20 13:28:55 -05002528 canDrawArgs.fShape = &tempShape;
Brian Salomone7df0bb2018-05-07 14:44:57 -04002529 // This time, allow SW renderer
2530 pr = this->drawingManager()->getPathRenderer(canDrawArgs, true, kType);
2531 } else {
2532 pr = this->drawingManager()->getSoftwarePathRenderer();
bsalomon6663acf2016-05-10 09:14:17 -07002533 }
Brian Salomon1e5d0ca2017-12-14 10:50:19 -05002534 }
robertphillipsea461502015-05-26 11:38:03 -07002535
bsalomon8acedde2016-06-24 10:42:16 -07002536 if (!pr) {
robertphillipsea461502015-05-26 11:38:03 -07002537#ifdef SK_DEBUG
2538 SkDebugf("Unable to find path renderer compatible with path.\n");
2539#endif
2540 return;
2541 }
2542
Robert Phillips256c37b2017-03-01 14:32:46 -05002543 GrPathRenderer::DrawPathArgs args{this->drawingManager()->getContext(),
Brian Salomon82f44312017-01-11 13:42:54 -05002544 std::move(paint),
2545 &GrUserStencilSettings::kUnused,
2546 this,
2547 &clip,
Chris Daltondb91c6e2017-09-08 16:25:08 -06002548 &clipConservativeBounds,
Brian Salomon82f44312017-01-11 13:42:54 -05002549 &viewMatrix,
Brian Salomon2fad74a2017-12-20 13:28:55 -05002550 canDrawArgs.fShape,
Chris Dalton6ce447a2019-06-23 18:07:38 -06002551 aaType,
Brian Osman34ec3742018-07-03 10:40:57 -04002552 this->colorSpaceInfo().isLinearlyBlended()};
bsalomon0aff2fa2015-07-31 06:48:27 -07002553 pr->drawPath(args);
robertphillipsea461502015-05-26 11:38:03 -07002554}
2555
Brian Salomon467921e2017-03-06 16:17:12 -05002556static void op_bounds(SkRect* bounds, const GrOp* op) {
2557 *bounds = op->bounds();
2558 if (op->hasZeroArea()) {
2559 if (op->hasAABloat()) {
2560 bounds->outset(0.5f, 0.5f);
2561 } else {
2562 // We don't know which way the particular GPU will snap lines or points at integer
2563 // coords. So we ensure that the bounds is large enough for either snap.
2564 SkRect before = *bounds;
2565 bounds->roundOut(bounds);
2566 if (bounds->fLeft == before.fLeft) {
2567 bounds->fLeft -= 1;
2568 }
2569 if (bounds->fTop == before.fTop) {
2570 bounds->fTop -= 1;
2571 }
2572 if (bounds->fRight == before.fRight) {
2573 bounds->fRight += 1;
2574 }
2575 if (bounds->fBottom == before.fBottom) {
2576 bounds->fBottom += 1;
2577 }
2578 }
2579 }
2580}
2581
Brian Salomon348a0372018-10-31 10:42:18 -04002582void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op,
2583 const std::function<WillAddOpFn>& willAddFn) {
joshualitt1de610a2016-01-06 08:26:09 -08002584 ASSERT_SINGLE_OWNER
Robert Phillips69893702019-02-22 11:16:30 -05002585 if (fContext->priv().abandoned()) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002586 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002587 return;
Robert Phillipsc0138922017-03-08 11:50:55 -05002588 }
robertphillips2e1e51f2015-10-15 08:01:48 -07002589 SkDEBUGCODE(this->validate();)
Ethan Nicholas029b22c2018-10-18 16:49:56 -04002590 SkDEBUGCODE(op->fAddDrawOpCalled = true;)
Brian Salomondcbb9d92017-07-19 10:53:20 -04002591 GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "addDrawOp", fContext);
robertphillips2d70dcb2015-10-06 07:38:23 -07002592
Brian Salomon467921e2017-03-06 16:17:12 -05002593 // Setup clip
2594 SkRect bounds;
2595 op_bounds(&bounds, op.get());
Brian Salomon97180af2017-03-14 13:42:58 -04002596 GrAppliedClip appliedClip;
Brian Salomon54d212e2017-03-21 14:22:38 -04002597 GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags();
Chris Dalton6b982802019-06-27 13:53:46 -06002598 bool usesHWAA = fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA;
2599 bool usesStencil = fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil;
2600
2601 if (usesStencil) {
2602 this->setNeedsStencil();
2603 }
2604
2605 if (!clip.apply(fContext, this, usesHWAA, usesStencil, &appliedClip, &bounds)) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002606 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002607 return;
Brian Salomon54d212e2017-03-21 14:22:38 -04002608 }
2609
Chris Dalton6b982802019-06-27 13:53:46 -06002610 SkASSERT((!usesStencil && !appliedClip.hasStencilClip()) || fNeedsStencil);
Brian Salomon54d212e2017-03-21 14:22:38 -04002611
Brian Osman5ced0bf2019-03-15 10:15:29 -04002612 GrClampType clampType = GrPixelConfigClampType(this->colorSpaceInfo().config());
Chris Dalton6ce447a2019-06-23 18:07:38 -06002613 // MIXED SAMPLES TODO: check stencil buffer is MSAA and make sure stencil test is actually doing
2614 // something (either in the clip or in the op).
2615 bool hasMixedSampledCoverage = false;
Brian Osman5ced0bf2019-03-15 10:15:29 -04002616 GrProcessorSet::Analysis analysis = op->finalize(
Chris Dalton6ce447a2019-06-23 18:07:38 -06002617 *this->caps(), &appliedClip, hasMixedSampledCoverage, clampType);
2618
2619 GrXferProcessor::DstProxy dstProxy;
Chris Dalton945ee652019-01-23 09:10:36 -07002620 if (analysis.requiresDstTexture()) {
Brian Salomon09181ef2018-11-14 13:39:51 -05002621 if (!this->setupDstProxy(this->asRenderTargetProxy(), clip, *op, &dstProxy)) {
Robert Phillips9da87e02019-02-04 13:26:26 -05002622 fContext->priv().opMemoryPool()->release(std::move(op));
Brian Salomon348a0372018-10-31 10:42:18 -04002623 return;
Brian Salomon54d212e2017-03-21 14:22:38 -04002624 }
2625 }
2626
2627 op->setClippedBounds(bounds);
Brian Salomon348a0372018-10-31 10:42:18 -04002628 auto opList = this->getRTOpList();
2629 if (willAddFn) {
2630 willAddFn(op.get(), opList->uniqueID());
2631 }
Chris Dalton945ee652019-01-23 09:10:36 -07002632 opList->addDrawOp(std::move(op), analysis, std::move(appliedClip), dstProxy, *this->caps());
Brian Salomon54d212e2017-03-21 14:22:38 -04002633}
2634
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002635bool GrRenderTargetContext::setupDstProxy(GrRenderTargetProxy* rtProxy, const GrClip& clip,
Brian Salomond6287472019-06-24 15:50:07 -04002636 const GrOp& op, GrXferProcessor::DstProxy* dstProxy) {
Greg Danielbe7fc462019-01-03 16:40:42 -05002637 // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we
2638 // don't actually have a VkImage to make a copy of. Additionally we don't have the power to
2639 // start and stop the render pass in order to make the copy.
2640 if (rtProxy->wrapsVkSecondaryCB()) {
2641 return false;
2642 }
2643
Brian Salomon467921e2017-03-06 16:17:12 -05002644 if (this->caps()->textureBarrierSupport()) {
Robert Phillipsbf25d432017-04-07 10:08:53 -04002645 if (GrTextureProxy* texProxy = rtProxy->asTextureProxy()) {
Brian Salomon467921e2017-03-06 16:17:12 -05002646 // The render target is a texture, so we can read from it directly in the shader. The XP
2647 // will be responsible to detect this situation and request a texture barrier.
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002648 dstProxy->setProxy(sk_ref_sp(texProxy));
2649 dstProxy->setOffset(0, 0);
Robert Phillipsbf25d432017-04-07 10:08:53 -04002650 return true;
Brian Salomon467921e2017-03-06 16:17:12 -05002651 }
2652 }
2653
Robert Phillipsbf25d432017-04-07 10:08:53 -04002654 SkIRect copyRect = SkIRect::MakeWH(rtProxy->width(), rtProxy->height());
Brian Salomon467921e2017-03-06 16:17:12 -05002655
Eric Karl74480882017-04-03 14:49:05 -07002656 SkIRect clippedRect;
Robert Phillipsbf25d432017-04-07 10:08:53 -04002657 clip.getConservativeBounds(rtProxy->width(), rtProxy->height(), &clippedRect);
Brian Salomon09181ef2018-11-14 13:39:51 -05002658 SkRect opBounds = op.bounds();
2659 // If the op has aa bloating or is a infinitely thin geometry (hairline) outset the bounds by
2660 // 0.5 pixels.
2661 if (op.hasAABloat() || op.hasZeroArea()) {
2662 opBounds.outset(0.5f, 0.5f);
2663 // An antialiased/hairline draw can sometimes bleed outside of the clips bounds. For
2664 // performance we may ignore the clip when the draw is entirely inside the clip is float
2665 // space but will hit pixels just outside the clip when actually rasterizing.
2666 clippedRect.outset(1, 1);
2667 clippedRect.intersect(SkIRect::MakeWH(rtProxy->width(), rtProxy->height()));
2668 }
2669 SkIRect opIBounds;
2670 opBounds.roundOut(&opIBounds);
2671 if (!clippedRect.intersect(opIBounds)) {
Brian Salomon467921e2017-03-06 16:17:12 -05002672#ifdef SK_DEBUG
Robert Phillipsbf25d432017-04-07 10:08:53 -04002673 GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw.");
Brian Salomon467921e2017-03-06 16:17:12 -05002674#endif
Robert Phillipsbf25d432017-04-07 10:08:53 -04002675 return false;
Brian Salomon467921e2017-03-06 16:17:12 -05002676 }
2677
2678 // MSAA consideration: When there is support for reading MSAA samples in the shader we could
2679 // have per-sample dst values by making the copy multisampled.
2680 GrSurfaceDesc desc;
Eric Karl74480882017-04-03 14:49:05 -07002681 bool rectsMustMatch = false;
2682 bool disallowSubrect = false;
Greg Daniel46cfbc62019-06-07 11:43:30 -04002683 if (!this->caps()->initDescForDstCopy(rtProxy, &desc, &rectsMustMatch,
Brian Salomon2a4f9832018-03-03 22:43:43 -05002684 &disallowSubrect)) {
Brian Salomon467921e2017-03-06 16:17:12 -05002685 desc.fFlags = kRenderTarget_GrSurfaceFlag;
Robert Phillipsbf25d432017-04-07 10:08:53 -04002686 desc.fConfig = rtProxy->config();
Brian Salomon467921e2017-03-06 16:17:12 -05002687 }
2688
Emircan Uysaler23ca4e72019-06-24 10:53:09 -04002689 desc.fIsProtected = rtProxy->isProtected() ? GrProtected::kYes : GrProtected::kNo;
2690
Eric Karl74480882017-04-03 14:49:05 -07002691 if (!disallowSubrect) {
2692 copyRect = clippedRect;
2693 }
Brian Salomon467921e2017-03-06 16:17:12 -05002694
Robert Phillipsbf25d432017-04-07 10:08:53 -04002695 SkIPoint dstPoint, dstOffset;
2696 SkBackingFit fit;
Greg Daniel46cfbc62019-06-07 11:43:30 -04002697 GrSurfaceProxy::RectsMustMatch matchRects;
Eric Karl74480882017-04-03 14:49:05 -07002698 if (rectsMustMatch) {
Robert Phillipsbf25d432017-04-07 10:08:53 -04002699 desc.fWidth = rtProxy->width();
2700 desc.fHeight = rtProxy->height();
Eric Karl74480882017-04-03 14:49:05 -07002701 dstPoint = {copyRect.fLeft, copyRect.fTop};
2702 dstOffset = {0, 0};
Robert Phillipsbf25d432017-04-07 10:08:53 -04002703 fit = SkBackingFit::kExact;
Greg Daniel46cfbc62019-06-07 11:43:30 -04002704 matchRects = GrSurfaceProxy::RectsMustMatch::kYes;
Eric Karl74480882017-04-03 14:49:05 -07002705 } else {
2706 desc.fWidth = copyRect.width();
2707 desc.fHeight = copyRect.height();
2708 dstPoint = {0, 0};
2709 dstOffset = {copyRect.fLeft, copyRect.fTop};
Robert Phillipsbf25d432017-04-07 10:08:53 -04002710 fit = SkBackingFit::kApprox;
Greg Daniel46cfbc62019-06-07 11:43:30 -04002711 matchRects = GrSurfaceProxy::RectsMustMatch::kNo;
Eric Karl74480882017-04-03 14:49:05 -07002712 }
Greg Daniel46cfbc62019-06-07 11:43:30 -04002713 sk_sp<GrTextureProxy> newProxy = GrSurfaceProxy::Copy(fContext, rtProxy, GrMipMapped::kNo,
2714 copyRect, fit, SkBudgeted::kYes,
2715 matchRects);
2716 SkASSERT(newProxy);
Robert Phillipsbf25d432017-04-07 10:08:53 -04002717
Greg Daniel46cfbc62019-06-07 11:43:30 -04002718 dstProxy->setProxy(std::move(newProxy));
Robert Phillipsbb581ce2017-05-29 15:05:15 -04002719 dstProxy->setOffset(dstOffset);
Robert Phillipsbf25d432017-04-07 10:08:53 -04002720 return true;
robertphillips2334fb62015-06-17 05:43:33 -07002721}
Greg Daniel46cfbc62019-06-07 11:43:30 -04002722
2723bool GrRenderTargetContext::blitTexture(GrTextureProxy* src, const SkIRect& srcRect,
2724 const SkIPoint& dstPoint) {
2725 SkIRect clippedSrcRect;
2726 SkIPoint clippedDstPoint;
2727 if (!GrClipSrcRectAndDstPoint(this->asSurfaceProxy()->isize(), src->isize(), srcRect, dstPoint,
2728 &clippedSrcRect, &clippedDstPoint)) {
2729 return false;
2730 }
2731
2732 GrPaint paint;
2733 paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
2734 auto fp = GrSimpleTextureEffect::Make(sk_ref_sp(src->asTextureProxy()),
2735 SkMatrix::I());
2736 if (!fp) {
2737 return false;
2738 }
2739 paint.addColorFragmentProcessor(std::move(fp));
2740
2741 this->fillRectToRect(
2742 GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(),
2743 SkRect::MakeXYWH(clippedDstPoint.fX, clippedDstPoint.fY, clippedSrcRect.width(),
2744 clippedSrcRect.height()),
2745 SkRect::Make(clippedSrcRect));
2746 return true;
2747}
2748